Aller au contenu

Staging & credentials UAT

Le jeu de données UAT est créé par le script apps/api/src/scripts/seed-uat.ts, lancé via :

Fenêtre de terminal
DATABASE_URL=<pool pms_app> \
MFA_ENCRYPTION_KEY_BASE64=<clé AES-256 base64 32 octets> \
pnpm --filter @pms/api seed:uat

Le seed est idempotent : re-lancer ne crée pas de doublons (idempotence par slug/code/email).

ChampValeur
Sluguat-osmozis
NomUAT Osmozis
Structure orgGroupe UAT-GROUP / Entité légale UAT-LE (SAS Osmozis UAT)
SIREN123456789
CodeNomTypeSIRET
UAT-HOTELHôtel UAT Les Pinshotel12345678900001
UAT-CAMPCamping UAT Les Étoilescampsite12345678900002

Les IDs (UUID) sont générés au premier run. Ils sont affichés dans la sortie console du seed :

SEED UAT — RÉSUMÉ
Tenant ID : <uuid>
Hôtel ID : <uuid>
Camping ID : <uuid>

Mot de passe commun : Uat2026!Osmozis

Source : seed-uat.ts constante UAT_PASSWORD + tableau UAT_USERS.

EmailRôlePérimètre
receptionist@uat.osmozis.comreceptionistCheck-in/out, board arrivées/départs, folio
housekeeper@uat.osmozis.comhousekeeperBoard HK, tâches ménage
manager@uat.osmozis.commanagerDashboard, rapports, réservations, tarifs
technician@uat.osmozis.commaintenance-technicianWork-orders, asset maintenance
accountant@uat.osmozis.comaccountantFolio, FEC, fiscal
admin@uat.osmozis.comtenant-adminAdministration tenant, users/rôles
director@uat.osmozis.comdirectorHôtel UAT + Camping UAT (scope /UAT-GROUP)

Scope RBAC de tous ces comptes : /UAT-GROUP (couvre les deux établissements).

Le persona Directeur (director@uat.osmozis.com) dispose des mêmes permissions que tenant-admin, avec un scope OrgPath /UAT-GROUP couvrant explicitement les deux établissements UAT (hôtel + camping). Rôle créé par ADR-00D86 pour la direction opérationnelle multi-établissements.

Les comptes sont créés sans enrôlement TOTP confirmé. À la première connexion, le front redirige automatiquement vers l’écran d’enrôlement MFA (MFA_ENROLLMENT_REQUIRED).

L’écran d’enrôlement affiche :

  • Un QR code SVG (role="img", accessible)
  • Le secret base32 copiable (pour une saisie manuelle dans l’appli TOTP)

Le secret TOTP n’est jamais persisté côté front — il est généré par l’API à la demande d’enrôlement, chiffré AES-256-GCM en base de données après confirmation du premier code valide.

Applications TOTP compatibles : Google Authenticator, Authy, 1Password, Bitwarden.

Le compte opérateur est créé séparément via seed:operator (voir Installation).

ChampValeur par défaut
Emailadmin@platform.internal (configurable via OPERATOR_EMAIL)
operatorId00000000-0000-4000-8000-000000000001
Mot de passeFourni via OPERATOR_PASSWORD (non hardcodé)
Clé API CLIGénérée au run, affichée une seule fois — stocker dans un gestionnaire de secrets

Le script affiche le secret TOTP base32 et l’URI TOTP (pour import dans une app TOTP) une seule fois. Re-lancer le seed renouvelle le secret (rotation MFA).

L’opérateur se connecte via la console admin (apps/admin, port 4301) :

  1. POST /admin/cp-sessions avec email + password → cookie cp_session httpOnly
  2. Saisie du code TOTP → cookie validé
  3. Toutes les requêtes /admin/* transportent le cookie automatiquement (SameSite=Strict)
  4. La session expire après 15 min d’inactivité ou 4 h absolues (CSRF Origin fail-closed)

9 scénarios créés par le seed pour l’hôtel UAT :

ScénarioÉtatInvité
ATentative (dans 14 j)Martin Dupont — martin.dupont@uat.test
BConfirmed (dans 7 j)Sophie Bernard — sophie.bernard@uat.test
CCheckedIn (hier → demain, folio avec charge mini-bar 15 €)Jean Lefort — jean.lefort@uat.test
DConfirmed arrivée du jourClaire Moreau — claire.moreau@uat.test
ECheckedIn départ du jour (check-out à faire)Pierre Blanc — pierre.blanc@uat.test
FCancelledAnne Lefebvre — anne.lefebvre@uat.test
GNoShowRobert Martin — robert.martin@uat.test
HConfirmed walk-in (à check-in manuellement)Isabelle Roy — isabelle.roy@uat.test
IConfirmed camping (emplacement EMP, dans 3 j)Luc Pinson — luc.pinson@uat.test

Le folio du scénario C contient :

  • Une charge mini-bar : 12,50 € HT + 2,50 € TVA 20 % = 15,00 € TTC
  • Un règlement espèces : 10,00 €
CodeNomÉtablissementTarif de base
BARBest Available RateHôtel120,00 € / chambre / nuit
NRNon RemboursableHôtel90,00 € / chambre / nuit
CAMP-BSCamping Basse SaisonCamping15 € unité + 6 € adulte/nuit
CAMP-HSCamping Haute SaisonCamping22 € unité + 9 € adulte/nuit
CodeNomNombreFormat
STDChambre Standard4room
DLXChambre Deluxe4room
STESuite2room

Horizon inventaire : J-7 → J+30 (généré au run du seed).

CodeNomNombreFormat
EMPEmplacement nu6pitch
MHMobil-home 2ch4mobile_home

Depuis ADR-00D85, aucun x-tenant-id n’est requis au login : le serveur résout le tenant depuis l’adresse email (unique globalement). Le header x-tenant-id est uniquement requis sur le refresh de token.

  1. POST /sessions — corps : { email, password } → réponse { accessToken, refreshToken } ou { mfaRequired: true, sessionToken }
  2. Si mfaRequired: true : POST /sessions/mfa/verify — corps : { sessionToken, code }{ accessToken, refreshToken }
  3. Si premier login (enrôlement MFA) : réponse { enrollmentRequired: true }POST /sessions/mfa/enroll/begin avec { email, password }{ otpauthUri, secret } → scanner le QR → POST /sessions/mfa/enroll/confirm avec { email, password, code }{ accessToken, refreshToken }
  4. Après login, appeler GET /v1/me pour récupérer le tenantId (data.tenantId) et le persister côté client (nécessaire pour POST /sessions/refresh qui exige le header x-tenant-id)
  5. Inclure Authorization: Bearer <accessToken> dans toutes les requêtes API

Le refreshToken est un token opaque haché en base de données (reuse-detection activée).

Une collection Bruno (outil REST open-source) est disponible dans le dossier /data/PMS/bruno/ du monorepo. Elle couvre les principaux appels API avec les credentials UAT pré-remplis.

Pour l’utiliser : installer Bruno, ouvrir la collection, configurer l’environnement staging avec BASE_URL=http://localhost:3000.