19 KiB
Design Requirements — Socle Plateforme SchotzimmO (aspects techniques)
Introduction
Ce document rassemble les exigences techniques dérivées du besoin fonctionnel métier décrit dans requirements.md. Il est organisé en miroir : chaque section reprend le même numéro et le même titre que requirements.md, suivi de « — aspects techniques ». Seules les exigences comportant effectivement des critères techniques y figurent.
Ces exigences sont arbitrées conjointement par le PO business et le PO IT. Les choix d'architecture, modèles de données et contrats d'API détaillés sont, eux, décrits dans design.md.
Les mots-clés EARS (WHEN / IF / WHILE / WHERE / THE ... SHALL) sont conservés. Les termes techniques, identifiants, codes HTTP, en-têtes et noms d'API restent en anglais ou sous leur forme littérale.
Glossary (technique)
- Base_Socle : La base MariaDB centrale et unique portant l'authentification, le référentiel des Reseaux et leurs informations de connexion, les abonnements, le catalogue des Modules/Packs et les KPI d'usage par Reseau. Aucune donnée métier produite par les Mandataires.
- Base_Reseau : La base MariaDB propre à un Reseau, portant toutes ses données métier (profil mandataire, parrainage, données des Modules). Une Base_Reseau par Reseau.
- Reference_Logique : Un identifiant (
AccountId) généré par la Base_Socle et réutilisé dans une Base_Reseau sans contrainte FK SQL ni jointure inter-bases ; la cohérence est assurée applicativement. - NetworkConnectionResolver : Le composant qui, à partir du claim
networkdu JWT, résout la clé logique (db_connection_key) du Reseau vers la chaîne de connexion de sa Base_Reseau fournie par configuration. - JWT : JSON Web Token signé émis à la connexion, portant l'identité du Mandataire (
sub= AccountId), son Reseau (network), son rôle (role∈ {mandataire,admin}) et une échéance (exp). - Claim : Une assertion portée par le JWT (identité, Reseau, rôle), utilisée côté Backend pour le contrôle d'accès.
- Access_Token : Le JWT d'accès transmis par le Frontend dans l'en-tête
Authorization: Bearer <token>à chaque appel protégé. - Hash_Mot_De_Passe : L'empreinte du Mot_De_Passe calculée avec un algorithme de hachage adapté aux mots de passe (ex. PBKDF2/BCrypt/Argon2), avec sel ; le Mot_De_Passe n'est jamais stocké en clair ni journalisé.
- SMTP : Le service d'envoi d'e-mails (invitations, réinitialisation). Configurable ; un
Smtp:Hostvide active un repli de journalisation du lien plutôt qu'un envoi. - Config_BDD : Les chaînes de connexion MariaDB/MySQL (Base_Socle et chaque Base_Reseau), fournies par configuration (variables d'environnement), pointant soit vers des instances conteneurisées, soit vers un serveur externe. La Base_Socle ne stocke qu'une clé logique par Reseau, jamais la chaîne elle-même.
- Migration : Une migration de schéma gérée par l'ORM (EF Core), appliquée de façon idempotente au démarrage ou via commande.
- DTO : Data Transfer Object, objet de transport exposé par l'API, distinct des entités persistées.
- Code_HTTP : Le statut HTTP retourné par l'API (ex. 200, 201, 400, 401, 403, 404, 409, 422, 500).
- Portee_Hierarchique : Le périmètre de données qu'un appel peut retourner compte tenu de la Visibilite_Descendante (soi-même, Descendance agrégée, Filleuls_Directs en détail).
Requirements (aspects techniques)
Requirement 1: Inscription d'un Mandataire — aspects techniques
- THE Backend SHALL exposer l'inscription via
POST /api/auth/registeracceptant un DTO { email, password, firstName, lastName, networkId, networkMemberId, legalStatus?, siren?, referralToken? }. - WHEN l'inscription réussit, THE Backend SHALL répondre
201 Createdet ne jamais retourner le Hash_Mot_De_Passe ni aucune donnée de sécurité. - IF l'Adresse_Email est déjà utilisée, THEN THE Backend SHALL répondre
409 Conflictavec un message générique ne révélant aucune donnée du Compte existant. - IF le DTO est invalide (champ obligatoire manquant, email mal formé, password < 8 caractères, siren au format incorrect), THEN THE Backend SHALL répondre
422 Unprocessable Entityavec le détail des champs en erreur. - THE Backend SHALL stocker le Mot_De_Passe uniquement sous forme de Hash_Mot_De_Passe salé ; en aucun cas en clair.
- THE Backend SHALL valider l'Adresse_Email par une expression de forme standard et normaliser sa casse (minuscule) avant unicité et Rapprochement_Email.
- WHEN un
referralTokenvalide et non expiré est fourni, THE Backend SHALL en extrairenetworkIdet l'identité du Parrain et ignorer toutnetworkIddivergent fourni par le client. - IF le
referralTokenest fourni mais invalide ou expiré, THEN THE Backend SHALL répondre400 Bad Requestet signaler que le lien d'invitation n'est plus valide.
Requirement 2: Authentification et session — aspects techniques
- THE Backend SHALL exposer
POST /api/auth/login{ email, password, rememberMe? } et retourner, en cas de succès, un Access_Token (JWT) et son échéance. - THE Backend SHALL signer le JWT avec une clé secrète fournie par configuration (
JWT:SecretKey), échouer au démarrage si la clé est absente, et appliquer une durée de validité configurable (JWT:ExpirationMinutes, défaut 720). - THE JWT SHALL porter les claims
sub(AccountId),network(NetworkId),roleetexp. - WHEN les identifiants sont invalides, THE Backend SHALL répondre
401 Unauthorizedavec un message générique, sans distinguer email inconnu et mot de passe erroné, et SHALL appliquer une temporisation ou limitation de débit contre le forçage. - THE Backend SHALL protéger toutes les routes métier par une authentification Bearer et répondre
401 Unauthorizeden l'absence d'un Access_Token valide. - THE Frontend SHALL transmettre l'Access_Token dans l'en-tête
Authorization: Bearer <token>et effacer le token local à la déconnexion. - THE Frontend SHALL stocker l'Identifiant_Mémorisé dans le stockage local du navigateur et ne jamais y stocker le Mot_De_Passe ni l'Access_Token au-delà de la politique de session définie.
- THE Backend SHALL exposer
POST /api/auth/forgot-password{ email } répondant toujours200 OKquel que soit l'existence de l'Adresse_Email (anti-énumération), et générer le Jeton_Reinitialisation uniquement si le Compte existe. - THE Backend SHALL générer un Jeton_Reinitialisation cryptographiquement aléatoire, à usage unique, de durée de vie configurable (
Auth:ResetTokenLifetimeMinutes, défaut 60), stocké sous forme hachée. - THE Backend SHALL exposer
POST /api/auth/reset-password{ token, newPassword } répondant200 OKen cas de succès,400 Bad Requestsi le token est invalide, expiré ou déjà consommé, et422si le nouveau mot de passe est trop court. - THE Backend SHALL construire les liens d'e-mail à partir d'une base d'URL configurable (
Auth:FrontendBaseUrl).
Requirement 3: Réseaux — aspects techniques
- THE Backend SHALL persister dans la Base_Socle un référentiel
Networks(code, libellé,db_connection_key,theme_settings,is_active,is_provisioned) et exposerGET /api/networks(Reseaux actifs et provisionnés) accessible sans authentification pour alimenter l'inscription. - THE Backend SHALL stocker toutes les données métier d'un Reseau dans sa Base_Reseau dédiée ; les tables de Base_Reseau ne portent pas de colonne
NetworkId(le cloisonnement est physique). - THE NetworkConnectionResolver SHALL déterminer la Base_Reseau de chaque requête métier à partir du claim
networkdu JWT, indépendamment de tout paramètre fourni par le client. - IF le claim
networkne correspond à aucun Reseau actif et provisionné, THEN THE Backend SHALL répondre403 Forbiddenet n'ouvrir aucune connexion. - WHEN l'Administrateur réalise l'Onboarding_Reseau, THE Backend SHALL créer/initialiser la Base_Reseau (schéma + données de référence) via
POST /api/admin/networks, enregistrerdb_connection_keyettheme_settings, puis positionneris_provisioned = 1. - IF la Base_Reseau d'un Reseau est indisponible ou non provisionnée, THEN THE Backend SHALL répondre
503 Service Unavailablesans exposer de détail d'infrastructure. - THE Backend SHALL fournir au Frontend la Personnalisation_Reseau (
theme_settings) du Reseau courant pour l'application du thème et des libellés.
Requirement 4: Parrainage et hiérarchie — aspects techniques
- THE Backend SHALL modéliser l'Arbre_Parrainage dans la Base_Reseau par une relation d'auto-référence
mandataire_profiles.sponsor_account_id(vraie FK intra-base), et un état d'Affiliation (supposee,validee). - THE Backend SHALL modéliser le Membre_Declare dans la Base_Reseau comme une entité porteuse d'Adresse_Email normalisée, lien hiérarchique et statut, sans credentials ni données métier (le cloisonnement Reseau étant physique, pas de
NetworkId). - THE Backend SHALL exposer
POST /api/referrals/declare(déclarer un Parrain ou des Filleuls) etPOST /api/referrals/{id}/invite(envoyer l'Invitation par SMTP). - WHEN une Invitation est envoyée, THE Backend SHALL générer un Lien_Parrainage signé (token portant
networkIdet identité du Parrain), de durée de vie configurable, et l'inclure dans l'e-mail viaAuth:FrontendBaseUrl. - WHEN
Smtp:Hostest vide, THE Backend SHALL journaliser le Lien_Parrainage et le lien de réinitialisation au lieu de les envoyer, pour les environnements sans SMTP. - THE Backend SHALL effectuer le Rapprochement_Email sur l'Adresse_Email normalisée (casse ignorée) lors de toute inscription, et convertir le Membre_Declare (Base_Reseau) en profil mandataire lié au Compte créé (Base_Socle), en coordonnant les deux bases avec compensation en cas d'échec partiel.
- IF une déclaration introduit un cycle (le descendant deviendrait ancêtre), THEN THE Backend SHALL répondre
409 Conflictsans persister. - THE Backend SHALL exposer
POST /api/referrals/confirmationsetPOST /api/referrals/confirmations/{id}/approve|rejectpour la Confirmation_Affiliation entre Comptes déjà inscrits, et répondre403 Forbiddensi l'appelant n'est pas la partie concernée. - THE Backend SHALL garantir, par contrainte applicative, au plus un
sponsor_account_idvalidé par mandataire à un instant donné.
Requirement 5: Visibilité hiérarchique descendante — aspects techniques
- THE Backend SHALL dériver la Portee_Hierarchique d'un appel à partir du claim
sub, en calculant la Descendance via la relationsponsor_account_idau sein de la Base_Reseau de l'appelant. - WHEN une Vue_Agregee est demandée, THE Backend SHALL calculer les agrégats sur l'ensemble de la Descendance par requête serveur, sans retourner d'identifiants individuels dans la réponse agrégée.
- WHEN une Vue_Detail_Direct est demandée, THE Backend SHALL restreindre le jeu de résultats aux mandataires dont le
sponsor_account_idest directement l'appelant (N+1). - IF un appel vise un AccountId hors de la Portee_Hierarchique de l'appelant, THEN THE Backend SHALL répondre
403 Forbiddensans révéler l'existence de la ressource (ne pas distinguer de404pour les ressources hors périmètre lorsque la divulgation serait sensible). - THE Backend SHALL exposer les capacités de partage hiérarchique via un contrat commun que chaque Module implémente (fourniture d'agrégats et, le cas échéant, de détail N+1), sans que le socle ne présume des données de chaque Module.
Note de calcul (indicateurs envisagés, non figés) : les premiers agrégats pressentis sont le nombre de mandats en entrée, le nombre de mandats en sortie, le chiffre d'affaires et le nombre de Filleuls par niveau. Leur définition précise relève des specs des Modules fournisseurs.
Requirement 6: Annuaire des abonnés — aspects techniques
- THE Backend SHALL exposer
GET /api/directoryretournant les Comptes et Membres_Declares dunetworkdu claim, paginé, avec un indicateur d'état (inscrit / déclaré). - THE Backend SHALL exposer
GET /api/directory/treeretournant l'Arbre_Parrainage de la Descendance de l'appelant. - THE Backend SHALL n'exposer dans ces endpoints que des champs d'annuaire (nom, prénom, Identifiant_Reseau, état, lien hiérarchique) et aucune donnée métier de Module.
- THE Backend SHALL supporter une recherche serveur par nom, prénom ou Identifiant_Reseau et limiter la taille de page par défaut (ex. 50) avec pagination.
Requirement 7: Abonnements et Packs — aspects techniques
- THE Backend SHALL persister les Packs et les Abonnements, un Abonnement portant AccountId, PackId, dates d'effet et statut (
actif,expire). - THE Backend SHALL exposer
GET /api/subscription(abonnement courant et Modules résultants) etPOST /api/subscription(changement de Pack). - WHEN un changement de Pack est appliqué, THE Backend SHALL recalculer côté serveur la liste des Modules_Accessibles par inclusion des Packs inférieurs.
- THE Backend SHALL déterminer les Modules_Consultation_Seule en comparant les Modules non inclus dans le Pack courant avec la présence de données persistées du Mandataire pour ces Modules.
- IF une action d'écriture est tentée sur un Module hors Abonnement, THEN THE Backend SHALL répondre
403 Forbiddenavec un code applicatif indiquant « abonnement requis ». - WHERE un paiement en ligne sera introduit ultérieurement, THE Backend SHALL isoler la logique de facturation d'abonnement derrière une abstraction (le MVP gère l'activation manuelle par l'Administrateur ou l'auto-attribution Starter), sans dépendance de paiement dans le socle initial.
Requirement 8: Catalogue et activation des Modules — aspects techniques
- THE Backend SHALL persister un Catalogue_Modules { ModuleKey, libellé, PackId requis, actif } et l'exposer via
GET /api/modules. - THE Backend SHALL initialiser le Catalogue avec :
carnet-adresses,kms,facturation→ Pack Starter ;crm,agenda→ Pack Pro. - THE Backend SHALL protéger les routes de chaque Module par un contrôle d'autorisation vérifiant, à partir des claims et de l'Abonnement, le droit d'accès (plein accès ou consultation seule), et répondre
403 Forbiddenà défaut. - THE Backend SHALL distinguer, dans la réponse
GET /api/modules, l'état de chaque Module pour l'appelant (accessible,consultation,verrouille) afin que le Frontend adapte la navigation. - THE Frontend SHALL masquer ou désactiver les actions d'écriture d'un Module en état
consultationet proposer un parcours de montée en abonnement pour un Moduleverrouille.
Requirement 9: Administration de la Plateforme — aspects techniques
- THE Backend SHALL matérialiser le rôle Administrateur par le claim
role=adminet protéger les routes/api/admin/**par une autorisation dédiée répondant403 Forbiddenà tout appelant non admin. - THE Backend SHALL exposer
GET /api/admin/accounts(tous Reseaux, via la Base_Socle, avec Reseau, Abonnement, statut),PUT /api/admin/accounts/{id}/subscription, etPUT /api/admin/modules(gestion Module->Pack). - THE Backend SHALL exposer
POST /api/admin/networksetPUT /api/admin/networks/{id}pour l'Onboarding_Reseau et le paramétrage (Personnalisation_Reseau). - THE Backend SHALL exposer
GET /api/admin/statsretournant les KPI d'usage remontés par chaque Reseau (tablenetwork_usage_kpisde la Base_Socle), sans requête ni jointure traversant les Base_Reseau et sans donnée métier individuelle. - THE Backend SHALL exposer des endpoints d'administration de l'Arbre_Parrainage (Base_Reseau concernée) permettant de rattacher, détacher ou réaffecter un mandataire, en refusant (
409 Conflict) toute opération créant un cycle.
Requirement 10: Tableau de bord — aspects techniques
- THE Backend SHALL exposer
GET /api/dashboardagrégeant les contributions des seuls Modules_Accessibles de l'appelant via un contrat de fourniture commun. - THE Backend SHALL borner le périmètre des données du Tableau_De_Bord à l'appelant et à sa Portee_Hierarchique.
- THE Frontend SHALL afficher un état vide explicite par section lorsque le Module correspondant ne fournit aucun élément.
- THE Backend SHALL concevoir l'agrégation du Tableau_De_Bord de façon résiliente : la défaillance de la contribution d'un Module ne doit pas empêcher le rendu des autres sections.
Requirement 11: Cadre applicatif et navigation — aspects techniques
- THE Frontend SHALL être une application Angular (TypeScript) à routage protégé par un garde d'authentification redirigeant vers la connexion en l'absence de Session valide.
- THE Frontend SHALL construire dynamiquement la navigation des Modules à partir de
GET /api/modules(étatsaccessible/consultation/verrouille). - THE Frontend SHALL présenter un composant d'identité (avatar par initiales) donnant accès au Profil, au paramétrage, à l'Abonnement et à la déconnexion.
- THE Frontend SHALL centraliser la présentation des erreurs d'API par mappage des Codes_HTTP vers des messages utilisateur en français (401 → reconnexion, 403 → accès/abonnement requis, 422 → erreurs de champ, 5xx → indisponibilité).
- THE Backend SHALL exposer
GET /api/profileetPUT /api/profilepermettant de modifier l'identité et les coordonnées, en interdisant la modification duNetworkId.
Requirement 12: Persistance et isolation des données par Réseau — aspects techniques
- THE Backend SHALL utiliser MariaDB/MySQL avec une Base_Socle et une Base_Reseau par Reseau ; chaque Config_BDD est fournie par variable d'environnement, pointant vers une instance conteneurisée ou un serveur externe, sans changement de code.
- THE Backend SHALL gérer deux jeux de Migrations EF Core : le schéma socle appliqué à la Base_Socle, et le schéma réseau appliqué de façon idempotente à chaque Base_Reseau.
- THE Backend SHALL utiliser deux DbContext (
SocleDbContext,ReseauDbContext), leReseauDbContextrecevant sa chaîne de connexion de la requête via le NetworkConnectionResolver. - THE Backend SHALL garantir qu'aucune requête ni jointure ne traverse deux Base_Reseau, et qu'aucune donnée d'un Reseau n'est atteignable depuis le contexte d'un autre Reseau ; les requêtes métier sont en outre bornées à la Portee_Hierarchique de l'appelant.
- WHEN une opération écrit plusieurs entités au sein d'une même base, THE Backend SHALL l'exécuter dans une transaction unique avec rollback complet en cas d'échec ; WHEN une opération touche à la fois la Base_Socle et une Base_Reseau (ex. création de Compte + profil), THE Backend SHALL la séquencer avec compensation applicative (pas de transaction distribuée).
- THE Backend SHALL ne jamais journaliser de secret (Mot_De_Passe, token, chaîne de connexion) et masquer ces valeurs dans les logs et messages d'erreur ; la Base_Socle ne stocke qu'une clé logique de connexion par Reseau.
- THE Backend SHALL exposer
GET /healthpour la sonde de disponibilité du déploiement (healthcheck conteneur). - THE deployment SHALL s'orchestrer via Docker Compose (service Backend ASP.NET Core, service Frontend statique), les bases MariaDB (Base_Socle et Base_Reseau) étant soit des services du Compose, soit un serveur externe référencé par la Config_BDD.