- 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>
8.9 KiB
SIOP V2 — GMAO ascenseurs (refondation design-first)
Contexte
Projet réel (SPELEV, maintenance d'ascenseurs, Maroc) mené par le Pr. Daaif (ENSET) avec ses étudiants. V2 = refondation de siop-spelev/siop (v1, gelée, référence de lecture seulement) décidée le 15 juillet 2026 : 100 % nouveau code, design en premier, documentation en « playbook » pédagogique. Double objectif : produit complet déployé (web + mobile + IA, Dokploy) et playbook du cycle de vie logiciel (cours ENSET + méthode de la future entreprise du référent).
Langue de travail : français (docs, échanges, commits descriptifs). Code et identifiants en anglais.
Principes non négociables (V2)
- Design-first : aucune ligne de code applicatif avant validation par le référent de la charte graphique, des tokens et des maquettes HD (
docs/02-design/). Chaque release subit une revue « pixel » écrans ↔ maquettes. - Playbook vivant : chaque phase du cycle de vie a son dossier
docs/0X-*/(template réutilisable + artefacts réels). Le journal quotidien vit dansdocs/journal/— jamais dans le livre. - Périmètre fermé par release : R0 Fondations → R1 Référentiel → R2 Exploitation → R3 Gestion → R4 Mobile → R5 IA. On n'ouvre pas Rn+1 avant recette et déploiement de Rn.
- Déployer tôt : chaque release part sur le serveur de production (Dokploy) dès sa recette.
- Le développeur est le premier utilisateur :
DEMO_MODE=trueactive un sélecteur de compte démo (connexion 1 clic sur les comptes seedés, endpointPOST /auth/demo-loginstrictement absent si l'env ne l'active pas). Critère : changer de rôle en < 3 s sans mot de passe.
Stack (ADR-001 — reconduite de v1 car éprouvée, code neuf)
pnpm + Turborepo. apps/api : NestJS, Prisma, PostgreSQL (pgvector + PostGIS), Redis, MinIO derrière l'interface FileStorage (jamais d'import direct du SDK). apps/web : React 19, Vite, TanStack Query/Table, shadcn/ui + Tailwind v4 thématisés par les tokens de docs/02-design/tokens.css, Lucide. apps/mobile : Expo (Expo Go). apps/ai : FastAPI (Python, uv). Règle d'or du contrat : schémas Zod dans packages/shared → OpenAPI committée → clients typés régénérés dans le même commit (CI bloquante).
Conventions
- Journal de bord : toute session se clôt par une entrée en tête de
docs/journal/journal.md(date — auteur — release/tâche ; Actions / Décisions / Prochaine étape). - Mode solo temporaire : commits directs sur
maintolérés ; à l'arrivée des étudiants → PR + CI obligatoires. - Commits conventionnels ; branches courtes
feat/…,fix/…. - Tests écrits avec le code : Jest (api), Vitest (web), jest-expo (mobile), pytest (ai) ; couverture backend ≥ 70 % bloquante ; parcours Playwright par release.
- API fermée par défaut (guard JWT global,
@Public()explicite) ; matrice de permissions en base. - Conformité loi 09-08 : géolocalisation limitée au service, purge des audios, consentements.
- IA : l'IA propose, un humain valide (sauf urgence « personne bloquée ») ; toute réponse RAG cite sa source.
Conventions d'infrastructure
- Docker/Dokploy : tous les services et conteneurs sont préfixés
siop2-(demande du référent, leçon v1 : sur le réseau partagé Dokploy, un service nommépostgres/apicollisionne avec les autres projets).
État d'avancement
- ✅ R0 (1/2) : playbook 00-vision, 01-cadrage, 02-design — charte + tokens + maquettes HD VALIDÉES par le référent le 15/07/2026 (artefact : maquette-web.html ; 7 écrans, bi-thème). 03-architecture rédigé (ADR-001 stack, ADR-002 démo-login, C4, modèle R0). Racine monorepo posée (package.json/pnpm-workspace/turbo/.nvmrc) +
infra/(compose PostgreSQL pgvector+PostGIS, Redis, MinIO — services préfixéssiop2-). - ✅ R0.10
apps/api: NestJS + Prisma (migrationr0_identity), guard JWT global fermé par défaut +@Public(), PermissionsGuard (matrice en base, cache 60 s), démo-login ADR-002 (module conditionnel, 404 sinon, double verrou prod), seed idempotent (7 rôles, 70 lignes de matrice, 7 comptes démo),FileStorage/health ;packages/shared(Zod) +pnpm contract→docs/openapi.jsoncommittée ; 19 tests Jest verts + smoke test build prod. - ✅ R0.11
apps/web: React 19 + Vite + Tailwind v4,tokens.csscopié tel quel + classes extraites de la maquette validée, Manrope auto-hébergée ; connexion + sélecteur démo (masqué si 404 — une seule source de vérité : l'API), coquille sidebar (rail safran, écrans futurs marqués R1-R3) / topbar (thème, chip DÉMO, sélecteur de rôle), page /design ; client typéschema.d.tsgénéré depuisdocs/openapi.jsonet committé ; vérifié en navigateur réel (bascule de rôle 101 ms, bi-thème, 0 erreur console). - ✅ R0.12 — tests + CI (5 jobs verts) :
lint(ESLint 10 flat config racine, règle ADR-001 anti-import MinIO codée et vérifiée),ci-contract(régénération spec+client, diff bloquant),api(PostgreSQL 18 + Redis, migrate deploy, Jest couverture ≥ 70 % bloquante — mesurée 97,5 %),web(typecheck + vitest + build),e2e(Playwright : parcours démo, bascule < 3 s chronométrée, déconnexion). Badge au README. - ✅ R0.13 — Dockerfiles + runbook Dokploy : image api (multi-stage pnpm deploy,
prisma migrate deployau boot, seed optionnelSEED_ON_START, non-root, healthcheck ;binaryTargetsexplicites) ; image web (nginx, proxy/apirésolu à la requête, fallback SPA, cache assets) ;infra/docker-compose.dokploy.yml(5 servicessiop2-, seul le web surdokploy-network) ; runbookdocs/06-production/runbook-dokploy.md. Répétition locale complète validée (migrate+seed au boot, parcours via nginx conteneurisé, double verrou ADR-002 observé). Le déploiement réel attend les accès au serveur du partenaire. - ✅ R0 CLOSE (tag
release/r0) — en production :https://siop2.apps.enset.top(Dokploy ENSET, profil démo, vérifiée en ligne). Restes non bloquants : secretDOKPLOY_WEBHOOK_URL(CD), sauvegardes PostgreSQL Dokploy. Production client SPELEV : attend les accès au serveur du partenaire. - ✅ R1 — maquettes validées (16/07) :
maquette-r1.html, 7 écrans + 4 décisions (statuts d'équipement ≠ statuts OT ; organe sans emplacement par construction ; invitation par lien 7 j ; catégories jamais supprimées si utilisées). - ✅ R1.1 — socle backend : migration
r1_referentiel(Category, Location site→zone + PostGIS générée, Asset, AssetComponent, Team, invitation User), 21 nouvelles opérations au contrat (26 total), 4 modules API + invitations/activation sous@RequirePermission, seed parc maquette (5 sites, 8 appareils, organes, 2 équipes), 36 tests (96 %/85 %), CI surpostgis/postgis:18-3.6. - ✅ R1.2 — écrans web du référentiel : 7 écrans fidèles à maquette-r1.html (Sites + carte Leaflet/OSM, fiche site, ascenseurs, fiche appareil + QR réel, création, étiquette A6 imprimable, personnes & équipes avec lien d'activation à copier, catégories) + page /activation ; navigation et actions pilotées par la matrice (
usePermissions) ; recette R1 rejouée en e2e Playwright (dont activation d'un invité) ; alias Vite@siop/shared→ source TS (leçon CJS/workspace). - 🏁 R1 CLOSE (16/07/2026, tag
release/r1) : recettée par le référent, déployée et vérifiée en ligne (migration + seed au boot, 5 sites / 8 appareils sur l'instance). - ✅ R2 — maquettes validées (16/07) :
maquette-r2.html(demandes/approbation, nouvel OT, préventif, checklist, compteurs) + 4 décisions actées. - ✅ R2.1 — socle backend exploitation : migration
r2_exploitation(10 tables), 15 opérations au contrat (41 total, transitions + champs requis du bilan dans@siop/shared), machine à états stricte avec garde de clôture (bilan 3 champs + checklist), demande→OT 1-1, rejet à motif, scoping « voir autre » (listes + accès directs), seed maquette (31 valeurs de bilan, 8 gabarits, OT/demandes/compteurs), 45 tests (95 %/79 %). - ✅ R2.2 — préventif + compteurs :
underContract+periodKey(unicité[assetId, periodKey]= idempotence EN BASE), génération mensuelle (ancrage mise en service, premier contrôle, gabarits administrables, statut du mois), compteurs strictement croissants ; +7 opérations (48), 50 tests (94,7 %/78 %). Automatisation cron/BullMQ notée pour le durcissement production. - 🔄 R2.3 — reprise ici : écrans web exploitation fidèles aux maquettes (liste OT + filtres + strie urgence, fiche OT : transitions/activité/bilan codé/checklist, demandes + panneau d'approbation, nouvel OT + interrupteur personne bloquée, préventif + bouton générer, compteurs en fiche appareil, chip urgence topbar + bandeau tableau de bord) → e2e Playwright recette R2 → R2.4 portail public QR → recette + déploiement + tag.
- Détail quotidien :
docs/journal/journal.md. Dépôt :siop-spelev/siop2(privé), jalons R0→R5.