Files
siop2/docs/journal/journal.md
pr-daaif 6d9aafdab4 docs(r1): kickoff design-first — maquettes HD R1 (7 écrans) à valider
- R0 close : tag release/r0 (recette + production en ligne)
- maquette-r1.html dans le moule validé (CSS répliquée, tokens identiques) :
  sites + carte PostGIS, fiche site (hiérarchie d'emplacements), liste
  ascenseurs (statuts d'équipement distincts des statuts OT), création
  (identité → rattachement → organes), étiquette QR imprimable A6,
  personnes & équipes (invitation par lien d'activation), catégories
- rendu vérifié en Chrome headless (7 écrans, bi-thème, zéro erreur)
- BLOQUANT : validation du référent avant tout code applicatif R1

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 12:00:05 +01:00

15 KiB

Journal de bord — SIOP V2

Trace chronologique des sessions (la plus récente en premier). Le playbook (docs/0X-*) est le livre ; ici, c'est le quotidien.


2026-07-16 — Pr. Daaif (+ Claude) — R0 CLOSE (tag) · R1 ouverte : maquettes à valider

Actions

  • R0 close : recette prononcée par le référent, tag release/r0 poussé (DoD complète : CI verte, revue pixel, production en ligne, journal).
  • R1 « Référentiel » ouverte — design d'abord (principe n°1) : maquette-r1.html produite dans le moule validé (CSS répliquée de maquette-web.html, mêmes tokens/typo/motifs) — 7 écrans : Sites (liste + carte PostGIS), Fiche site (hiérarchie d'emplacements), Ascenseurs (liste, statuts d'équipement distincts des statuts OT), Nouvel ascenseur (identité → rattachement → organes), Étiquette QR imprimable (A6 papier, blanche même en thème sombre), Personnes & équipes (invitation par lien d'activation 7 jours, modale montrée), Catégories (référentiels administrables, jamais de suppression si utilisé).
  • Rendu vérifié en Chrome headless : 7 écrans + 2 contrôles thème sombre, zéro erreur.

Décisions (proposées à la validation)

  • Statuts d'équipement (En service / À l'arrêt / En maintenance) distincts des statuts OT ; l'appareil à l'arrêt porte la strie rouge.
  • Un organe n'a jamais d'emplacement propre : il suit son appareil (contrainte en base, comme en v1).
  • Invitation par lien d'activation (7 jours) — aucun mot de passe créé pour autrui ; compte inactif avant activation.
  • Catégorie utilisée : renommage/désactivation seulement, jamais de suppression.

Bloquant : validation des maquettes R1 par le référent avant toute ligne de code applicatif R1.


2026-07-16 — Pr. Daaif (+ Claude) — 🚀 R0 EN PRODUCTION : https://siop2.apps.enset.top

Actions

  • Blocage de clone résolu (le provider « Custom » HTTPS n'avait pas d'identifiants sur dépôt privé) ; déploiement Dokploy réussi depuis GitHub, domaine posé sur siop2-web:80, certificat Let's Encrypt émis.
  • Vérification de l'instance en ligne (commit 3f9d0d8) : /api/healthok (base, Redis, MinIO up) ; 7 comptes démo ; demo-login → /users/me (Salma Idrissi, Dispatcher, 10 lignes de matrice) ; 401 sans jeton ; fallback SPA sur /design ; HTTPS valide.
  • Principe « déployer tôt » honoré : R0 est en ligne avant l'ouverture de R1.

Reste à faire

  • Poser le secret DOKPLOY_WEBHOOK_URL (runbook §4) pour activer le déploiement continu — le job deploy saute proprement tant qu'il manque.
  • Sauvegardes PostgreSQL côté Dokploy (runbook §5) à configurer.
  • Recette R0 avec le référent sur l'instance en ligne (revue pixel écrans ↔ maquettes) → clôture du jalon R0 → ouverture R1 Référentiel.

2026-07-15 — Pr. Daaif (+ Claude) — R0.13 : Dockerfiles + runbook Dokploy

Actions

  • Image API (multi-stage, node:24-slim) : pnpm deploy --legacy --prod, client Prisma régénéré dans l'arborescence déployée, entrypoint prisma migrate deploy → seed optionnel (SEED_ON_START=true, compilé en dist/seed) → API ; utilisateur non-root, HEALTHCHECK /health. prisma passe en dépendance de production (migrations au boot).
  • Image web (nginx:alpine) : statique Vite + proxy /api${API_UPSTREAM} (template envsubst) — même topologie que le proxy Vite de dev ; cache immuable sur /assets, no-cache sur index.html.
  • infra/docker-compose.dokploy.yml : 5 services préfixés siop2-, secrets exigés (:?), profils production client / instance démo documentés dans le fichier ; seul siop2-web rejoint dokploy-network (l'API n'est jamais exposée).
  • Runbook docs/06-production/runbook-dokploy.md : topologie, variables, checklist de première mise en production, releases suivantes, rollback, répétition locale.
  • Répétition locale validée : images construites, conteneurs lancés sur le réseau infra (migrate + seed au boot), parcours complet vérifié à travers nginx conteneurisé (/api/health tout up, demo-login → /users/me, fallback SPA).

Leçons de la répétition (consignées pour le playbook)

  • Prisma en conteneur : binaryTargets explicites dans schema.prisma (debian-openssl-3.0.x x64 serveur + linux-arm64-openssl-3.0.x répétition Mac) — sinon mismatch de moteur au runtime.
  • nginx : upstream résolu à la requête (resolver 127.0.0.11 + variable) et non au boot — sinon nginx refuse de démarrer si l'API n'est pas encore là.
  • Healthcheck alpine : 127.0.0.1 et non localhost (busybox wget tente ::1, nginx écoute en IPv4).
  • Le double verrou ADR-002 a été prouvé en vraie situation : l'image (NODE_ENV=production) avec DEMO_MODE=true sans DEMO_MODE_I_KNOW refuse de démarrer — comportement observé, pas seulement testé.

Décisions

  • Migrations au démarrage du conteneur (idempotentes) : la base suit toujours le code déployé ; un échec de migration arrête l'API sans servir de trafic.
  • Le web est l'unique service exposé (domaine → nginx → proxy interne /api) : mêmes chemins en dev et en prod, surface d'attaque minimale.

Statut : R0.13 prêt — la première exécution réelle attend les accès au serveur du partenaire. Reste pour clore R0 : recette avec le référent (revue pixel écrans ↔ maquettes).


2026-07-15 — Pr. Daaif (+ Claude) — R0.13 (suite) : instance ENSET + déploiement continu

Actions

  • Instance de démonstration décidée : https://siop2.apps.enset.top (Dokploy ENSET, projet compose créé par le référent) — la production client SPELEV suivra la même procédure avec le profil « production client ».
  • Job deploy ajouté au pipeline : appelle le webhook Dokploy sur push main uniquement si lint + contrat + api + web + e2e sont verts ; « skip » explicite tant que le secret DOKPLOY_WEBHOOK_URL n'est pas configuré. L'« Auto Deploy » natif de Dokploy reste désactivé (il ignorerait la CI).
  • Runbook §3 réécrit en checklist concrète (source GitHub, Compose Path, variables du profil démo, domaine → siop2-web:80) et §4 en procédure CD (secret webhook).

Prochaine étape : premier déploiement manuel (runbook §3), pose du secret DOKPLOY_WEBHOOK_URL (§4), vérification https://siop2.apps.enset.top/api/health, puis recette R0 avec le référent sur l'instance en ligne.


2026-07-15 — Pr. Daaif (+ Claude) — R0.12 (2/2) : ESLint + parcours Playwright — R0.12 CLOS

Actions

  • ESLint 10 (flat config unique à la racine, typescript-eslint, react-hooks sur le web) + scripts lint par paquet et job CI dédié. La règle d'architecture ADR-001 est codée : no-restricted-imports interdit minio partout sauf minio-storage.service.ts — violation vérifiée par un fichier-test (détectée puis retiré). Monorepo lint : 0 erreur.
  • Playwright (apps/web/e2e) : 3 tests — redirection sans jeton (fermée par défaut), parcours complet connexion démo → coquille (rail actif, chip DÉMO) → bascule de rôle chronométrée < 3 s (ADR-002) → /design, et déconnexion avec purge de session. webServer démarre l'API construite + Vite ; seed idempotent en globalSetup ; localement PW_CHANNEL=chrome (pas de téléchargement).
  • CI : jobs lint et e2e (services PostgreSQL/Redis, artefact playwright-report en cas d'échec). Vitest restreint à src/ (e2e appartient à Playwright).

Décisions

  • Une seule config ESLint à la racine (pas une par app) : les règles d'architecture sont transversales et la config est le lieu du cours.

Prochaine étape : R0.13 — Dockerfiles (api, web) + runbook Dokploy (docs/04-*), puis recette R0 avec le référent (revue pixel écrans ↔ maquettes).


2026-07-15 — Pr. Daaif (+ Claude) — R0.12 (1/2) : pipeline GitHub Actions

Actions

  • .github/workflows/ci.yml, 3 jobs sur push main + PR : ci-contract (régénère docs/openapi.json + schema.d.ts, échoue au moindre diff — la règle d'or devient bloquante), api (PostgreSQL 18 + Redis en services, prisma migrate deploy, typecheck, Jest avec couverture ≥ 70 % bloquante via coverageThreshold), web (typecheck + vitest + build prod).
  • Test unitaire de PermissionsGuard ajouté (aucune route @RequirePermission en R0 ne l'exerçait) : couverture 97,5 % stmts / 90,7 % branches, 23 tests.
  • Badge CI dans le README ; ci-contract simulé en local (diff propre) avant push.

Décisions

  • CI sur PostgreSQL nu en R0 (la migration r0_identity n'exige aucune extension) ; bascule sur l'image infra/postgres dès que des tests toucheront pgvector/PostGIS (R1+).
  • Pas de MinIO en CI : /health répond degraded sans casser les tests — seul database: up est exigé.

Prochaine étape : R0.12 (2/2) — ESLint (dont la règle « pas d'import MinIO hors FileStorage »), parcours Playwright (connexion démo → coquille → bascule de rôle), puis R0.13 Dockerfiles + runbook Dokploy.


2026-07-15 — Pr. Daaif (+ Claude) — R0.11 : apps/web (connexion + sélecteur démo, coquille, /design)

Actions

  • apps/web (React 19 + Vite + Tailwind v4) : tokens.css copié tel quel depuis 02-design ; classes composants extraites de la maquette validée ; Manrope auto-hébergée (@fontsource) ; primitives shadcn-style possédées (Button/variants cva, menu Radix).
  • Client typé : pnpm generate:clientsrc/api/schema.d.ts généré depuis docs/openapi.json et committé (règle d'or) ; openapi-fetch + injection du jeton.
  • Écrans : connexion (fidèle maquette, liste démo masquée si l'API répond 404 — ADR-002), coquille sidebar (4 groupes, rail safran actif, écrans à venir marqués R1-R3) + topbar (recherche ⌘K, bascule de thème, chip DÉMO, sélecteur de rôle dans le menu compte), /design (référence vivante : nuanciers, typo, boutons, pastilles), tableau de bord R0 minimal.
  • Compléments : tokens --nav-* ajoutés à tokens.css (valeurs issues de la maquette validée) ; seed réaligné sur les personas de la maquette (Salma Idrissi, Ahmed Benali, …) pour des revues pixel cohérentes.
  • Vérifié dans un vrai navigateur (Playwright + Chrome headless) : parcours démo-login → tableau de bord → bascule Dispatcher→Technicien en 101 ms (critère < 3 s) → /design clair & sombre ; 7 captures, zéro erreur console. Typecheck, 3 tests vitest, build prod OK.

Décisions

  • Le web ne lit pas VITE_DEMO_MODE : la présence du mode démo est déduite de la réponse de /auth/demo-accounts (404 ⇒ rien n'est affiché) — une seule source de vérité, l'API.
  • Les entrées de navigation des releases futures restent visibles mais inertes, marquées R1/R2/R3 — le périmètre est annoncé, pas simulé.

Prochaine étape : R0.12 — CI GitHub Actions (lint, typecheck, tests, couverture api ≥ 70 %, ci-contract sur openapi.json/clients, Playwright du parcours démo) puis R0.13 Dockerfiles + runbook Dokploy.


2026-07-15 — Pr. Daaif (+ Claude) — R0.10 : apps/api complète (auth, matrice, démo-login, seed)

Actions

  • packages/shared : vocabulaires (7 rôles, 10 catégories d'objets), schémas Zod (auth, profil, santé) et contrat d'API ; pnpm contract génère docs/openapi.json (committée — règle d'or ADR-001).
  • apps/api (NestJS 11 + Prisma 6) : migration r0_identity (Role/Permission/User) ; guard JWT global fermé par défaut (+ @Public() explicite) ; PermissionsGuard (@RequirePermission, matrice relue en base, cache 60 s) ; FileStorage (seul point d'import MinIO) ; /health (base, Redis, stockage).
  • Démo-login ADR-002 : module enregistré uniquement si DEMO_MODE=true (sinon routes 404), double verrou production (DEMO_MODE_I_KNOW), refus des comptes isDemo=false.
  • Seed idempotent : 7 rôles, matrice complète (70 lignes), 7 comptes démo (mot de passe commun SEED_DEMO_PASSWORD pour la connexion classique).
  • Vérifié bout-en-bout : 19 tests Jest verts (dont e2e démo on/off) ; smoke test sur build de prod — démo-login → /users/me avec matrice, 401 sans jeton, health ok.

Décisions

  • AppModule.forRoot() (module dynamique) pour rendre l'enregistrement conditionnel du module démo testable dans les deux états — le e2e « routes absentes » est l'exigence n°1 de l'ADR-002.
  • Le seed n'écrase jamais une ligne de matrice existante : la base est la source de vérité des droits, le fichier n'est que le point de départ.

Prochaine étape : R0.11 apps/web — login + sélecteur de comptes démo (fidèle à maquette-web.html), coquille sidebar/topbar avec bandeau « DÉMO », page /design, client typé généré depuis docs/openapi.json.


2026-07-15 — Pr. Daaif (+ Claude) — R0 : maquettes VALIDÉES ; architecture + squelette

Actions

  • Maquettes HD validées par le référent → le design est la loi des revues pixel.
  • 03-architecture : ADR-001 (stack), ADR-002 (démo-login DEMO_MODE, double verrou prod), vue C4, modèle de données R0 (Role/Permission/User, isDemo).
  • Racine monorepo (pnpm + turbo, Node 24) ; infra/ : compose local (PostgreSQL 18 pgvector+PostGIS via Dockerfile dédié, Redis, MinIO).

Décisions

  • Convention siop2- pour tous services/conteneurs Docker (référent — collisions sur le réseau partagé Dokploy en v1).

Prochaine étape (reprise) : R0.10 apps/api (auth JWT + matrice permissions + démo-login + seed) → R0.11 apps/web (login + sélecteur démo + coquille + /design) → R0.12 CI → R0.13 prépa Dokploy.


2026-07-15 — Pr. Daaif (+ Claude) — R0 : kickoff, vision, cadrage, design

Actions

  • Refondation décidée : nouveau dépôt siop-spelev/siop2, 100 % nouveau code ; la v1 (siop) est gelée comme référence. Jalons R0→R5 créés.
  • Playbook initialisé : 00-vision (charte projet, personas, benchmark Atlas), 01-cadrage (plan de releases avec DoD, user-story map, exigences non fonctionnelles mesurables, registre des risques).
  • 02-design : charte graphique (bleu-treuil / safran / acier, Manrope, motif « rail »), tokens.css (source de vérité, bi-thème), palettes analytics validées par script (CVD + contraste, modes clair et sombre), maquettes HD navigables (7 écrans : connexion + démo-login, tableau de bord, liste OT, fiche OT avec bilan codé, fiche ascenseur + QR, portail demandeur, mobile technicien) — publiées pour revue.

Décisions (référent, via questions)

  • Diagnostic v1 : esthétique absente, docs éparpillées, périmètre dérivant, bascule de comptes pénible → V2 design-first, playbook en livre, releases fermées, sélecteur de compte démo (DEMO_MODE) dès R0.
  • 100 % nouveau code ; périmètre v1 = web + mobile + IA par paliers ; déploiement Dokploy ; nom conservé : SIOP.

Prochaine étape : validation de la charte + maquettes par le référent (bloquant — aucun code applicatif avant), puis 03-architecture + squelette monorepo.