← Phase 1 Overview / Auth & Profils
👤
Module 1 — Phase 1 MVP

Authentification & Profils

Gestion complète de l'identité utilisateur : inscription, connexion multi-provider, profil public, confidentialité et jumeau digital IA.

Backlog

User Stories

US1.1
En tant que visiteur, je peux créer un compte avec mon email et un mot de passe sécurisé (min 8 car., 1 maj., 1 chiffre)
must 5 pts
US1.2
En tant que visiteur, je peux m'inscrire via Google OAuth2 en 1 clic
must 3 pts
US1.3
En tant que visiteur, je peux m'inscrire via Apple Sign-In (iOS obligatoire)
must 3 pts
US1.4
En tant que visiteur, je reçois un email de vérification et dois confirmer mon adresse
must 2 pts
US1.5
En tant qu'utilisateur, je peux me connecter et rester connecté 30 jours (refresh token)
must 3 pts
US1.6
En tant qu'utilisateur, je peux réinitialiser mon mot de passe via email
must 2 pts
US1.7
En tant que nouvel utilisateur, je complète un profil : photo, nom affiché, bio, pays, type de voyageur, langues
must 5 pts
US1.8
En tant qu'utilisateur, je peux voir et modifier mon profil public à tout moment
must 2 pts
US1.9
En tant qu'utilisateur, je peux configurer qui voit mes voyages (public / abonnés / privé)
must 3 pts
US1.10
En tant qu'utilisateur, je peux suivre / ne plus suivre un autre utilisateur
must 2 pts
US1.11
En tant qu'utilisateur, je vois la liste de mes abonnés et abonnements
should 1 pts
US1.12
En tant que système, je construis progressivement le jumeau digital (style voyage, budget, rythme) à partir des actions
must 8 pts
US1.13
En tant qu'utilisateur, je peux voir et éditer mon profil IA (jumeau digital) dans les paramètres
should 3 pts
US1.14
En tant qu'utilisateur, je peux supprimer mon compte (RGPD — soft delete 30j)
must 3 pts
REST API /auth & /users

Endpoints API

POST /auth/register Créer un compte email/mdp public
POST /auth/login Login + retourne access_token + refresh_token public
POST /auth/refresh Renouveler l'access token (body: refresh_token) public
POST /auth/logout Invalider refresh token 🔒 auth
POST /auth/forgot-password Envoie email reset public
POST /auth/reset-password Nouveau mdp (body: token + password) public
GET /auth/google Redirect OAuth Google public
GET /auth/google/callback Callback Google → JWT public
GET /users/me Profil complet de l'utilisateur connecté 🔒 auth
PATCH /users/me Modifier profil (bio, photo, pays...) 🔒 auth
GET /users/:id Profil public d'un utilisateur public
POST /users/:id/follow Suivre un utilisateur 🔒 auth
DELETE /users/:id/follow Ne plus suivre 🔒 auth
GET /users/:id/followers Liste abonnés (paginé) public
GET /users/:id/following Liste abonnements (paginé) public
DELETE /users/me Supprimer le compte (soft delete) 🔒 auth
Schémas de données

Tables & Relations

TABLE users
id UUID PRIMARY KEY DEFAULT gen_random_uuid() email TEXT UNIQUE NOT NULL password_hash TEXT -- null si OAuth only username TEXT UNIQUE NOT NULL display_name TEXT NOT NULL avatar_url TEXT bio TEXT country_code CHAR(2) languages TEXT[] traveler_type TEXT -- solo/family/couple/group/nomad interests TEXT[] role ENUM DEFAULT 'user' is_email_verified BOOLEAN DEFAULT false trust_score INT DEFAULT 0 -- 0-100 privacy_settings JSONB DEFAULT '{}' ai_profile JSONB DEFAULT '{}' -- jumeau digital deleted_at TIMESTAMPTZ -- soft delete created_at TIMESTAMPTZ DEFAULT NOW()
TABLE oauth_accounts
id UUID PRIMARY KEY user_id UUID REFERENCES users(id) provider TEXT -- 'google' | 'apple' provider_id TEXT NOT NULL email TEXT created_at TIMESTAMPTZ DEFAULT NOW() UNIQUE(provider, provider_id)
TABLE refresh_tokens
id UUID PRIMARY KEY user_id UUID REFERENCES users(id) token_hash TEXT NOT NULL -- SHA256 du token expires_at TIMESTAMPTZ NOT NULL revoked_at TIMESTAMPTZ -- null = valide user_agent TEXT ip_address INET
TABLE follows
follower_id UUID REFERENCES users(id) following_id UUID REFERENCES users(id) created_at TIMESTAMPTZ DEFAULT NOW() PRIMARY KEY (follower_id, following_id)
Business Logic

Règles Métier & Sécurité

🔐
JWT Access Token : 15 minutes
Short-lived pour limiter l'exposition en cas de fuite. Refresh token 30 jours, stocké en HttpOnly cookie sur web, SecureStorage sur mobile.
🔒
Mot de passe : bcrypt (cost factor 12)
Jamais stocké en clair. Reset via token HMAC SHA256 valable 1h uniquement.
📧
Email de vérification obligatoire
L'utilisateur peut naviguer mais ne peut pas poster avant validation. Renvoi possible toutes les 5 min.
🤖
Jumeau digital construit progressivement
À chaque post/itinéraire/destination visitée/préférence IA, le champ ai_profile est enrichi. Utilisé par le Copilote pour personnaliser les réponses.
🛡️
Rate limiting auth
5 tentatives de login par IP par 15 min. Lockout 30 min après. Alerte email si 3 lockouts en 24h.
🗑️
Soft delete 30j
Données anonymisées (email → deleted_UUID@nomiiq.com) mais conservées 30j pour réactivation. Purge définitive J+30.
👁️
Confidentialité granulaire
privacy_settings JSONB : { show_trips: "public"|"followers"|"private", show_dates: bool, show_location_exact: bool }
Critères d'acceptation
Inscription email → email de vérification reçu en < 30 secondes
Login Google fonctionne sur iOS 16+ et Android 10+
Access token expiré → refresh automatique transparent pour l'utilisateur
Profil incomplet (< 3 champs) → banner incitatif persistent
Suppression compte → données indisponibles immédiatement, purge effective J+30
Jumeau digital mis à jour après chaque action significative (max 5s de délai)
Rate limiting : 6ème tentative bloquée avec message explicatif