Files
siop2/CLAUDE.md
pr-daaif dfdf8f7c18 feat(r3.1): socle backend gestion — stock dérivé, BC, coûts figés sur OT
- migration r3_gestion (7 tables) : Partner, Part (SANS colonne de
  quantité), StockMovement (signé, tracé, PU figé), PurchaseOrder/Line,
  LaborTime (taux figé), Document (R3.2) ; User.hourlyRate administrable
- API (66 opérations) : tiers ; pièces (stock = Σ mouvements, alerte sous
  seuil) ; entrée/ajustement (motif requis, stock jamais négatif, en
  transaction) ; BC Brouillon→Envoyé→Reçu (la réception crée les RECEIPT
  et met à jour lastUnitPrice) ; consommation sur OT (stock suffisant,
  PRIX FIGÉ) ; main-d'œuvre (TAUX FIGÉ, refus si taux non défini) ;
  WorkOrderDetail.costs ; coûts verrouillés après clôture (409)
- seed : tiers/pièces/BC/taux de la maquette — OT-0341 = 505 MAD (testé)
- durcissement : références OT/DEM/BC/P par SÉQUENCES Postgres (nextval)
  — fin des courses « max+1 » (500 sporadiques sous charge parallèle) ;
  3 runs Jest complets consécutifs verts
- 55 tests (92 % stmts / 74,9 % branches) dont la recette officielle :
  consommer sous seuil → BC → réception → réappro, prix/taux figés prouvés

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

10 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)

  1. 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.
  2. Playbook vivant : chaque phase du cycle de vie a son dossier docs/0X-*/ (template réutilisable + artefacts réels). Le journal quotidien vit dans docs/journal/jamais dans le livre.
  3. 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.
  4. Déployer tôt : chaque release part sur le serveur de production (Dokploy) dès sa recette.
  5. Le développeur est le premier utilisateur : DEMO_MODE=true active un sélecteur de compte démo (connexion 1 clic sur les comptes seedés, endpoint POST /auth/demo-login strictement 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 main tolé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/api collisionne 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és siop2-).
  • R0.10 apps/api : NestJS + Prisma (migration r0_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 contractdocs/openapi.json committée ; 19 tests Jest verts + smoke test build prod.
  • R0.11 apps/web : React 19 + Vite + Tailwind v4, tokens.css copié 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.ts généré depuis docs/openapi.json et 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 deploy au boot, seed optionnel SEED_ON_START, non-root, healthcheck ; binaryTargets explicites) ; image web (nginx, proxy /api résolu à la requête, fallback SPA, cache assets) ; infra/docker-compose.dokploy.yml (5 services siop2-, seul le web sur dokploy-network) ; runbook docs/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 : secret DOKPLOY_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 sur postgis/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 — écrans web exploitation : liste/fiche OT (transitions via allowedTransitions, garde visible, bilan codé, checklist cliquable, activité), demandes+approbation/rejet motivé, nouvel OT (interrupteur urgence), préventif (tuiles+générer+gabarits), compteurs, tableau de bord réel, urgence traversante (chip topbar, badges, bandeau) ; GET /assets/options (trou Demandeur corrigé) ; retry sur collision de référence dans la génération ; 9 Playwright verts (recette R2 complète), 50 tests API.
  • 🏁 R2 CLOSE (16/07/2026, tag release/r2) : recettée (1 anomalie corrigée en recette : tri « Interventions récentes »), déployée et vérifiée en ligne (portail /q/A1, urgence en tête, préventif de juillet généré).
  • R3 — maquettes validées (16/07) + R3.1 socle backend gestion : migration r3_gestion (Partner, Part sans colonne de quantité, StockMovement signé/tracé/PU figé, PurchaseOrder, LaborTime taux figé, Document, User.hourlyRate) ; 66 opérations ; stock = Σ mouvements (jamais négatif, en transaction), réception BC → RECEIPT + lastUnitPrice, conso/MO à prix/taux FIGÉS, WorkOrderDetail.costs immuable après clôture ; seed maquette (OT-0341 = 505 MAD, testé) ; 55 tests (92 %/74,9 %). Durcissement : références par séquences Postgres (fin des courses max+1).
  • 🔄 R3.2 — reprise ici : bibliothèque de documents (upload multipart 20 Mo → FileStorage.putObject, download streamé par l'API — MinIO jamais exposé, types fermés, rattachement appareil/OT requis) + analytics GET /analytics/summary (coûts/mois, pannes par organe via bilans, taux préventif, top équipements) → R3.3 écrans web (stock, fiche pièce, BC, coûts sur fiche OT, statistiques, tiers, bibliothèque + taux dans Personnes) → recette + déploiement + tag.
  • Détail quotidien : docs/journal/journal.md. Dépôt : siop-spelev/siop2 (privé), jalons R0→R5.