Staging & credentials UAT
Seed UAT
Section intitulée « Seed UAT »Le jeu de données UAT est créé par le script apps/api/src/scripts/seed-uat.ts, lancé via :
DATABASE_URL=<pool pms_app> \MFA_ENCRYPTION_KEY_BASE64=<clé AES-256 base64 32 octets> \pnpm --filter @pms/api seed:uatLe seed est idempotent : re-lancer ne crée pas de doublons (idempotence par slug/code/email).
Tenant UAT
Section intitulée « Tenant UAT »| Champ | Valeur |
|---|---|
| Slug | uat-osmozis |
| Nom | UAT Osmozis |
| Structure org | Groupe UAT-GROUP / Entité légale UAT-LE (SAS Osmozis UAT) |
| SIREN | 123456789 |
Établissements
Section intitulée « Établissements »| Code | Nom | Type | SIRET |
|---|---|---|---|
UAT-HOTEL | Hôtel UAT Les Pins | hotel | 12345678900001 |
UAT-CAMP | Camping UAT Les Étoiles | campsite | 12345678900002 |
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>Comptes utilisateurs (7 rôles)
Section intitulée « Comptes utilisateurs (7 rôles) »Mot de passe commun : Uat2026!Osmozis
Source : seed-uat.ts constante UAT_PASSWORD + tableau UAT_USERS.
| Rôle | Périmètre | |
|---|---|---|
receptionist@uat.osmozis.com | receptionist | Check-in/out, board arrivées/départs, folio |
housekeeper@uat.osmozis.com | housekeeper | Board HK, tâches ménage |
manager@uat.osmozis.com | manager | Dashboard, rapports, réservations, tarifs |
technician@uat.osmozis.com | maintenance-technician | Work-orders, asset maintenance |
accountant@uat.osmozis.com | accountant | Folio, FEC, fiscal |
admin@uat.osmozis.com | tenant-admin | Administration tenant, users/rôles |
director@uat.osmozis.com | director | Hô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.
MFA TOTP
Section intitulée « MFA TOTP »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.
Compte opérateur control-plane
Section intitulée « Compte opérateur control-plane »Le compte opérateur est créé séparément via seed:operator (voir Installation).
| Champ | Valeur par défaut |
|---|---|
admin@platform.internal (configurable via OPERATOR_EMAIL) | |
operatorId | 00000000-0000-4000-8000-000000000001 |
| Mot de passe | Fourni via OPERATOR_PASSWORD (non hardcodé) |
| Clé API CLI | Gé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) :
- POST
/admin/cp-sessionsavec email + password → cookiecp_sessionhttpOnly - Saisie du code TOTP → cookie validé
- Toutes les requêtes
/admin/*transportent le cookie automatiquement (SameSite=Strict) - La session expire après 15 min d’inactivité ou 4 h absolues (CSRF Origin fail-closed)
Données de jeu (réservations)
Section intitulée « Données de jeu (réservations) »9 scénarios créés par le seed pour l’hôtel UAT :
| Scénario | État | Invité |
|---|---|---|
| A | Tentative (dans 14 j) | Martin Dupont — martin.dupont@uat.test |
| B | Confirmed (dans 7 j) | Sophie Bernard — sophie.bernard@uat.test |
| C | CheckedIn (hier → demain, folio avec charge mini-bar 15 €) | Jean Lefort — jean.lefort@uat.test |
| D | Confirmed arrivée du jour | Claire Moreau — claire.moreau@uat.test |
| E | CheckedIn départ du jour (check-out à faire) | Pierre Blanc — pierre.blanc@uat.test |
| F | Cancelled | Anne Lefebvre — anne.lefebvre@uat.test |
| G | NoShow | Robert Martin — robert.martin@uat.test |
| H | Confirmed walk-in (à check-in manuellement) | Isabelle Roy — isabelle.roy@uat.test |
| I | Confirmed 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 €
Rate plans
Section intitulée « Rate plans »| Code | Nom | Établissement | Tarif de base |
|---|---|---|---|
BAR | Best Available Rate | Hôtel | 120,00 € / chambre / nuit |
NR | Non Remboursable | Hôtel | 90,00 € / chambre / nuit |
CAMP-BS | Camping Basse Saison | Camping | 15 € unité + 6 € adulte/nuit |
CAMP-HS | Camping Haute Saison | Camping | 22 € unité + 9 € adulte/nuit |
Inventaire hôtel
Section intitulée « Inventaire hôtel »| Code | Nom | Nombre | Format |
|---|---|---|---|
STD | Chambre Standard | 4 | room |
DLX | Chambre Deluxe | 4 | room |
STE | Suite | 2 | room |
Horizon inventaire : J-7 → J+30 (généré au run du seed).
Inventaire camping
Section intitulée « Inventaire camping »| Code | Nom | Nombre | Format |
|---|---|---|---|
EMP | Emplacement nu | 6 | pitch |
MH | Mobil-home 2ch | 4 | mobile_home |
Flux de connexion (JWT + MFA)
Section intitulée « Flux de connexion (JWT + MFA) »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.
POST /sessions— corps :{ email, password }→ réponse{ accessToken, refreshToken }ou{ mfaRequired: true, sessionToken }- Si
mfaRequired: true:POST /sessions/mfa/verify— corps :{ sessionToken, code }→{ accessToken, refreshToken } - Si premier login (enrôlement MFA) : réponse
{ enrollmentRequired: true }→POST /sessions/mfa/enroll/beginavec{ email, password }→{ otpauthUri, secret }→ scanner le QR →POST /sessions/mfa/enroll/confirmavec{ email, password, code }→{ accessToken, refreshToken } - Après login, appeler
GET /v1/mepour récupérer letenantId(data.tenantId) et le persister côté client (nécessaire pourPOST /sessions/refreshqui exige le headerx-tenant-id) - 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).
Collection Bruno
Section intitulée « Collection Bruno »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.