Files
RelaisSMS/doc/lot-0-decisions-techniques.md
T

237 lines
12 KiB
Markdown

# RelaisSMS - Lot 0 - Decisions techniques
Date : 2026-06-11
## Objectif du lot
Ce document fixe les decisions de cadrage avant le demarrage du socle applicatif. Il complete le cahier des charges et sert de reference pour les lots suivants.
## Decisions actees
| Sujet | Decision | Impact |
| --- | --- | --- |
| Source CardDAV/Nextcloud | CardDAV/Nextcloud est le premier systeme d'import/synchronisation distant a implementer. | Le lot 3 porte sur `CardDavSourceConnector` et ne depend pas de Galette. |
| Source Galette | Galette est prepare comme source future, mais le connecteur n'est pas implemente tant que l'instance n'est pas mise a jour. | Galette est reporte au dernier lot. Le socle et CardDAV/Nextcloud avancent sans dependance Galette. |
| Nommage des sources | CardDAV/Nextcloud et Galette sont deux sources separees, meme si Galette expose ou exporte un format vCard. | Les connecteurs, configurations, cles de source et libelles UI restent distincts. Pas de regroupement sous un meme lot ou nommage. |
| Version Galette cible | Galette 1.2.1 cote projet. La documentation `latest` consultee affiche 1.2.2. | Les endpoints exacts seront revalides apres upgrade, avant implementation du dernier lot Galette. |
| Fournisseur SMS | OVHcloud SMS via API REST OVH Europe. | Le connecteur initial depend de l'API OVH, isole derriere `SmsProviderInterface`. |
| SDK OVH | Ne pas imposer le SDK au lot 0. Preferer un adaptateur HTTP Laravel au demarrage, sauf validation explicite du SDK avec la version PHP cible. | Moins de dependance externe et controle clair de la signature API. |
| Roles | Un seul role applicatif au MVP : administrateur complet. | Pas de RBAC fin au lot 1. Tous les utilisateurs authentifies ont les memes droits. |
| Suppression contacts synchronises | Suppression logique par `deleted_at`, pas suppression physique. | L'historique SMS reste auditable meme si un contact disparait d'une source. |
| Suppression contacts locaux | Jamais supprimes par synchronisation. | Un contact local reste sous controle applicatif. |
| Refus SMS | Flag manuel `sms_opt_out` au niveau contact. | Les contacts opt-out sont exclus au moment de la resolution des destinataires. |
| Limite d'envoi | 100 SMS par envoi par defaut, configurable. | Validation cote serveur obligatoire avant creation de campagne. |
| Conservation historique | 3 ans par defaut, configurable. | `sms_campaigns.expires_at` est calcule a la creation. |
| Programmation | Prevue dans le modele, activee par configuration. | Le lot 7 pourra utiliser le scheduler sans revoir le modele. |
## CardDAV/Nextcloud
### Etat retenu
CardDAV/Nextcloud est la source distante prioritaire pour l'import/synchronisation. Elle est traitee comme un systeme autonome : son connecteur lit des carnets CardDAV, des vCards, des UID et des ETags, sans reutiliser le contrat Galette.
### Contrat cible pour RelaisSMS
Le connecteur CardDAV devra fournir au cache local :
| Donnee RelaisSMS | Source CardDAV attendue |
| --- | --- |
| Identifiant distant | UID vCard, complete par l'URL ou l'adresse du carnet si necessaire. |
| Nom affiche | `FN` vCard. |
| Nom / prenom | Champs structures vCard si presents. |
| Telephones | Proprietes `TEL`, avec conservation du type si disponible. |
| Groupes | Categories vCard si presentes. |
| Synchronisation incrementale | ETag, `ctag` ou horodatage distant selon les capacites du serveur. |
Decision : nommer cette source `carddav` ou `carddav_nextcloud` cote configuration/UI, jamais `galette_vcard`.
## Galette
### Etat retenu
Galette est laisse de cote pour l'implementation immediate, conformement au cadrage projet : l'upgrade est planifie mais pas encore effectif. Le lot 0 documente donc le contrat attendu sans figer un endpoint qui pourrait changer au moment de l'upgrade. Le connecteur Galette sera le dernier lot.
### Documentation consultee
- Documentation Galette fournie : <https://apidoc.galette.eu/en/latest/functions_m.html>
- La page consultee est une documentation Doxygen de classes PHP, pas une specification REST/OpenAPI.
- Elements reperes utiles au cadrage :
- `Galette\Controllers\Crud\MembersController::list`
- `Galette\Controllers\Crud\MembersController::ajaxList`
- `Galette\Controllers\Crud\MembersController::show`
- `Galette\Controllers\Crud\MembersController::vcard`
- `Galette\Controllers\CsvController::membersExport`
### Contrat cible pour RelaisSMS
Le connecteur Galette devra fournir au cache local :
| Donnee RelaisSMS | Source Galette attendue |
| --- | --- |
| Identifiant distant | ID adherent Galette, par exemple `Numéro adhérent` dans l'export actuel. |
| Nom | Champ nom. |
| Prenom | Champ prenom. |
| Structure | Personne morale si presente. |
| Email | Courriel. |
| Telephones | Telephone et GSM, avec conservation du numero original. |
| Groupes/statuts | Statut adherent au minimum ; groupes Galette a confirmer apres upgrade. |
| Date de modification | Date de modification si exposee par API/export. |
### Endpoints a valider apres upgrade
Avant le lot 9, valider sur l'instance Galette 1.2.1 :
| Usage | Endpoint ou mecanisme attendu | Statut |
| --- | --- | --- |
| Liste complete des adherents | Endpoint HTTP ou export membres base sur `membersExport` | A confirmer |
| Detail adherent | Route detail membre ou endpoint dedie | A confirmer |
| Fiche/export vCard Galette | Route `vcard` si exploitable dans le connecteur Galette | Optionnel, sans lien avec CardDAV/Nextcloud |
| Groupes/statuts | Route groupes ou champs presents dans la liste/export | A confirmer |
| Authentification | Session, jeton, basic auth ou autre mecanisme Galette | A confirmer |
| Filtrage incremental | Date de modification, ETag ou pagination | A confirmer |
Decision : ne pas coupler RelaisSMS a une route Galette non confirmee. Le connecteur sera concu avec un adaptateur remplacable : API JSON si disponible, export CSV authentifie en solution de repli. Une eventuelle route vCard Galette reste un mecanisme interne au connecteur Galette, pas une source CardDAV.
## OVHcloud SMS
### Documentation consultee
- Page produit API SMS OVHcloud : <https://www.ovhcloud.com/fr/sms/api-sms/>
- Definition API OVH SMS Europe : <https://eu.api.ovh.com/1.0/sms.json>
### Endpoints retenus pour le MVP
Base API : `https://eu.api.ovh.com/1.0`
| Usage | Methode | Endpoint | Notes |
| --- | --- | --- | --- |
| Lister les services SMS | `GET` | `/sms` | Permet de selectionner `serviceName`. |
| Lire le compte SMS | `GET` | `/sms/{serviceName}` | Retourne notamment statut et credits restants. |
| Estimer un message | `POST` | `/sms/estimate` | Parametres : `message`, `noStopClause`, `senderType`. |
| Envoyer un job SMS | `POST` | `/sms/{serviceName}/jobs` | Parametres principaux : `message`, `receivers`, `sender`, `noStopClause`, `tag`. |
| Lire jobs en attente | `GET` | `/sms/{serviceName}/jobs` | Utile pour debug et suivi. |
| Lire un job | `GET` | `/sms/{serviceName}/jobs/{id}` | Suivi fin si necessaire. |
| Annuler un job | `DELETE` | `/sms/{serviceName}/jobs/{id}` | A utiliser seulement tant que l'envoi est stoppable. |
| Historique sortant | `GET` | `/sms/{serviceName}/outgoing` | Filtres disponibles : dates, destinataire, sender, tag, etc. |
| Detail sortant | `GET` | `/sms/{serviceName}/outgoing/{id}` | Permet de recuperer les informations par SMS envoye. |
| Expediteurs autorises | `GET` | `/sms/{serviceName}/senders` | Pour valider la configuration sender. |
Les endpoints batch existent aussi (`/sms/{serviceName}/batches`) et supportent les envois differes via `deferred`. Decision MVP : demarrer avec `/jobs` pour l'envoi immediat et gerer la programmation cote RelaisSMS via queue/scheduler. Les batches restent une option a reevaluer au lot 7 si l'on veut deleguer le differe a OVH.
### Credentials attendus
Configuration par variables d'environnement :
```dotenv
OVH_ENDPOINT=ovh-eu
OVH_APPLICATION_KEY=
OVH_APPLICATION_SECRET=
OVH_CONSUMER_KEY=
OVH_SMS_SERVICE_NAME=
OVH_SMS_SENDER=
OVH_SMS_NO_STOP_CLAUSE=true
```
Les secrets ne sont pas stockes en clair en base. L'interface pourra afficher l'etat de configuration sans exposer les valeurs.
### Quota et garde-fous
- Le compte OVH expose `creditsLeft` via `GET /sms/{serviceName}`.
- RelaisSMS applique sa propre limite de 100 SMS par campagne par defaut.
- Avant envoi, le connecteur doit refuser une campagne si :
- aucun `serviceName` n'est configure ;
- aucun expediteur valide n'est configure quand necessaire ;
- la liste finale depasse la limite applicative ;
- OVH retourne des destinataires invalides.
## Numeros de telephone
### Echantillon Galette
Fichier analyse : `doc/tmp/liste_adherents_filtree.csv`
- 179 lignes adherents.
- 86 numeros presents dans `Telephone` ou `GSM`.
- Exemples fictifs de formats : `06 11 11 11 11`, `0622222222`, `(+33) 6 33 33 33 33`, `+33 (0)6 44 44 44 44`, fixes francais, numeros internationaux.
### Regex portable par defaut
La regex par defaut detecte les mobiles francais bruts avant normalisation :
```regex
^\s*(?:(?:\(\s*\+33\s*\)|\+33|0033)\s*(?:\(0\)\s*)?|0)\s*[67](?:[\s.-]*\d{2}){4}\s*$
```
Elle accepte notamment :
- `06 11 11 11 11`
- `0622222222`
- `07 55 55 55 55`
- `(+33) 6 33 33 33 33`
- `+33 (0)6 44 44 44 44`
- `0033 6 11 11 11 11`
Elle exclut les fixes francais (`01`, `02`, `03`, `04`, `05`, `09`) et les numeros mobiles non francais. Le pays par defaut est `FR`.
Decision importante : cette regex sert a classifier les portables. La normalisation E.164 reste separee et devra etre faite avec `giggsey/libphonenumber-for-php` au lot 2.
## Parametres applicatifs par defaut
| Cle | Valeur par defaut | Source |
| --- | --- | --- |
| `default_country` | `FR` | Cadrage projet |
| `mobile_phone_regex` | Regex ci-dessus | Echantillon Galette |
| `max_sms_per_campaign` | `100` | Cahier des charges |
| `history_retention_years` | `3` | Cahier des charges |
| `scheduled_sends_enabled` | `true` | MVP |
| `active_sms_provider` | `ovh` | Fournisseur cible |
| `galette_sync_enabled` | `false` | Upgrade Galette non fait |
| `carddav_sync_enabled` | `false` | Active a partir du lot 3 |
## Impacts pour les lots suivants
### Lot 1
- Initialiser Laravel sans dependance Galette active.
- Authentification simple.
- Tous les utilisateurs authentifies sont administrateurs.
- Prevoir `app_settings` ou configuration equivalente pour les parametres non secrets.
### Lot 2
- Stocker `raw_number`, `normalized_number`, `is_valid`, `is_mobile`.
- Utiliser la regex configurable pour `is_mobile`.
- Ajouter `sms_opt_out` sur les contacts.
- Prevoir `deleted_at` sur contacts synchronises.
- Prevoir des cles de source distinctes pour `local`, `carddav` et `galette`.
### Lot 3
- Implementer `CardDavSourceConnector`.
- Synchroniser les vCards depuis Nextcloud/CardDAV avec UID et ETag si disponibles.
- Mapper les categories vCard en groupes importes CardDAV.
### Lot 5
- Implementer `OvhSmsProvider` via client HTTP signe.
- Journaliser reponse OVH brute et IDs retournes.
- Utiliser le champ `tag` OVH pour relier les SMS a une campagne RelaisSMS.
### Lot 9
- Revalider Galette 1.2.1 apres upgrade.
- Choisir entre API JSON, export CSV authentifie ou route Galette dediee.
- Mapper les statuts Galette en groupes applicatifs importes.
- Garder un nommage Galette explicite, separe de CardDAV/Nextcloud.
## Points ouverts
| Sujet | Question | A trancher avant |
| --- | --- | --- |
| Galette auth | Quel mecanisme d'authentification sera disponible apres upgrade ? | Lot 9 |
| Galette groupes | Les groupes sont-ils exposes directement ou seulement les statuts ? | Lot 9 |
| CardDAV categories | Les categories Nextcloud sont-elles renseignees et suffisantes comme groupes ? | Lot 3 |
| OVH sender | Expediteur alphanumerique valide ou numero reponse ? | Lot 5 |
| STOP OVH | `noStopClause=true` est-il conforme a l'usage AFPMA non publicitaire ? | Lot 5 |
| Numeros internationaux | Faut-il envoyer aux mobiles non francais presents dans les sources synchronisees ? | Lot 4 |