Files
siop2/docs/journal/journal.md
pr-daaif 902efa6192 feat(r2.2): préventif — génération mensuelle idempotente — et compteurs
- migration : Asset.underContract + WorkOrder.periodKey avec unicité
  [assetId, periodKey] — l'idempotence de la génération est EN BASE
  (deux appels concurrents ne doublent jamais une grille)
- génération : une grille par appareil sous contrat, périodicités ancrées
  sur la mise en service (mensuelles toujours dues), premier contrôle
  (toutes les tâches) pour un appareil sans historique, échéance fin de
  mois, événement GENERATED ; déclenchement manuel (cron au durcissement)
- gabarits administrables (désactivé = exclu des générations suivantes) ;
  GET /preventive/status (générées, terminées, en retard, premiers contrôles)
- compteurs : GET meters (2 compteurs, récents d'abord) ; relevé
  strictement croissant, refus motivé sinon
- contrat +7 opérations (48) ; 50 tests verts (94,7 % / 78 %) ; smoke test
  prod : juillet généré (9 grilles, 8 premiers contrôles), 2e appel à zéro

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

26 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) — R2.2 : préventif (génération idempotente) + compteurs

Actions

  • Modèle (migration r2_preventif_compteurs) : Asset.underContract (contrat préventif, maquette fiche appareil) et WorkOrder.periodKey avec unicité [assetId, periodKey] : l'idempotence de la génération est EN BASE, pas seulement dans le code — deux générations concurrentes ne peuvent pas doubler une grille.
  • Génération mensuelle (POST /preventive/generate, 200 idempotent) : une grille par appareil sous contrat ; tâches dues par périodicité ancrée sur la mise en service (mensuelles toujours dues) ; appareil sans historique préventif → OT « Premier contrôle » avec toutes les tâches ; échéance = fin de mois ; événement GENERATED tracé. Déclenchement manuel en R2 (bouton maquette) — l'automatisation cron/BullMQ viendra avec le durcissement production.
  • Gabarits administrables (ajout/renommage/désactivation — un gabarit désactivé sort des générations suivantes) ; GET /preventive/status (générées, terminées, en retard, premiers contrôles du mois).
  • Compteurs : GET /assets/{id}/meters (les 2 compteurs, relevés récents d'abord) ; POST /assets/{id}/meter-readingsrelevé strictement croissant, refus motivé sinon.
  • Contrat : +7 opérations (48). 50 tests verts (couverture 94,7 % / 78 %) : idempotence (8 grilles seed, jamais 16), premier contrôle vs grille normale, mois anniversaire (mars 2031 pour A1 : les 3/6/12 mois tombent ensemble), gabarit désactivé exclu, compteur qui refuse de redescendre. Smoke test prod : juillet 2026 généré (9 grilles, 8 premiers contrôles), 2ᵉ appel à zéro.

Leçon

  • Les specs Jest partagent la base en parallèle : les assertions e2e doivent porter sur leurs propres données (ici les 8 appareils du seed), jamais sur des comptages globaux.

Prochaine étape : R2.3 — écrans web de l'exploitation (liste/fiche OT, demandes+approbation, nouvel OT, préventif, checklist, compteurs, chip urgence + bandeau tableau de bord).


2026-07-16 — Pr. Daaif (+ Claude) — R2.1 : socle backend de l'exploitation

Actions

  • Modèle R2 (doc + migration r2_exploitation, 10 tables) : WorkOrder (référence séquentielle, horodatages par état), WorkOrderEvent (activité), Request (1-1 vers OT, motif de rejet), ReferenceValue (référentiels du bilan par champ), InterventionReport (6 FK nommées), TaskTemplate/ChecklistItem, Meter/MeterReading.
  • Contrat : 15 opérations (41 total) — la table des transitions et les champs requis du bilan vivent dans @siop/shared (une seule loi pour l'API et l'UI) ; la fiche OT expose allowedTransitions et closureBlockers (messages métier).
  • API : machine à états stricte (transition → DONE refusée si bilan incomplet OU checklist avec tâche sans réponse — messages « quoi faire », charte §7) ; approbation de demande = création d'OT lié en 1-1 (double traitement → 409) ; rejet à motif obligatoire ; scoping « voir autre » appliqué aux listes ET aux accès directs (404, pas de fuite) ; valeurs de bilan validées champ par champ.
  • Seed : 31 valeurs de référentiels (6 champs), 8 gabarits de préventif (parachute réglementaire), 4 OT et 4 demandes rejouant la maquette, compteurs d'A1.
  • 45 tests verts (couverture 95 % / 79 % branches) dont la recette officielle rejouée : demande Karim → approbation Salma → OT assigné Ahmed → démarrage → clôture refusée sans bilan → bilan codé → clôture → Karim voit sa demande résolue. Smoke test build prod.

Décisions

  • POST de transition/rejet répondent 200 (le contrat prime sur le défaut 201 de Nest — c'est le contrat qui a raison).
  • La priorité « personne bloquée » trie en tête côté API : aucun client ne peut l'oublier.

Prochaine étape : R2.2 — génération mensuelle du préventif (BullMQ, idempotente, premier contrôle) + API compteurs, puis R2.3 écrans web.


2026-07-16 — Pr. Daaif (+ Claude) — R2 ouverte : maquettes des écrans manquants à valider

Actions

  • R2 « Exploitation » ouverte — design d'abord. Les écrans cœur sont déjà validés depuis R0 (tableau de bord, liste OT, fiche OT avec bilan codé 6 champs et garde de clôture, portail demandeur) ; maquette-r2.html complète avec les 5 écrans manquants : Demandes (file + panneau d'approbation : approuver → OT 1-1, rejeter avec motif requis), Nouvel OT (interrupteur « personne bloquée » explicite), Préventif (gabarits à périodicité — parachute marqué réglementaire — génération du mois idempotente, premiers contrôles), OT préventif (checklist Fait/N-A, clôture bloquée si tâche sans réponse), Compteurs (relevés croissants, historique).
  • Rendu vérifié (5 écrans + thème sombre, zéro erreur).

Décisions (proposées à la validation)

  • Statuts de DEMANDE distincts (Reçue / Approuvée→OT lié / Rejetée / Résolue) réutilisant la sémantique chromatique des statuts OT ; à trancher : est-ce une entorse à « réservés » de la charte ou une extension cohérente ?
  • Un rejet de demande exige un motif (lisible côté portail, sans jargon).
  • Génération mensuelle : automatique le 1ᵉʳ à 06 h + bouton manuel ; regénérer ne crée que le manquant ; appareil sans historique → OT « premier contrôle » (toutes les tâches).
  • Relevé de compteur strictement croissant (refus sinon).

Bloquant : validation des maquettes R2 par le référent avant toute ligne de code R2. → Levé le 16/07/2026 : maquettes R2 et les 4 décisions VALIDÉES par le référent (statuts de demande = extension cohérente, actée). Lancement R2.1 (socle backend exploitation).


2026-07-16 — Pr. Daaif (+ Claude) — 🏁 R1 CLOSE : recettée, déployée, taguée

Actions

  • Recette R1 prononcée par le référent (écrans ↔ maquette-r1, deux thèmes).
  • Déploiement vérifié en ligne (https://siop2.apps.enset.top) : migration r1_referentiel + seed appliqués au boot du conteneur — 5 sites, 8 appareils, écrans /sites servis ; parcours API admin vérifié (locations, assets).
  • DoD complète (recette, CI 6 jobs verts, revue pixel, production, journal) → tag release/r1.

Prochaine étape : R2 Exploitation. Maquettes R0 déjà validées pour tableau de bord, liste OT, fiche OT (bilan codé), portail demandeur ; il restera à maquetter le préventif (gabarits, grille du mois, checklist) avant tout code R2 — design d'abord.


2026-07-16 — Pr. Daaif (+ Claude) — R1.2 : écrans web du référentiel

Actions

  • 7 écrans fidèles à maquette-r1.html : Sites (liste + carte Leaflet/OSM réelle, pins maquette, création en modale avec position posée au clic), Fiche site (arbre site→zones, appareils, ajout de zone), Ascenseurs (table dense, filtres site/statut, strie rouge sur appareil à l'arrêt), Fiche appareil (écran validé R0 : identité, organes ± ajout/retrait, changement de statut, QR réel ; historique R2 et documents R3 annoncés sans simulation), Nouvel ascenseur (identité → rattachement → organes ligne à ligne), Étiquette A6 imprimable (window.print n'imprime qu'elle, objet papier même en sombre), Personnes & équipes (invitation → lien d'activation affiché à copier — pas d'email en R1, décision explicite ; renvoi de lien ; équipes), Catégories (ajout, renommage inline, désactivation).
  • Page /activation (cible du lien d'invitation, moule visuel de la connexion) — la personne choisit son mot de passe et entre directement.
  • Navigation pilotée par la matrice : les entrées livrées n'apparaissent que si canView (Catégories exige SETTINGS) ; boutons de création/édition conditionnés par can() — l'API re-vérifie de toute façon.
  • e2e Playwright : la recette R1 officielle rejouée intégralement (site → zone → appareil+organe → étiquette → invitation → activation du compte → l'invité est connecté) + un parcours « la matrice pilote l'UI » (Technicien : lecture sans boutons) ; purge idempotente des données de test en globalSetup. 5 tests verts, 4 vitest, build prod, lint.

Leçon

  • Paquet workspace CJS + Vite : les exports nommés runtime échouent (pas de pré-bundle des paquets liés) → alias Vite @siop/sharedsource TypeScript ; l'API garde le dist CJS. Symptôme vicieux : app blanche, tests e2e tous rouges.

Prochaine étape : R1.3 — recette R1 avec le référent (revue pixel écrans ↔ maquette-r1), déploiement (CI → Dokploy), tag release/r1. Puis R2 Exploitation (maquettes déjà validées pour OT/demandes/portail).


2026-07-16 — Pr. Daaif (+ Claude) — R1.1 : socle backend du référentiel

Actions

  • Modèle R1 (doc + Prisma + migration r1_referentiel) : Category (kind EQUIPMENT/COMPONENT_TYPE), Location (site → zone, lat/lng + colonne PostGIS générée geography(Point,4326) + index GIST), Asset (statut d'équipement), AssetComponent (organe sans emplacement par construction), Team (m2m User), invitation sur User (token unique + expiration). Migration autosuffisante (CREATE EXTENSION IF NOT EXISTS postgis).
  • Contrat : 21 nouvelles opérations (26 au total) — categories/locations/assets+organes/teams/users/roles/invitations/activate ; générateur OpenAPI étendu aux paramètres de chemin ; spec + client web régénérés dans le même commit.
  • API : 4 nouveaux modules + gestion des personnes, tous sous @RequirePermission (la matrice décide) ; invariants en service : profondeur 2, kinds de catégories, catégorie jamais supprimée, lien d'activation 7 jours à usage unique qui connecte directement.
  • Seed : parc de la maquette (5 sites + 8 zones, 8 appareils dont B2 à l'arrêt et M1 en maintenance, organes d'A1/B2, 9 catégories, 2 équipes).
  • 36 tests verts (couverture 96 % stmts / 85 % branches) : parcours de recette site→zone→appareil→organes, profondeur 3 refusée, matrice vivante (Technicien lit mais ne crée pas), invitation→activation complète (lien périmé/consommé/renvoyé). Smoke test sur build de prod : sites avec compteurs, fiche A1 et ses 4 organes.
  • CI : bascule sur postgis/postgis:18-3.6 (la migration R1 l'exige) — le moment anticipé dans le commentaire du workflow.

Leçons

  • Migration modifiée après application locale ⇒ réaligner son checksum dans _prisma_migrations (ou reset) — d'où la règle : rendre la migration autosuffisante AVANT de l'appliquer.
  • Un serveur reuseExistingServer de Playwright peut squatter :3000 et faire tester un dist périmé — tuer le port avant tout smoke test.

Prochaine étape : R1.2 apps/web — écrans Sites (+ carte Leaflet/OSM), Fiche site, Ascenseurs, Nouvel ascenseur, Étiquette QR, Personnes & équipes, Catégories, fidèles à maquette-r1.html.


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. → Levé le 16/07/2026 : maquettes R1 et les 4 décisions de conception VALIDÉES par le référent. Lancement R1.1 (socle backend).


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.