Files
siop2/CLAUDE.md
pr-daaif 266ffaaf1b feat(r1.1): socle backend du référentiel — modèle, contrat, API, seed, tests
- migration r1_referentiel : Category (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, invitation sur User ; migration
  autosuffisante (CREATE EXTENSION IF NOT EXISTS postgis)
- contrat : 21 nouvelles opérations (26 total), générateur OpenAPI étendu
  aux paramètres de chemin ; spec + client web régénérés dans ce commit
- API : modules categories/locations/assets/teams + gestion des personnes
  (liste, rôles, invitation lien 7 j à usage unique, activation publique
  qui connecte directement, mise à jour rôle/équipes) — tout sous
  @RequirePermission ; invariants en service (profondeur 2, kinds,
  catégorie jamais supprimée)
- seed : parc de la maquette validée (5 sites + 8 zones, 8 appareils,
  organes A1/B2, 9 catégories, 2 équipes) — idempotent
- 36 tests verts (couverture 96 % stmts / 85 % branches) : recette
  site→zone→appareil→organes, matrice vivante, invitation→activation ;
  smoke test sur build de prod
- CI : postgres → postgis/postgis:18-3.6 (la migration R1 l'exige)

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

7.2 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 — reprise ici : apps/web — écrans Sites (+ carte Leaflet/OSM à intégrer), Fiche site, Ascenseurs, Nouvel ascenseur, Étiquette QR imprimable, Personnes & équipes (invitation + lien à copier), Catégories — fidèles à maquette-r1.html ; puis e2e Playwright du parcours de recette R1 et déploiement.
  • Détail quotidien : docs/journal/journal.md. Dépôt : siop-spelev/siop2 (privé), jalons R0→R5.