539 lines
19 KiB
Markdown
539 lines
19 KiB
Markdown
# Cahier des charges - RelaisSMS
|
|
|
|
## 1. Objectif
|
|
|
|
RelaisSMS est une application web d'envoi de SMS permettant à des utilisateurs autorisés de sélectionner des contacts ou des groupes issus de plusieurs sources, de composer un message, de l'envoyer immédiatement ou de le programmer, puis de consulter l'historique des envois.
|
|
|
|
Le premier fournisseur cible est l'API SMS OVHcloud. L'architecture doit toutefois permettre d'ajouter d'autres fournisseurs sans réécrire l'interface ni la logique métier.
|
|
|
|
## 2. Périmètre fonctionnel
|
|
|
|
### 2.1 MVP
|
|
|
|
- Authentification des utilisateurs de l'interface.
|
|
- Tableau de bord d'envoi de SMS.
|
|
- Sélection de destinataires par contacts et par groupes.
|
|
- Gestion de contacts locaux.
|
|
- Synchronisation de contacts CardDAV/Nextcloud.
|
|
- Préparation de l'intégration Galette, sans la mélanger avec CardDAV/Nextcloud.
|
|
- Cache local des contacts, téléphones, groupes et appartenances.
|
|
- Déclenchement de synchronisation par tâche planifiée et par bouton manuel.
|
|
- Suppression locale des contacts synchronisés disparus de la source.
|
|
- Journal des SMS envoyés.
|
|
- Connecteur SMS OVHcloud.
|
|
- Abstraction permettant d'ajouter d'autres connecteurs SMS.
|
|
- Gestion des favoris contacts et groupes.
|
|
- Gestion manuelle d'un refus SMS sur les contacts.
|
|
- Programmation d'un envoi différé dans le temps.
|
|
|
|
### 2.2 V2
|
|
|
|
- Connexion à un agenda CalDAV ou autre source d'événements.
|
|
- Rappels SMS liés aux événements.
|
|
- Modèles de messages.
|
|
- Brouillons et réutilisation des derniers envois.
|
|
- Import/export CSV de contacts locaux.
|
|
- Statistiques détaillées par campagne, groupe, fournisseur et statut.
|
|
- Gestion fine des droits par rôle.
|
|
|
|
## 3. Utilisateurs et rôles
|
|
|
|
| Rôle | Droits principaux |
|
|
| --- | --- |
|
|
| Administrateur | Configurer les sources, fournisseurs SMS, utilisateurs, synchronisations et règles globales. |
|
|
| Opérateur | Envoyer des SMS, consulter contacts/groupes, lancer une synchronisation manuelle si autorisé. |
|
|
|
|
## 4. Sources de données
|
|
|
|
### 4.1 CardDAV/Nextcloud
|
|
|
|
La source CardDAV permet de synchroniser un carnet d'adresses, par exemple Nextcloud. C'est un système d'import/synchronisation distinct de Galette, avec son propre connecteur, ses propres identifiants distants et son propre nommage de source.
|
|
|
|
Données à récupérer :
|
|
|
|
- UID vCard.
|
|
- Nom affiché.
|
|
- Nom, prénom si présents.
|
|
- Numéros de téléphone et types.
|
|
- Groupes/catégories vCard si présents.
|
|
- ETag ou horodatage distant pour optimiser la synchronisation.
|
|
|
|
### 4.2 Galette
|
|
|
|
La source Galette fournit des adhérents et leurs informations de contact.
|
|
|
|
Galette n'est pas la source CardDAV/Nextcloud. Même si Galette peut exposer ou exporter des vCards, cette possibilité reste un détail d'implémentation du connecteur Galette et ne doit pas être nommée ni organisée comme une synchronisation CardDAV.
|
|
|
|
Données à récupérer :
|
|
|
|
- Identifiant distant stable.
|
|
- Nom, prénom, structure éventuelle.
|
|
- Numéros de téléphone, avec type si disponible.
|
|
- Adresse email si utile pour l'identification.
|
|
- Groupes ou statuts d'appartenance.
|
|
- Date de dernière modification si disponible.
|
|
|
|
Mode d'accès retenu :
|
|
|
|
- API HTTP Galette.
|
|
|
|
Points à préciser au démarrage :
|
|
|
|
- Endpoints exacts disponibles côté Galette.
|
|
- Mode d'authentification API.
|
|
- Mapping exact des champs téléphone.
|
|
- Mapping exact des groupes Galette vers les groupes applicatifs.
|
|
|
|
### 4.3 Contacts locaux
|
|
|
|
Les contacts locaux sont créés directement dans l'application. Ils ne sont jamais supprimés par une synchronisation distante.
|
|
|
|
Chaque contact doit conserver :
|
|
|
|
- Son origine : `local`, `galette`, `carddav`, puis identifiant de source.
|
|
- Son statut actif/inactif.
|
|
- Les numéros associés.
|
|
- Les groupes locaux auxquels il appartient.
|
|
- Ses informations de favori.
|
|
- Son indicateur de refus SMS, géré manuellement.
|
|
|
|
## 5. Règles de synchronisation
|
|
|
|
- Les sources sont cumulables.
|
|
- CardDAV/Nextcloud et Galette sont deux sources distinctes ; elles ne partagent ni connecteur, ni configuration, ni nommage fonctionnel.
|
|
- Un contact synchronisé est identifié par le couple clé de source (`carddav`, `galette`, etc.) + identifiant externe.
|
|
- Si un contact disparaît de la source distante, il est supprimé ou désactivé localement selon la politique choisie.
|
|
- Politique recommandée MVP : suppression logique (`deleted_at`) pour préserver l'historique SMS.
|
|
- Les groupes importés restent visibles dans l'interface.
|
|
- Les groupes importés ne sont pas supprimables manuellement, sauf suppression/désactivation de la source.
|
|
- Les groupes locaux sont créables, modifiables et supprimables depuis l'application.
|
|
- Si un contact disparaît d'un groupe distant, l'appartenance locale synchronisée est retirée.
|
|
- Les appartenances locales ne doivent pas être écrasées par les synchronisations distantes.
|
|
- Un bouton "Synchroniser" permet de lancer une synchronisation manuelle.
|
|
- Une tâche planifiée lance les synchronisations selon la fréquence configurée.
|
|
|
|
## 6. Envoi SMS
|
|
|
|
### 6.1 Formulaire
|
|
|
|
Le formulaire d'envoi doit permettre :
|
|
|
|
- La recherche de contacts.
|
|
- La recherche de groupes.
|
|
- L'ajout de plusieurs contacts et groupes.
|
|
- La déduplication automatique des numéros.
|
|
- La saisie du message.
|
|
- L'affichage du nombre de caractères.
|
|
- L'estimation du nombre de SMS selon encodage GSM-7/UCS-2.
|
|
- La prévisualisation du nombre de destinataires et numéros valides.
|
|
- La validation avant envoi.
|
|
- Le choix entre envoi immédiat et envoi programmé.
|
|
- Le respect d'une limite configurable de 100 SMS par envoi par défaut.
|
|
|
|
### 6.2 Gestion des numéros
|
|
|
|
- Normaliser les numéros au format E.164.
|
|
- Conserver le numéro original pour audit.
|
|
- Marquer les numéros invalides et les exclure de l'envoi.
|
|
- Gérer plusieurs numéros par contact.
|
|
- Envoyer à tous les numéros détectés comme téléphones portables.
|
|
- Détecter les téléphones portables avec une expression régulière configurable.
|
|
- Expression régulière par défaut à prévoir pour les numéros français de type `+33 6`, `+33 7`, `06`, `07`.
|
|
- Exclure les contacts marqués en refus SMS.
|
|
- Afficher un résumé des exclusions : numéros invalides, numéros non mobiles, doublons, contacts en refus SMS.
|
|
|
|
### 6.3 Envoi différé
|
|
|
|
L'utilisateur peut choisir une date et une heure d'envoi. L'envoi programmé reste modifiable ou annulable tant qu'il n'a pas été pris en charge par le job d'envoi.
|
|
|
|
Règles attendues :
|
|
|
|
- Stocker l'état `draft`, `scheduled`, `sending`, `sent`, `partial`, `failed`, `cancelled`.
|
|
- Refuser une programmation dans le passé.
|
|
- Déclencher les envois dus via scheduler Laravel lancé par cron.
|
|
- Résoudre les destinataires au moment de la validation de l'envoi, puis conserver cette liste pour audit.
|
|
- Option à confirmer en implémentation : revalider les refus SMS et numéros invalides juste avant l'envoi effectif.
|
|
|
|
### 6.4 Journalisation
|
|
|
|
Chaque envoi doit créer :
|
|
|
|
- Une campagne ou opération d'envoi.
|
|
- Le message envoyé.
|
|
- L'utilisateur émetteur.
|
|
- Les destinataires résolus.
|
|
- Le fournisseur utilisé.
|
|
- Les statuts par numéro : préparé, envoyé, erreur, livré si disponible.
|
|
- La réponse brute ou référence externe du fournisseur.
|
|
- Les dates de création, envoi et dernière mise à jour.
|
|
- La date de programmation si l'envoi est différé.
|
|
- Une date d'expiration d'historique calculée selon la configuration, par défaut à 3 ans.
|
|
|
|
## 7. Connecteurs SMS
|
|
|
|
### 7.1 Interface technique
|
|
|
|
Prévoir une interface applicative, par exemple :
|
|
|
|
```php
|
|
interface SmsProviderInterface
|
|
{
|
|
public function send(SmsMessage $message, array $recipients): SmsSendResult;
|
|
|
|
public function getName(): string;
|
|
|
|
public function supportsDeliveryStatus(): bool;
|
|
}
|
|
```
|
|
|
|
Le code métier dépend de cette interface et non d'OVHcloud directement.
|
|
|
|
### 7.2 Connecteur OVHcloud
|
|
|
|
Fonctions attendues :
|
|
|
|
- Configuration des identifiants API.
|
|
- Sélection du service SMS OVHcloud.
|
|
- Envoi vers un ou plusieurs numéros.
|
|
- Récupération de l'identifiant de message distant.
|
|
- Gestion des erreurs API.
|
|
- Journalisation technique des réponses.
|
|
|
|
Point d'attention : le SDK `ovh/ovh` existe, mais sa compatibilité PHP doit être validée avec la version cible du projet. Une implémentation via client HTTP standard peut être préférable si le SDK officiel n'est pas encore compatible avec la version PHP retenue.
|
|
|
|
## 8. Agenda et rappels
|
|
|
|
Fonction à prévoir mais hors MVP.
|
|
|
|
Cas d'usage :
|
|
|
|
- Synchroniser des événements depuis un agenda.
|
|
- Associer un événement à un groupe ou une liste de contacts.
|
|
- Déclencher un rappel X minutes/heures avant l'événement.
|
|
- Journaliser les rappels envoyés comme des SMS classiques.
|
|
|
|
Règles à clarifier :
|
|
|
|
- Source agenda : CalDAV, ICS, API spécifique.
|
|
- Responsabilité de la création des événements.
|
|
- Gestion des modifications et suppressions d'événements.
|
|
- Anti-doublon sur les rappels.
|
|
|
|
## 9. Modèle de données cible
|
|
|
|
Tables principales :
|
|
|
|
- `users`
|
|
- `sources`
|
|
- `source_sync_runs`
|
|
- `contacts`
|
|
- `contact_phone_numbers`
|
|
- `groups`
|
|
- `contact_group_memberships`
|
|
- `favorites`
|
|
- `sms_providers`
|
|
- `sms_campaigns`
|
|
- `sms_recipients`
|
|
- `sms_delivery_events`
|
|
- `app_settings`
|
|
- `message_templates` en V2
|
|
- `calendar_sources` en V2
|
|
- `calendar_events` en V2
|
|
- `scheduled_reminders` en V2
|
|
|
|
Champs clés recommandés :
|
|
|
|
- `contacts.source` : `local`, `carddav`, `galette` ou autre clé de source explicite.
|
|
- `contacts.external_id` nullable, rempli pour les contacts synchronisés.
|
|
- `contacts.deleted_at` pour suppression logique.
|
|
- `groups.source` : `local`, `carddav`, `galette` ou autre clé de source explicite.
|
|
- `groups.external_id` nullable, rempli pour les groupes synchronisés.
|
|
- `contact_group_memberships.source` : `local`, `carddav`, `galette` ou autre clé de source explicite.
|
|
- `contact_phone_numbers.normalized_number`.
|
|
- `contacts.sms_opt_out` pour le refus SMS manuel.
|
|
- `sms_campaigns.status`.
|
|
- `sms_campaigns.scheduled_at` nullable.
|
|
- `sms_campaigns.expires_at`.
|
|
- `sms_recipients.provider_message_id`.
|
|
|
|
## 10. Configuration applicative
|
|
|
|
La configuration doit pouvoir être ajustée depuis l'interface administrateur ou, pour les secrets, via variables d'environnement.
|
|
|
|
Paramètres attendus :
|
|
|
|
- Identifiants et URL CardDAV/Nextcloud.
|
|
- Identifiants et URL Galette, à activer seulement au dernier lot.
|
|
- Identifiants et paramètres du fournisseur SMS OVHcloud.
|
|
- Fournisseur SMS actif.
|
|
- Expression régulière de détection des téléphones portables.
|
|
- Pays par défaut pour la normalisation des numéros.
|
|
- Limite maximale de SMS par envoi, valeur par défaut : 100.
|
|
- Durée de conservation de l'historique, valeur par défaut : 3 ans.
|
|
- Fréquence de synchronisation des sources.
|
|
- Activation ou non des envois programmés.
|
|
|
|
Les secrets API ne doivent pas être stockés en clair dans une table applicative si l'environnement permet de les gérer par variables d'environnement ou coffre de secrets.
|
|
|
|
## 11. Choix techniques recommandés
|
|
|
|
### 11.1 Stack principale
|
|
|
|
- PHP 8.3 ou 8.4.
|
|
- Laravel 13 si PHP 8.3 est disponible.
|
|
- Laravel 12 possible si l'environnement cible impose PHP 8.2.
|
|
- PostgreSQL ou MariaDB pour la base principale.
|
|
- Eloquent ORM + migrations Laravel.
|
|
- Queue Laravel avec driver `database`.
|
|
- Scheduler Laravel lancé par cron système.
|
|
- Blade pour les vues.
|
|
- Livewire ou Alpine.js en complément léger pour les recherches dynamiques et formulaires interactifs.
|
|
- Tailwind CSS ou CSS applicatif structuré pour l'interface.
|
|
|
|
Pourquoi Laravel :
|
|
|
|
- Suffisant pour le périmètre et moins lourd à mettre en place.
|
|
- Bons composants intégrés pour console, jobs, planification, validation, sécurité, migrations et HTTP.
|
|
- Interface Blade/Livewire adaptée à une application métier sans SPA complète.
|
|
- Architecture propre pour des connecteurs `SourceConnectorInterface` et `SmsProviderInterface`.
|
|
- Déploiement simple en PHP classique.
|
|
- Driver de queue en base adapté au volume attendu, sans service de queue additionnel.
|
|
|
|
Alternative possible :
|
|
|
|
- PHP natif structuré avec Composer peut suffire pour un très petit périmètre, mais Laravel apporte un socle utile pour auth, jobs, migrations et scheduler.
|
|
|
|
### 11.2 Librairies pressenties
|
|
|
|
| Besoin | Librairie / composant |
|
|
| --- | --- |
|
|
| Framework | `laravel/framework` |
|
|
| ORM et migrations | Eloquent + migrations Laravel |
|
|
| Authentification | Laravel Breeze ou auth applicative Laravel |
|
|
| Jobs asynchrones | Laravel Queue driver `database` |
|
|
| Planification | Laravel Scheduler + cron |
|
|
| HTTP API | Client HTTP Laravel ou `guzzlehttp/guzzle` |
|
|
| CardDAV/vCard | `sabre/dav`, `sabre/vobject` |
|
|
| Normalisation téléphone | `giggsey/libphonenumber-for-php` |
|
|
| SMS OVHcloud | Adapter maison via HTTP, ou `ovh/ovh` si compatible PHP cible |
|
|
| Tests | PHPUnit ou Pest |
|
|
| Qualité | PHPStan ou Larastan, Laravel Pint |
|
|
| Front | Blade, Livewire ou Alpine.js, Tailwind CSS ou CSS maintenu localement |
|
|
|
|
## 12. Architecture applicative
|
|
|
|
### 12.1 Domaines
|
|
|
|
- `Contact`
|
|
- `Group`
|
|
- `Source`
|
|
- `Sync`
|
|
- `Sms`
|
|
- `Provider`
|
|
- `Audit`
|
|
- `Calendar` en V2
|
|
|
|
### 12.2 Interfaces métier
|
|
|
|
```php
|
|
interface SourceConnectorInterface
|
|
{
|
|
public function sync(SourceConfig $config): SyncResult;
|
|
}
|
|
```
|
|
|
|
```php
|
|
interface ContactResolverInterface
|
|
{
|
|
public function resolve(RecipientSelection $selection): ResolvedRecipients;
|
|
}
|
|
```
|
|
|
|
```php
|
|
interface PhoneNumberNormalizerInterface
|
|
{
|
|
public function normalize(string $rawNumber, string $defaultCountry): PhoneNumberResult;
|
|
}
|
|
```
|
|
|
|
## 13. Découpage en tâches
|
|
|
|
### Lot 0 - Cadrage
|
|
|
|
- Acter la séparation entre CardDAV/Nextcloud et Galette.
|
|
- Relever les inconnues Galette sans bloquer les premiers lots.
|
|
- Valider les paramètres d'accès CardDAV/Nextcloud.
|
|
- Valider le fournisseur OVHcloud, endpoints, credentials et quota.
|
|
- Définir les rôles utilisateurs.
|
|
- Définir la politique de suppression : logique ou physique.
|
|
- Valider la regex portable par défaut.
|
|
- Valider les paramètres de conservation et de limite d'envoi.
|
|
|
|
Livrable : document de décisions techniques.
|
|
|
|
### Lot 1 - Socle applicatif
|
|
|
|
- Initialiser le projet Laravel.
|
|
- Configurer base, migrations, environnement et sécurité.
|
|
- Créer l'authentification.
|
|
- Mettre en place layout, navigation et design system minimal.
|
|
- Ajouter CI locale : tests, lint, analyse statique.
|
|
|
|
Critère d'acceptation : un utilisateur connecté accède à l'interface vide.
|
|
|
|
### Lot 2 - Modèle contacts/groupes
|
|
|
|
- Créer entités et migrations.
|
|
- Gérer contacts locaux.
|
|
- Gérer groupes locaux.
|
|
- Gérer numéros multiples.
|
|
- Ajouter normalisation et validation téléphone.
|
|
- Ajouter flag manuel de refus SMS.
|
|
- Ajouter favoris.
|
|
|
|
Critère d'acceptation : création d'un contact local, ajout à un groupe, recherche dans l'interface.
|
|
|
|
### Lot 3 - Synchronisation CardDAV/Nextcloud
|
|
|
|
- Implémenter `CardDavSourceConnector`.
|
|
- Lire les vCards et extraire téléphones/catégories.
|
|
- Utiliser ETag/UID si disponible.
|
|
- Gérer disparition distante.
|
|
- Écrire les logs de synchronisation.
|
|
- Gérer création, mise à jour et disparition.
|
|
- Ajouter déclenchement manuel.
|
|
|
|
Critère d'acceptation : un carnet Nextcloud peut être synchronisé et ses contacts apparaissent dans l'interface.
|
|
|
|
### Lot 4 - Sélection destinataires
|
|
|
|
- Construire recherche contacts/groupes.
|
|
- Résoudre les groupes vers contacts.
|
|
- Dédupliquer les numéros.
|
|
- Appliquer la regex portable configurable.
|
|
- Exclure les contacts en refus SMS.
|
|
- Signaler invalides, non mobiles, doublons, refus SMS et contacts sans téléphone.
|
|
- Préparer un résumé avant envoi.
|
|
|
|
Critère d'acceptation : sélectionner plusieurs groupes et contacts produit une liste de numéros uniques et valides.
|
|
|
|
### Lot 5 - Envoi SMS
|
|
|
|
- Créer `SmsProviderInterface`.
|
|
- Implémenter connecteur OVHcloud.
|
|
- Créer campagnes et destinataires.
|
|
- Envoyer via job Laravel Queue.
|
|
- Gérer erreurs et retries.
|
|
- Afficher l'état d'envoi.
|
|
|
|
Critère d'acceptation : un SMS peut être envoyé via OVHcloud et apparaît dans l'historique.
|
|
|
|
### Lot 6 - Historique et audit
|
|
|
|
- Lister les campagnes.
|
|
- Filtrer par date, utilisateur, groupe, statut.
|
|
- Voir le détail par destinataire.
|
|
- Export CSV simple.
|
|
- Mettre en place l'expiration automatique à 3 ans, configurable.
|
|
|
|
Critère d'acceptation : un administrateur peut retrouver qui a envoyé quoi, quand et à quels numéros.
|
|
|
|
### Lot 7 - Envois programmés
|
|
|
|
- Ajouter date/heure d'envoi au formulaire.
|
|
- Créer un statut `scheduled`.
|
|
- Déclencher les campagnes dues via Scheduler Laravel.
|
|
- Permettre l'annulation avant prise en charge.
|
|
- Journaliser le passage de `scheduled` à `sending`.
|
|
|
|
Critère d'acceptation : un SMS peut être programmé, puis envoyé automatiquement à l'heure prévue.
|
|
|
|
### Lot 8 - Agenda et rappels V2
|
|
|
|
- Configurer une source agenda.
|
|
- Synchroniser événements.
|
|
- Programmer des rappels.
|
|
- Empêcher les doublons.
|
|
- Journaliser comme campagne SMS.
|
|
|
|
Critère d'acceptation : un événement peut générer un rappel SMS automatiquement.
|
|
|
|
### Lot 9 - Synchronisation Galette
|
|
|
|
- Revalider l'état de l'instance Galette après upgrade.
|
|
- Implémenter `GaletteSourceConnector`, séparé du connecteur CardDAV.
|
|
- Choisir le mécanisme d'accès Galette : API HTTP, export CSV authentifié ou autre mécanisme validé.
|
|
- Mapper adhérents, téléphones et groupes/statuts Galette.
|
|
- Gérer création, mise à jour et disparition.
|
|
- Ajouter déclenchement manuel et logs de synchronisation.
|
|
|
|
Critère d'acceptation : une synchronisation Galette met à jour le cache local sans écraser les données locales ni réutiliser le nommage CardDAV/Nextcloud.
|
|
|
|
## 14. Parcours interface
|
|
|
|
### Écran principal - Envoi
|
|
|
|
- Barre latérale : Envoi, Contacts, Groupes, Sources, Historique, Paramètres.
|
|
- Zone de sélection destinataires avec recherche rapide.
|
|
- Panneau contacts/groupes favoris.
|
|
- Zone message avec compteur.
|
|
- Résumé compact avant envoi : destinataires, numéros valides, invalides, non mobiles, refus SMS, nombre de SMS estimé.
|
|
- Choix envoi immédiat ou programmé.
|
|
- Bouton d'envoi avec confirmation.
|
|
|
|
### Écran contacts
|
|
|
|
- Liste filtrable.
|
|
- Badges d'origine.
|
|
- Téléphones associés.
|
|
- Groupes.
|
|
- Favori.
|
|
- Refus SMS.
|
|
- État synchronisé/local/supprimé.
|
|
|
|
### Écran sources
|
|
|
|
- Liste des sources.
|
|
- Dernière synchronisation.
|
|
- Statut.
|
|
- Bouton synchroniser.
|
|
- Détail des erreurs.
|
|
|
|
### Écran historique
|
|
|
|
- Liste des campagnes.
|
|
- Détail destinataires.
|
|
- Statuts d'envoi.
|
|
- Référence fournisseur.
|
|
- Export.
|
|
|
|
## 15. Sécurité et conformité
|
|
|
|
- Accès authentifié obligatoire.
|
|
- Protection CSRF sur formulaires.
|
|
- Journalisation des actions sensibles.
|
|
- Stockage chiffré ou protégé des secrets API.
|
|
- Masquage partiel des numéros dans certaines vues si nécessaire.
|
|
- Conservation de l'historique compatible avec les obligations internes.
|
|
- Expiration automatique de l'historique au bout de 3 ans par défaut, durée configurable.
|
|
- Prévoir une procédure de suppression/anonymisation sur demande.
|
|
- Sauvegarde régulière de la base.
|
|
|
|
## 16. Décisions actées
|
|
|
|
- CardDAV/Nextcloud et Galette sont deux systèmes d'import/synchronisation distincts.
|
|
- Galette est reporté au dernier lot, car l'instance cible n'est pas prête.
|
|
- Les SMS partent vers tous les numéros détectés comme portables.
|
|
- La détection portable est basée sur une regex configurable.
|
|
- Les contacts peuvent être marqués manuellement en refus SMS.
|
|
- Le volume maximal attendu par envoi est de 100 SMS.
|
|
- Il n'y a pas de validation à deux personnes avant envoi.
|
|
- L'interface affiche le nombre de SMS estimé, pas le coût.
|
|
- L'historique expire à 3 ans par défaut, avec durée configurable.
|
|
|
|
## 17. Références techniques consultées
|
|
|
|
- Laravel release notes : https://laravel.com/docs/releases
|
|
- SDK PHP OVHcloud : https://github.com/ovh/php-ovh
|
|
- SabreDAV : https://sabre.io/dav/
|