## Backend - Modifications Necessaires pour Mode Invite + Fusion

Objectif: permettre a un utilisateur non connecte de creer/suivre ses actions (signalements, messages, suivi dossier), puis lier ces donnees a son compte apres login, tout en distinguant strictement GUEST vs AUTH_USER.

### 1) Invariants metier (obligatoires)
- Toute action metier doit avoir un acteur valide:
  - acteur connecte: actorType=AUTH_USER et actorUserId non null
  - acteur invite: actorType=GUEST et actorGuestId non null
- Les donnees invitees restent en base meme si le stockage local de l'app est perdu.
- La fusion guest->user est idempotente (rejouable sans doublons).
- Distinction obligatoire dans toutes les reponses: sourceActeur.

### 2) Nouvelles structures DB

#### 2.1 Table guest_sessions
- id (uuid, PK) = guestId
- statut (ACTIVE, MERGED, DISABLED)
- telephoneHash (string, index)
- telephoneChiffre (string, nullable)
- deviceFingerprint (string, nullable)
- createdAt, updatedAt, lastSeenAt
- mergedIntoUserId (uuid, nullable)
- mergedAt (datetime, nullable)

Index recommandes:
- idx_guest_sessions_telephone_hash
- idx_guest_sessions_statut

#### 2.2 Table guest_merge_audit
- id (uuid, PK)
- guestId
- userId
- mergeRequestId (string, unique)
- summaryJson (json)
- createdAt

Contrainte cle:
- unique(mergeRequestId) pour idempotence metier.

#### 2.3 Colonnes actor sur tables metier
Sur les aggregates concernes (signalements, discussions, messages, timeline/notes de suivi si applicable):
- actorType (enum AUTH_USER|GUEST)
- actorUserId (nullable)
- actorGuestId (nullable)

Regle SQL:
- CHECK actorType/ids coherents.

### 3) Endpoints nouveaux (API v1)

#### 3.1 Session invitee
- POST /guest/sessions
  - Body: { telephone, deviceFingerprint? }
  - Reponse data: { guestId, statut, createdAt }
- GET /guest/sessions/{guestId}
  - Reponse data: { guestId, statut, telephoneMasked, lastSeenAt }
- PATCH /guest/sessions/{guestId}/telephone
  - Body: { telephone }
  - Reponse data: { guestId, telephoneMasked, updatedAt }

#### 3.2 Fusion
- GET /guest/sessions/{guestId}/merge-preview
  - Query: userId (optionnel si derive du JWT)
  - Reponse data: {
      guestId,
      userId,
      canMerge,
      counts: { signalements, discussions, messages, suivis },
      conflicts: []
    }
- POST /guest/sessions/{guestId}/merge
  - Headers: Idempotency-Key (obligatoire)
  - Body: { acceptPolicy: "MERGE_ALL" | "MERGE_SAFE" }
  - Reponse data: {
      merged: true,
      guestId,
      userId,
      migratedCounts,
      mergedAt
    }

### 4) Endpoints existants a etendre

#### 4.1 Signalements
- POST /signalements/
  - Autoriser 2 modes:
    - JWT present -> actorType=AUTH_USER
    - JWT absent + guestId valide -> actorType=GUEST
- GET /signalements/me (JWT)
  - inchange pour connecte
- Nouveau: GET /signalements/guest/me
  - Auth par guestId (header X-Guest-Id ou query guestId)
  - Retourne uniquement les signalements de la guest session
- GET /signalements/{id}
  - Autoriser acces si proprietaire auth OU proprietaire guest

#### 4.2 Discussions/messages
- POST /discussions/
  - Autoriser creation par guestId
- GET /discussions/
  - connecte: inchange
- Nouveau: GET /discussions/guest/me
  - filtrage par actorGuestId
- POST /discussions/{discussion_id}/messages
  - autoriser message si participant guest owner
- GET /discussions/{discussion_id}/messages
  - autoriser lecture guest owner

#### 4.3 Suivi dossier invite
- Nouveau: GET /guest/suivi
  - Retour de suivi agrege (signalement + statut + unread)
- Nouveau: GET /guest/suivi/{reference}
  - detail de suivi invite (sans surfaces admin)

### 5) Contrat de distinction GUEST vs AUTH_USER
Toutes les reponses des objets concernes ajoutent:
- sourceActeur: "GUEST" | "AUTH_USER"
- acteurId: userId ou guestId
- estFusionne (optionnel): bool

Exemple signalement reponse:
- sourceActeur: "GUEST"
- acteurId: "<guestId>"

### 6) Regles de fusion (transactionnelles)
- Debut transaction.
- Verifier guest session ACTIVE et user cible valide.
- Verrouiller la guest session (SELECT FOR UPDATE).
- Migrer proprietes actorGuestId -> actorUserId sur tous les aggregates.
- Eviter doublons discussions/messages via cle metier (discussionId/messageId origine).
- Inserer trace guest_merge_audit avec mergeRequestId.
- Marquer guest_sessions.statut=MERGED + mergedIntoUserId + mergedAt.
- Commit.

Idempotence:
- Si meme Idempotency-Key rejoue, renvoyer resultat precedent (200).

### 7) Securite / confidentialite
- Pas de token JWT stocke dans guest session.
- telephone stocke en hash indexable + version chiffree si necessaire affichage.
- Rate-limit sur creation session invitee et merge.
- Journal d'audit obligatoire (creation guest, update telephone, merge accepted/refused).
- Aucun log de donnees sensibles en clair.

### 8) Gestion des erreurs
Codes recommandes:
- GUEST_SESSION_NOT_FOUND
- GUEST_SESSION_INVALID
- GUEST_SESSION_MERGED
- GUEST_MERGE_CONFLICT
- GUEST_MERGE_IDEMPOTENT_REPLAY
- GUEST_ACCESS_DENIED

### 9) Compatibilite et migration
- Migration DB en 2 etapes:
  1) ajout colonnes actor nullable + backfill AUTH_USER
  2) ajout contraintes CHECK apres backfill
- Feature flag backend: guestModeEnabled
- Deploiement progressif:
  - activer endpoints guest lecture
  - activer creation guest
  - activer merge

### 10) Tests backend obligatoires
- Unit tests:
  - creation guest session
  - merge preview
  - merge idempotent
- Integration tests:
  - signalement guest create/list/detail
  - discussion guest create/send/list
  - merge guest->user avec verification de proprietaire
- Non regression:
  - parcours utilisateur connecte existant inchange
