# Session Resume — Wakdo **Document de reprise entre sessions de travail.** A consulter en premier quand tu reprends le projet. --- ## Derniere session : 2026-06-19 — Fix borne same-origin + GOAL re-alignement maquette (P5 front) + reste P4 **Auteur : BYAN.** Session marathon. Depart : le user a constate que la borne « n'etait pas cablee » (clic produit sans effet). Diagnostic prouve sur la vraie stack, puis un cycle FD complet (`borne-realign-maquette`, COMPLETED) + un /goal de 8 items livres en autonomie, chacun en PR auto-merge sur CI verte. ### 1. Fix borne same-origin (PR #62) `data.js` faisait des `fetch('/api/*')` RELATIFS -> resolus sur l'origine borne (corentin-wakdo.stark.a3n.fr) ou il n'y a pas d'API -> fallback SPA index.html (HTML, pas JSON) -> catalogue vide. Le middleware CORS de #61 n'etait donc pas sollicite. Decision (secu + conventions) : SAME-ORIGIN. Le vhost kiosk relaie `/api/*` vers PHP-FPM (`ProxyPassMatch` + `ProxyFCGISetEnvIf` qui force SCRIPT_FILENAME sur admin/index.php, sinon FPM rejette via security.limit_extensions). CORS conserve en defense. conventions.md §10 reecrit. ### 2. Decomposition maquette (PR #63) maquette-borne.pdf decompose : 10 ecrans en PNG (docs/design/screens/) + docs/design/ maquette-vs-build.md (mapping maquette<->build : la maquette est mono-ecran avec panneau persistant, le build etait multi-pages). ### 3. GOAL — 8 items livres (PR #64-#71) - #64 L1 : panneau commande persistant + bandeau categories + charte. - #65 L2 : composeur menu SLOT-DRIVEN /api/menus (remplace la compo libre ; ferme dette P4 #3). - #66 L3 : modale options produit (remplace la page product.html ; grille -> modales). - #67 seed : recettes des 53 produits (db/seeds/0003_ingredients_recipes.sql, 50 ingredients) -> stock vivant. - #68 L4 : SOUMISSION REELLE de commande (checkout.js panier->/api/orders create+pay) + ecran chevalet. Avant : checkout 100% simule. - #69 cleanup : memoisation des loaders data.js (promesse) + contraste a11y selection. - #70 orders admin : /admin/orders (order.read) + KPIs vente dans /admin/stats (OrderQueryRepository). - #71 /api/allergens : endpoint public (id/code/name) ; la borne garde son JSON statique (descriptions). Item 0 = gate CI js-tests requis (dev+main). ### Decouvertes corrigees - La borne ne soumettait aucune commande (payment.html simulait) -> soumission reelle cablee. - Migration 0003_order_service_tag.sql non appliquee sur la stack dev (3 j d'uptime) -> la creation de commande echouait (Unknown column service_tag). Reconciliee dans schema_migrations ; doublon de migration ecarte (catch d'une revue adversariale). - Incident compose (reseau recree) : `wakdo-web` recree via `docker compose -f docker-compose.prod.yml up -d --no-deps --force-recreate` (la stack tourne via prod.yml + Traefik reseau `admin_proxy`). ### Verification 351 tests PHP (unit + integration DB) + 64 JS, PHPStan L6 propre. e2e reel : commande K1 creee + payee, stock decremente exactement (-5 Steak hache). Chaque lot a eu une revue adversariale par workflow (must-fix integres). ### Nettoyage git (fin de session) Branches purgees : local + forge = `dev` + `main` seulement (17 branches feature mergees supprimees cote forge, 6 locales). `dev` = `7ab9a5a` (#71). ### EN COURS — accompagnement menu Frite/Potatoes + Maxi (approuve, NON code) Le user a constate que le composeur menu propose les 5 produits frites (Petite/Moyenne/ Grande Frite + Potatoes/Grande Potatoes) comme accompagnement. Regle voulue (et conforme maquette ecran 4 : 2 choix Frites/Potatoes) : - Menu = 2 choix d'accompagnement : Frites (Moyenne Frite) + Potatoes. - Maxi -> version Grande associee automatiquement (Grande Frite / Grande Potatoes). - Petite Frite + tailles individuelles = a la carte seulement (section frites), hors menu. **Approche choisie par le user : variante en base** (data-driven, le stock decremente le bon produit). Plan a executer (TDD + revue + commit/PR/auto-merge) : 1. Migration `db/migrations/0004_product_maxi_variant.sql` : `ALTER TABLE product ADD COLUMN maxi_variant_product_id INT UNSIGNED NULL` + FK -> product(id). A appliquer sur dev. 2. Seed `db/seeds/0004_menu_side_maxi.sql` (idempotent) : - `UPDATE product SET maxi_variant_product_id=24 WHERE name='Moyenne Frite'` (24 = Grande Frite) ; `=26 WHERE name='Potatoes'` (26 = Grande Potatoes). - `DELETE` des options de slot `side` pour ne garder que Moyenne Frite (23) + Potatoes (25) ; retirer Petite Frite (22), Grande Frite (24), Grande Potatoes (26) des options menu. 3. `ProductRepository::find` (src/app/Catalogue/ProductRepository.php:50) : ajouter `maxi_variant_product_id` aux colonnes du SELECT (absent aujourd'hui). 4. `OrderRepository::resolveSelections` (src/app/Order/OrderRepository.php:395) : passer le `format` ; valider la selection BASE contre les options du slot, puis si format='maxi' ET le produit a un maxi_variant non nul -> STOCKER l'id de la variante (label de la variante). `consumption()` decremente alors la Grande variante (stock correct). `resolveLine` (qui connait le format) passe `$format` a `resolveSelections`. 5. Tests : OrderRepository DbTest (menu Maxi + accompagnement -> selection stockee = Grande variante + stock decremente Grande Frite, pas Moyenne) ; unit du swap dans resolveSelections. 6. Borne : le composeur affiche 2 options automatiquement (slots /api/menus restreints par le seed) -> pas de code borne. Afficher le libelle Maxi au recap = optionnel, differable. Ids frites (dev) : Petite 22, Moyenne 23, Grande 24, Potatoes 25, Grande Potatoes 26. ### Reste / a faire - VALIDATION VISUELLE utilisateur sur ecran reel (gros changement front, pas encore vu en vrai). - Differes (LOW, notes) : format menu deduit de supplement_cents (theorique, seed +150) ; multi-slots de meme slot_type (menus famille) ; descriptions allergenes cote schema si on veut basculer la borne sur /api/allergens. - Donnees demo : commande de test K1 en base dev (stock -5, sans impact). ### Reprendre ```bash cd /home/acadenice/corentin_wakdo git checkout dev && git fetch forgejo && git merge --ff-only forgejo/dev git log --oneline -12 dev # #62 fix borne ... #71 allergens docker compose ps # stack dev (prod.yml + Traefik) ``` --- ## Session : 2026-06-18 (suite 2) — P4 read API borne (#60) + cablage CORS/data.js (#61) **Auteur : BYAN.** Deux cycles FD menes en entier (BRAINSTORM -> PRUNE -> DISPATCH -> BUILD -> VALIDATE), chacun livre en PR auto-merge sur CI verte. But : brancher la borne kiosk sur le catalogue en base, a la place des fichiers JSON statiques. ### Livre - **PR #60 — read API catalogue borne** (mergee dans dev, squash `a35db88`) : 5 endpoints publics anonymes en lecture seule (`docs/api/conventions.md` 5.2) : `GET /api/categories`, `/api/products`, `/api/products/{id}`, `/api/menus`, `/api/menus/{id}` (detail avec slots). `CatalogueController` + methodes de lecture filtrees sur Category/Product/MenuRepository (`is_available=1` ET categorie active : la borne ne voit que le commandable, en liste comme en detail). Enveloppe `{data,total}`, champs canoniques snake_case ; `vat_rate` exclu, `is_available` retire des payloads, `is_required` de slot en booleen, sans timestamp. Dispo calculee RG-T21 differee (recettes non seedees). - **PR #61 — cablage borne (CORS + data.js)** (auto-merge arme a la redaction) : - `App\Core\Cors` : middleware CORS scope `/api/`, origine unique et exacte (`CORS_ALLOWED_ORIGIN`, sans joker), `GET/POST/OPTIONS`, header `Content-Type`, sans credentials, fail-closed ; preflight `OPTIONS -> 204` avant le routeur ; decoration de la reponse y compris le 500 du `catch`. `CORS_ALLOWED_ORIGIN` deja cable (`.env.example` + docker-compose). - `data.js` reecrit : consomme `/api/categories|products|menus`, deballe `{data}`, traduit la forme canonique vers la forme borne (`nom/prix/image/type`), regroupe par slug de categorie, glisse les menus sous la cle `menus`. Signatures publiques inchangees -> pages intactes. `loadAllergens` reste statique. ### Revue adversariale (workflow multi-agents, une par cycle) - Read API : 1 finding LOW (lacune de test : slot sans option) -> test ajoute. - Cablage : 2 findings, corriges. - **CRITIQUE** : `findProduct(id)` supposait des ids uniques sur l'ensemble du catalogue (vrai pour l'ancien JSON statique). En base, `product` et `menu` sont deux tables auto-increment distinctes demarrant a 1 -> collision (id 4 = burger Big Mac ET Menu Big Mac), cliquer un burger ouvrait le composeur de menu. Corrige : `findProduct(id, categorySlug)` desambigue par categorie (id unique dans une categorie) ; `page-product.js` passe le slug deja present dans l'URL ; 2 tests de regression. - **LOW** : la reponse 500 du `catch` n'etait pas decoree CORS -> `$request`/`$cors` construits hors du `try` + decoration de la 500. ### Etat tests / CI PHP unit 305 / 859 assertions, integration 40 / 253 (`WAKDO_DB_TESTS=1`, vraie base dev), PHPStan L6 propre ; JS `data.js` 10 tests (node:test, `fetch` mocke). CI Forgejo : merge natif squash sur checks requis (secret-scan, php-lint, static-tests). ### Decisions actees - L'API de lecture parle le dictionnaire (snake_case canonique) ; le rapprochement vers la forme heritee de la borne se fait en un point unique, `data.js` (conventions.md 8.3). - Le composeur de menu reste libre (il ne consomme pas les slots `/api/menus`) pour ce chunk ; sa refonte sur les slots est differee. - Regle de livraison (user) : livrer via commit + PR + auto-merge natif sur CI verte, sans gate manuel a chaque commit (memoire `feedback_commit_discipline`). ### File d'attente (suite) 1. **Verif cross-origin reelle** : le `.env` pointe `CORS_ALLOWED_ORIGIN` sur l'origine serveur. Pour valider borne -> API en local, mettre `CORS_ALLOWED_ORIGIN` sur l'origine du kiosk (`APP_URL_KIOSK`) + recreer `wakdo-app`, puis E2E #45. 2. **Seed des recettes** (`product_ingredient`) -> active le decrement de stock de `pay()` (chunk 1b) ET la dispo calculee RG-T21 dans les endpoints read. 3. **Refonte du composeur de menu** borne pour consommer les slots `/api/menus` (B1 burger impose, B2 Normal/Maxi) au lieu de la composition libre. 4. **Gate CI** : ajouter `CI / js-tests` aux checks requis (sinon un JS rouge pourrait merger). 5. Optionnel : `/api/allergens` (la borne garde son JSON), prix en euros vs centimes. ### Reprendre ```bash cd /home/acadenice/corentin_wakdo git checkout dev && git fetch forgejo && git merge --ff-only forgejo/dev git log --oneline -6 dev # #60 read API + #61 cablage borne docker compose up -d ``` --- ## Session : 2026-06-17 (suite) — P3 Users/RBAC/Stats + Makefile -> docker compose **Auteur : BYAN.** Deuxieme cycle FD du jour (`20260617-102548-p3-users-rbac-stats`, COMPLETED) puis un chore d'infra. P3 back-office desormais complet. ### Livre (dev = 9d75fab) - **Lot S — Stats (#37)** : `StatsController` + `StatsRepository` -> `/admin/stats` (permission `stats.read`). KPIs disponibles : compteurs catalogue + sante stock (bandes RG-T21). **Ferme le 404 du landing manager**. KPIs de vente differes P4. - **Lot U — Users (#38)** : `UserController` + `UserRepository` (mlt domaine 10). CRUD comptes, desactivation, **anonymisation RGPD** (mlt 10.5, tombstone). Chaque mutation = PIN equipier + audit (RG-T13/14), throttle (RG-T22). Garde-fous : pas d'auto-desactivation (403), dernier admin actif protege. Unicite email -> 409. - **Lot R — RBAC (#39)** : `RoleController` + `RoleRepository` (mlt 10.4). Matrice roles x permissions (cases scalaires `perm_`) + roles custom (RG-4) + `role_visible_source`. PIN + audit avec DIFF des permissions (RG-6). Garde admin (garde `role.manage` + reste actif), code immuable, 409 code dupli. - **Chore (#40) — Makefile -> `docker compose up`** : service one-shot `wakdo-migrate` (image mariadb) applique migrations (suivi `schema_migrations`) + seed (suivi `seeds_applied`) idempotents via `db/migrate-container.sh` (connexion reseau) ; `wakdo-app`/`web` attendent sa completion. Makefile supprime. Le « une commande » (Cr 7.c.4) passe de `make init` a `docker compose up`. Cr 7.b porte par les scripts Bash. Docs realignees + correction CI = **Forgejo Actions** (pas GitHub). Detail : `docs/journal/2026-06-17--makefile-to-compose-migrate.md`. - **Chore (#41) — `docker-compose.yml` standalone portable** : le repo ship un compose qui tourne EN LOCAL sans config (`docker compose up -d` -> http://kiosk.localhost:8080 + http://admin.localhost:8080), facon app open-source. Reseau interne seul, `wakdo-web` publie `${HTTP_PORT:-8080}:80`, plus de Traefik dans le fichier versionne, zero commentaire. Renommage `TRAEFIK_DOMAIN_*` -> **`APP_HOST_KIOSK/ADMIN`** (vhosts Apache `ServerName`, *.localhost en local). `.env.example` local-first (valeurs dev qui marchent sans edition). **Prod = `docker-compose.prod.yml` GITIGNORE**, propre a chaque hote (meme stack + Traefik, sans port hote) : `docker compose -f docker-compose.prod.yml up -d`. Valide via `docker compose config` (les deux fichiers) ; smoke-test runtime a faire sur machine propre (container_name fixes -> pas de up parallele a la stack en cours). - **Doc set socle (#42/#43/#44)** : `docs/ARCHITECTURE.md` (10 sections) + `docs/DEVELOPER.md` (#42) ; `docs/adr/` (index + 9 ADR : from-scratch, MVC serveur, stock %, PIN+audit, throttle PIN, 409/422, RGPD anonymise, Makefile->compose, standalone+prod) (#43) ; `docs/domaines/` (index + 7 fiches : auth, catalogue, stock-recettes, users, rbac, stats, borne) (#44). Decoupage en 3 PR par cohesion (squash). A pousser/lire sur la Forge. ### Etat tests / CI unit 263 + integration 301/916 assertions (`WAKDO_DB_TESTS=1`) + 7 tests JS + 2 parcours E2E (borne + admin, Playwright, lance a la main), PHPStan L6, CI Forgejo verte. Branches feature nettoyees (local + remote). ### Fait depuis - **Smoke-test standalone : PASSE** (2026-06-17). Lance dans un projet jetable isole (`-p wakdotest`, override container_name, port 8099) pour ne pas toucher la stack dev 26h : migrate exit 0 (2 mig + 2 seeds, 5 roles/23 perms/admin), borne `kiosk.localhost` HTTP 200 (`Wakdo - Bienvenue`), admin `admin.localhost` HTTP 200 (`Wakdo back-office`), healthz 200. Le renommage `APP_HOST_*` marche au runtime. Projet jetable + volumes/images supprimes ensuite. - **`.env` LOCAL migre** : `TRAEFIK_DOMAIN_*` -> `APP_HOST_*` (memes valeurs FQDN). Le `.env` SERVEUR reste a migrer (idem) avant son prochain deploiement. - **Playwright E2E etape 1 : PASSE** (#45, dev). Parcours borne complet (welcome -> boissons -> produit -> ajout panier -> panier -> paiement -> confirmation), headless en conteneur officiel, contre une stack JETABLE isolee (`tests/e2e/run.sh`). A trouve + corrige un **bug a11y** : `#pay-btn` (un ``) gardait `aria-disabled="true"` car `.disabled` est un no-op sur un `` -> pilote via `aria-disabled` (commit 2b51be3). Detail conteneur : hostnames de test en `.test` (Chromium force `*.localhost`->127.0.0.1). - **Playwright E2E etape 2 : PASSE** (#46, dev). Parcours admin : garde -> login (admin@wakdo.local / mdp dev seede + CSRF) -> /admin/dashboard -> logout. A revele un **probleme secu/usage** : cookie de session `secure=true` en dur -> session intenable en HTTP local -> login admin KO. Corrige en `secure` **conditionnel au HTTPS** (`SessionManager::cookieSecure`, X-Forwarded-Proto ; prod inchange) -> [[ADR-0010]]. Valide : PHPStan L6, 263 unit, 2 E2E verts. ### File d'attente (decidee avec le user) 1. **Deploiement serveur (Thanos)** : migrer le `.env` serveur (`TRAEFIK_DOMAIN_*` -> `APP_HOST_*`, memes valeurs ; `HTTP_PORT` inutile en prod), placer son `docker-compose.prod.yml` (gitignore), back-fill `seeds_applied` avant le 1er up avec `wakdo-migrate` (sinon re-seed -> conflits). Le `.env` local est deja migre. 2. **Playwright E2E — etape 3 (CI)** : etapes 1 (borne) + 2 (admin) FAITES. Reste le job CI Forgejo qui monte la stack jetable + lance Playwright en conteneur (image `mcr.microsoft.com/playwright:v1.49.1-jammy`, doit matcher la devDep). NB : le runner CI doit pouvoir faire du docker-in-docker / acceder au socket (a verifier). 3. **Front : page de LOGIN a retravailler** (demande user : "la page login est moche"). Initiative UI dediee ; ne PAS confondre avec le dashboard admin (qui, lui, va). 4. **Doc set — suite possible** : diagrammes/captures, ou doc commande quand P4 sort. Footgun : branches `docs/*` heurtent le dossier `docs/` dans `forgejo-pr-automerge.sh` (`git log "$HEAD"` ambigu) -> passer le titre en 3e arg. 5. **Reste P4** : domaine commande (KPIs vente, liens nav orders, swap borne->API). ### Reprendre ```bash cd /home/acadenice/corentin_wakdo git checkout dev && git fetch forgejo && git merge --ff-only forgejo/dev docker compose up -d # stack complete en une commande (migrate+seed via wakdo-migrate) ``` --- ## Session : 2026-06-17 — P3 Stock + Recettes + Borne allergenes (cycle FD complet, 4 PR mergees) **Auteur : BYAN.** Cycle FD `20260616-134152-p3-ingredients-stock` mene a terme (reprise a DISPATCH -> BUILD -> VALIDATE). Scope Stock + recettes, etendu en cours a la borne allergenes, livre en 4 PR sequentielles toutes mergees sur `dev` en auto-merge sur CI verte. ### Livre (dev = 1ecd783) - **PR-0 #33 — Harmonisation HTTP 409** : les reponses de CONFLIT (SQLSTATE 23000 : unicite + hard-delete bloque par FK RESTRICT) passent de 422 a 409 sur Category/Product/Menu (aligne le code sur le contrat `byan-api.md`) ; la validation simple reste 422. IngredientController nait directement en 409. - **PR-A #34 — Stock ingredients** : `IngredientRepository` (CRUD, stock %/bande calcules, `restock` tx, `inventoryCount` tx ecrivant une ligne meme a delta=0 RG-3, `movements` borne, `isReferenced`) ; `IngredientController` (CRUD `ingredient.manage` sans PIN ; RESTOCK `stock.manage` sans PIN ; INVENTORY_COUNT `stock.count` + PIN equipier, `pin.failed`+throttle en 1 tx, sans `audit_log` au succes RG-T14 ; movements `stock.read`, user_id visible manager/admin RG-4) ; vues `admin/ingredients/*` + lien nav Stock ; hard-delete bloque -> 409. - **PR-B #35 — Recettes + dispo calculee** : `ProductRepository` (`composition`, `setComposition` delete-and-reinsert tx, `ingredientExists`, `compositionCount`, `autoUnavailableIds`, `isOrderable` RG-T21) ; editeur recette `ProductController::recipeForm/saveRecipe` (`ingredient.manage`, sans PIN) + vue `admin/products/recipe.php` + `product-recipe.js` (vanilla CSP-safe) ; badge "Rupture auto" (RG-T21) dans la liste produits ; **dette #27 fermee** (nb de lignes `product_ingredient` cascade-supprimees trace dans le resume d'audit a la suppression produit). - **PR-C #36 — Borne allergenes** : icone "i" sur carte ET fiche produit ouvrant une modale GENERALE des 14 allergenes INCO (`allergens.js` CSP-safe, `data/allergens.json`, `loadAllergens()` dans `data.js` avec point de swap P4 -> `/api/allergens`). Premier harnais de tests front du depot : node:test + jsdom (`tests/js/`, 7 tests), job CI `js-tests` (Node 20 epingle via NodeSource). ### Decisions actees (2026-06-17) - Inventaire = seule action sensible du domaine stock (RG-T13 liste 9.2, hors 8.8 CRUD et 9.1 restock). Succes -> `stock_movement.user_id`, sans `audit_log` (RG-T14). Echec PIN -> `pin.failed` + throttle dans UNE transaction (RG-T22). - "i" allergenes = info GENERALE (14 INCO), pas un calcul par produit. Mapping `ingredient_allergen` et allergenes calcules par produit restent differes. - Harnais JS : ESM declare LOCALEMENT (`src/public/borne/assets/js/package.json` + `tests/js/package.json`), racine en CommonJS -> hooks `.claude` / `_byan` / `bin` intacts. (Une 1ere tentative `"type":"module"` a la racine cassait les hooks CommonJS -> corrige avant commit.) ### Etat tests / CI 259 tests PHP / 777 assertions (`WAKDO_DB_TESTS=1`), PHPStan L6 propre ; 7 tests JS (node:test + jsdom). CI `dev` verte : secret-scan, php-lint, static-tests, js-tests. ### A faire (suivi) - **Gate CI** : ajouter `CI / js-tests (pull_request)` aux checks REQUIS de la branch protection (`scripts/forgejo-branch-protection.sh`). Au merge de #36 l'auto-merge natif (`merge_when_checks_succeed`) n'a pas attendu `js-tests` (pas encore requis) ; il a valide a posteriori sur `dev` (vert). Sans ce gate, une PR au JS rouge pourrait merger. - **P3 restant** : Users + matrice RBAC ; Stats (ferme le finding `manager.default_route = /admin/stats` 404). - **Differe** : mapping `ingredient_allergen` + allergenes calcules par produit ; decrement atomique RG-T20 + swap borne JSON->API = domaine commande **P4** (debloque liens nav `orders` #23, purge `ORDER_RETENTION` #25). - **Hygiene user** : vars `.env` auth/throttle absentes (l'app tourne sur ses defauts code) ; revoquer anciens PAT GitHub. ### Reprendre ```bash cd /home/acadenice/corentin_wakdo git checkout dev && git fetch forgejo && git merge --ff-only forgejo/dev git log --oneline -6 dev # FD p3-ingredients-stock en phase VALIDATE (a clore en COMPLETED apres validation finale). ``` --- ## Session : 2026-06-16 — Audit "du reel" + 13 PR de remediation + Menus (#32) + demarrage Ingredients/stock ### Vue d'ensemble Session longue, quatre temps : 1. Diagnostic branche `dev` (CI "rouges" + graphe "bizarre"). 2. Audit sur pieces du travail du 2026-06-15 (demande : "du reel, pas le journal") via un sweep multi-agents + verification adversariale -> 13 PR de remediation, toutes mergees. 3. Feature **Menus** construite en cycle FD complet (PR #32, mergee). 4. Demarrage du cycle FD **Ingredients/stock** -> EN PAUSE a la phase DISPATCH. ### 1. Diagnostic dev (resolu, rien de casse) - **"CI pas vertes"** = 8 echecs `auto-merge` cosmetiques (double-fire : un 2e run tente de merger une PR deja mergee -> non-200 ; job non-bloquant) + 3 `static-tests` historiques (PR #9, php-xml/mbstring manquants, corriges le jour meme). `dev` HEAD etait vert. - **"Graphe bizarre"** = refs de suivi locales non prunees (branches squash-mergees, supprimees cote serveur). `git fetch --all --prune` nettoie. Le squash ne cree pas de 2e parent -> moignons rouges (cosmetique). ### 2. Audit + remediation (PR #19-#31, toutes mergees) - **CRITIQUE** : durcissement `php.ini` absent du conteneur en service (image perimee) -> **rebuild `wakdo-app`** (runtime, fait + verifie). - **HIGH** : la CI ne lancait **aucun** test d'integration DB (auto-skip) -> **#21** (service MariaDB + `WAKDO_DB_TESTS=1` + `--fail-on-skipped`). - **MEDIUM** : XSS kiosk innerHTML #20 ; liens nav morts #23 ; user DB `GRANT ALL` -> moindre privilege #24 ; purge RGPD/throttle cron #25. - **LOW** : enum email sur reset #26 ; contrat FK suppression produit #27 ; lien page PIN #28 ; bouton mort `PASSWORD_ALGO` #29 ; atomicite chemin echec PIN #30 ; drift JSON borne #31. - **+** maquettes `.html` non authentifiees retirees #19 ; note d'audit jury `docs/journal/2026-06-16--audit-reel-livrables-p2-p3.md` #22. - **Incident** : `docker compose up -d ` nu a tue le reseau (vars `${...}` absentes du `.env` -> drift) -> recup `down`+`up` sans perte. Memoire `ops-compose-single-service-network` (utiliser `--no-deps --force-recreate`). ### 3. Menus (PR #32, mergee) CRUD menus composes (mlt 8.4-8.6) : burger de base + slots (`menu_slot`/`menu_slot_option`), prix Normal/Maxi. Slots en **vanilla JS** (champ cache `slots_json`, CSP-safe). `delete` = PIN equipier + audit ; `create`/`update` **sans** PIN ; `update` = delete-and-reinsert des slots. Lien nav Menus reactive. Acces : `menu.create/update` admin+manager, `menu.delete` admin seul, `menu.read` tous. ### Etat Git `dev = c2a4854` (toutes les PR #19-#32 mergees ; local == forgejo == github). Working tree propre sur `dev`. Branches feature supprimees au merge. **201 tests verts** (597 assertions avec `WAKDO_DB_TESTS=1`), PHPStan L6 propre, CI verte (avec tests d'integration DB). ### 4. EN COURS : FD Ingredients/stock (PAUSE a DISPATCH) - `fd_id = 20260616-134152-p3-ingredients-stock`, phase **DISPATCH** (voir `byan_fd_status`). - **Scope decide : Stock + recettes**, livre en 2 PR sequentielles : - **PR-A Stock** : `IngredientRepository` (CRUD + calcul stock %/bande + `restock` tx + `inventoryCount` tx + registre `stock_movement` + `isReferenced`) ; `IngredientController` (CRUD `ingredient.manage` ; RESTOCK `stock.manage` ; **INVENTORY_COUNT `stock.count` + PIN** ; mouvements `stock.read`) ; vues `admin/ingredients/{index,form,restock,inventory,movements}` + lien nav Stock ; tests (unit + integration + FakeDatabase). - **PR-B Recettes** : `product_ingredient` (quantite normal/maxi, `is_removable`/`is_addable`, `extra_price_cents`), editeur imbrique facon slots (vanilla JS). **Debloque RG-T21** (dispo produit calculee) + ferme la dette #27 (trace cascade). - **Decisions actees** : inventaire = PIN + trace `stock_movement.user_id` **SANS** `audit_log` (RG-T14 exclut le stock du double-journal) ; soft-delete `is_active`, hard-delete bloque (FK `product_ingredient`/`stock_movement` RESTRICT -> 422). - **Modele** : `ingredient` (`stock_quantity` signe ; `stock_capacity>0` = 100% ; `pack_size` ; `low_stock_pct=10`/`critical_stock_pct=5` avec `critical chunk 1 = `IngredientRepository` + `IngredientRepositoryDbTest` (meme decoupe que Menus, chaque chunk verifie). ### A faire (apres le stock) - **P3 restant** : Users + matrice RBAC ; Stats (ferme le finding `manager.default_route = /admin/stats` 404). - **Differe** : allergenes `ingredient_allergen` ; affichage dispo calculee RG-T21 (vient avec PR-B) ; domaine commande **P4** (debloque les liens nav `orders` #23, la purge `ORDER_RETENTION` #25). - **Hygiene cote user** : les vars auth/throttle (`ARGON2_*`, `ACCOUNT_LOCKOUT_*`, `PIN_THROTTLE_*`, ...) sont absentes du `.env` reel (l'app tourne sur ses defauts code) ; revoquer les anciens PAT GitHub. ### Reprendre ```bash cd /home/acadenice/corentin_wakdo git checkout dev && git fetch forgejo && git merge --ff-only forgejo/dev git log --oneline -6 dev # FD en cours : phase DISPATCH. Dire "go PR-A" pour reprendre le build (IngredientRepository). ``` --- ## Session : 2026-06-15 (suite 5) — P3 : throttle PIN (RG-T22, #18) merge ### Vue d'ensemble Fermeture du finding HIGH de la revue Produits (PIN d'action sensible sans limitation de tentatives). Conception via un panel multi-agents (3 lentilles Ockham / efficacite-menace / anti-DoS -> synthese -> passe adversariale, `holds = true`), construction en TDD avec les correctifs de l'adversaire integres, revue adversariale de l'implementation (`holds = true`), puis merge sur `dev` en auto-merge (PR #18). **Resume de session detaille (format jury RNCP) : `docs/journal/2026-06-15--p3-throttle-pin-rg-t22.md`.** ### Decision actee Compter les echecs de PIN **par utilisateur AGISSANT** (`$guard->userId`), pas par email cible (contournable par rotation) ni par IP (collateral sur poste a session partagee). Table dediee `pin_throttle` (entite 22) cle sur `actor_user_id` (FK ON DELETE CASCADE), separee des compteurs de connexion : un echec de PIN n'incremente aucun compteur de login (pas d'escalade DoS). Bornes propres (PIN_THROTTLE_*, base 30s / plafond 300s, plus permissives que le login : controle de dissuasion). ### Ce qui a ete livre (merge ; PR #18 ; dev = ad5203d) - `App\Auth\PinThrottle` (isLocked / recordFailure upsert atomique + backoff / reset), dimension `'pin'` de `ThrottlePolicy`, `PinVerifier::payTimingDecoy` (parite de timing), cablage `ProductController` update/destroy (gate avant verification, pas de `pin.failed` sous verrou actif = anti-flood, reset sur l'acteur de session). - Migration `0002_pin_throttle.sql` (appliquee a la base dev) ; docs Merise 21 -> 22 entites (RG-T22) ; `.env.example` + `docker-compose.yml` (PIN_THROTTLE_*). - 188 tests verts (525 assertions), PHPStan L6 propre. Branche supprimee (local + remote). ### Etat Git ``` dev ad5203d (auth #11 ... produits #17 + throttle PIN #18 ; local == forgejo == github) Hors-scope untracked : package*.json, SESSION_RESUME.md, journal P1 2026-06-04. ``` ### A faire a la reprise - Suite P3 : Menus (+ slots), Ingredients/stock, Users + matrice RBAC, Stats. - Differe : etendre le cron de purge a `pin_throttle` (predicat dans `mlt.md` 13.5) ; alerte de volume `pin.failed` cote supervision ; seed ingredients/recettes ; revoquer anciens PAT GitHub. ### Reprendre ```bash cd /home/acadenice/corentin_wakdo git checkout dev && git fetch forgejo dev && git merge --ff-only forgejo/dev git log --oneline -8 dev ``` --- ## Session : 2026-06-15 (suite 4) — P3 : CRUD Produits (#17) ### Vue d'ensemble Suite directe de la session P3. Le CRUD Produits est livre et merge (PR #17, squash sur `dev`), memes patterns que Categories : `App\Catalogue\ProductRepository` sur `DatabaseInterface`, `ProductController` non-`final`, double `FakeDatabase`, tests unit + integration auto-skippee, revue adversariale par chunk. C'est le **premier usage reel du PIN d'action sensible** (RG-T13) sur des mutations metier, avec ecriture `audit_log` dans la meme transaction (RG-T08 / RG-T14). ### CRUD Produits (merge ; PR #17 ; dev = 2756fb4) - `App\Catalogue\ProductRepository` (DatabaseInterface) : all/find/create/update/delete + `categoryExists`, allowlist de colonnes a l'ecriture (RG-T16). - `ProductController` (index/create/store/edit/update/confirmDelete/destroy) : chaque action `guard('product.manage')` (RG-T03), mutations CSRF (RG-T01), validation serveur bornee (RG-T18 : categorie existante, nom <=120, prix > 0 et <= UINT32, TVA dans {55,100}, image <=255, display_order 0..65535). - **PIN conditionnel (8.2 RG-4)** : a l'update, le PIN equipier est exige uniquement si `price_cents` OU `vat_rate` change (les deux sont fiscalement sensibles : sur_place 10% vs a_emporter 5.5%) ; sinon write simple sans PIN. A la suppression, le PIN est exige dans tous les cas. - **Modele PIN = identifiant equipier + PIN** : `PinVerifier::resolveActingUser(email, pin)` (ajoute ce chunk) resout l'identite de l'equipier qui valide (SELECT filtre `is_active = 1`), et c'est cet `acting_user_id` (pas l'utilisateur de session) qui est ecrit dans `audit_log` (RG-T14), dans la MEME transaction que la mutation (RG-T08). - **Suppression FK-safe** : hard delete seulement si le produit n'est pas reference (order_item / menu.burger_product_id, FK RESTRICT) ; sinon `PDOException` SQLSTATE 23000 traduit en 422. - Vues `admin/products/{index,form,delete}`, ajout des routes dans `src/public/admin/index.php`. - 172 tests verts (452 assertions), PHPStan L6 propre. ### Revue : 6 findings confirmes (0 refute) - **HIGH — PIN d'action sensible sans limitation de tentatives.** `PinVerifier` verifie avec parite de timing (leurre argon2id) mais sans compteur ni backoff : un insider tenant deja `product.manage` peut iterer les PIN (4 chiffres = 10^4) contre l'email d'un collegue et forger l'`acting_user_id` de l'audit. Le login a son `login_throttle` (RG-8) ; le PIN n'a pas d'equivalent. **Mitigation shippee dans ce chunk** : chaque PIN refuse ecrit un `audit_log` `pin.failed` (acteur NULL, cible, email tente) -> la tentative devient detectable et alertable. Le throttle PIN degressif complet reste a faire (chunk dedie, cf. plus bas). - **LOW — case `is_available`** : sur re-rendu d'erreur, une case decochee revenait cochee (fallback `?? 1` applique aussi au re-rendu). Corrige : la valeur ne retombe sur le defaut que pour le formulaire de creation, le re-rendu reflete l'etat soumis. - **4 MEDIUM = lacunes de couverture / resistance aux mutations** (le code de prod etait correct, les correctifs durcissent les tests) : - chemin TVA-only (vat 55) non teste -> ajout `testUpdateVatChangeRequiresPin` + `...WithValidPinAudits`. - route `resolveActingUser` du `FakeDatabase` ne forcait pas `is_active = 1` (un mutant retirant le predicat passait) -> route durcie + assertion SQL. - test de suppression n'assertait pas que l'acteur audit = l'equipier resolu -> assertions actor (uid === 9, rid === 4) ajoutees sur update et destroy. - `FakeDatabase` ne prouvait pas que l'INSERT `audit_log` tombe ENTRE begin et commit (deux listes disjointes) -> ajout d'un `eventLog` entrelace + assertions d'ordre (begin < audit < commit). ### Etat Git (post-chunk) ``` dev 2756fb4 (auth #11 + RBAC #12 + PIN #13 + shell #14 + categories #15 + set-PIN #16 + produits #17 ; == forgejo/dev) Branche feat/p3-products-crud supprimee (remote auto-merge + local). 172 tests, PHPStan L6 propre. Hors-scope untracked : package*.json, SESSION_RESUME.md, journal P1. ``` ### A faire a la reprise — d'abord le throttle PIN (chunk dedie), AVANT Menus / Stock - **Throttle PIN d'action sensible (chunk dedie, prioritaire)** : fermer le finding HIGH. Decision de schema a trancher d'abord : ne PAS reutiliser les colonnes `user.failed_login_attempts` / `lockout_until` du login (un attaquant qui spamme le PIN d'une victime verrouillerait son LOGIN = DoS sur la victime). Pistes : compteur PIN dedie (colonnes `pin_failed_attempts` / `pin_lockout_until` sur `user`, OU table `pin_throttle`), dimension per-user ET per-IP (comme RG-8), reponse generique (ne pas reveler quels emails existent), reset sur succes. Reutilise `ThrottlePolicy`. Ajouter une RG Merise dediee + migration + tests. La mitigation `pin.failed` reste en place entre-temps. - Ensuite : Menus (+ slots), Ingredients/stock, Users + matrice RBAC, Stats. - Differe : seed ingredients/recettes ; revoquer anciens PAT GitHub. ### Reprendre ```bash cd /home/acadenice/corentin_wakdo git checkout dev && git fetch forgejo dev && git merge --ff-only forgejo/dev git log --oneline -7 dev ``` --- ## Session : 2026-06-15 (suite 3) — P3 : shell (#14) + CRUD Categories (#15) + set-PIN (#16) ### Vue d'ensemble P3 (CRUD admin) demarre. Architecture tranchee : **pages rendues serveur (PHP MVC)**, pas d'API JSON pour le back-office (coherent avec l'auth, demontre le MVC). Routes back-office sous `/admin/...` (le seed fixe `role.default_route` a `/admin/dashboard`, `/admin/stats`, etc.). Deux chunks merges, memes patterns que P2 (services/repos sur `DatabaseInterface`, controleurs non-`final`, `FakeDatabase`, tests unit + integration auto-skippee, revue adversariale par chunk). ### Shell admin (merge ; PR #14) - `Controller` gagne un hook `layoutName()` (defaut inchange) ; le back-office rend dans `admin/layout`. - `AdminController` (base) : `guard(permission?)` = RG-6/RG-T02 (302 `/login` si session KO) puis RG-T03 (403 si permission manquante), sinon `GuardResult` ; `adminView()` injecte identite + permissions + CSRF + flash ; helpers `setFlash`/`takeFlash`. - `DashboardController` -> `GET /admin/dashboard` ; `UserDirectory` (nom + libelle role topbar). - Vues `admin/{layout,dashboard,forbidden}` : nav conditionnee aux permissions, logout POST CSRF, sorties echappees (RG-T15). Premier cablage reel du `SessionGuard` sur une page. - Revue : 5 findings corriges (initiales multibyte, couverture 403, test d'echappement, marqueur de fragment, commentaire d'heritage). ### CRUD Categories (merge ; PR #15) — pattern de reference - `App\Catalogue\CategoryRepository` : couche d'acces des entites CRUD (all/find/create/update/ setActive/nameExists/slugExists), testable via `DatabaseInterface`. - `CategoryController` (index/create/store/edit/update/toggle) : chaque action `guard('category.manage')` (RG-T03), mutations CSRF (RG-T01) + validation serveur (RG-T18 : requis/format/bornes/unicite, display_order 0..65535) + allowlist de colonnes (RG-T16). Pas de suppression dure (FK RESTRICT) : bascule `is_active`. Violation d'unicite concurrente traduite en 422. Flash apres redirection. - Vues `admin/categories/{index,form}` + `admin/not_found`. Revue : 6 findings corriges (borne display_order, violation unique -> 422, +4 tests de regression). ### Set-PIN self-service (merge ; PR #16) - `ProfileController` -> `GET/POST /admin/profile/pin` : l'utilisateur connecte definit/change SON propre PIN (cible = `guard.userId` de session, pas un champ de form -> pas d'IDOR). CSRF + validation serveur (numerique + bornes via `meetsLengthPolicy`, confirmation). Hash argon2id. Ecriture gardee sur 1 ligne affectee (pas de faux succes). `UserRepository` : `setPinHash`/`pinIsSet`. - **Decision PIN actee** : modele **identifiant equipier + PIN** pour les actions sensibles (attribution individuelle). `PinVerifier::resolveActingUser(email, pin)` reste a ajouter en chunk Produits. - E2E : l'**admin a un PIN dev = `4729`** en base (pose via la page), ce qui debloque le gate Produits. - Revue : 3 findings corriges (fallback `?? 0` retire, gate ligne affectee, assertion cible = session). ### Etat Git (post-chunks) ``` dev f63ac98 (auth #11 + RBAC #12 + PIN #13 + shell #14 + categories #15 + set-PIN #16 ; == forgejo/dev) 152 tests (unit + integration DB auto-skippee), PHPStan L6 propre. Branches feature supprimees. Hors-scope untracked : package*.json, SESSION_RESUME.md, journal P1. ``` ### Pattern CRUD admin (a reutiliser pour produits/menus/users) 1. `App\Catalogue\Repository` (DatabaseInterface) : requetes preparees, unicite. 2. `Controller extends AdminController` : par action -> `guard()` -> (mutation : `Csrf::validate`) -> validation serveur + allowlist -> repo -> redirect + `setFlash`, ou re-rendu 422. 3. Vues `admin//{index,form}` rendues dans le shell ; tout texte echappe. 4. Actions sensibles (RG-T13) -> `PinVerifier` + `audit_log` (RG-T14) dans la meme transaction. 5. Pas de suppression dure si FK RESTRICT -> desactivation. 6. Tests : controleur (double via hooks), repository (integration DB auto-skippee). ### A faire a la reprise - **CRUD Produits (chunk en cours)** : cas riche (price_cents, vat_rate {55,100}, category_id FK, is_available, image, display_order). **Premier usage reel de `PinVerifier`** : PIN exige uniquement si prix/TVA change (8.2 RG-4) et a la suppression (8.3), modele **identifiant equipier + PIN** via `PinVerifier::resolveActingUser(email, pin)` (a ajouter) -> `acting_user_id` ecrit dans `audit_log` dans la meme transaction (RG-T14). Suppression dure seulement si non reference (FK RESTRICT depuis order_item / menu.burger_product_id) sinon 422. Reutilise les bornes d'entiers durcies (revue categories). - Ensuite : Menus (+ slots), Ingredients/stock, Users + matrice RBAC, Stats. - Differe : seed ingredients/recettes ; revoquer anciens PAT GitHub. --- ## Session : 2026-06-15 (suite 2) — RBAC P2 (PR #12) + moteur PIN (PR #13), tous deux merges ### Vue d'ensemble Poursuite directe de la session auth. RBAC livre et merge (PR #12), puis moteur PIN d'action sensible construit (commit/PR en attente apres revue). Memes patterns que l'auth : services dependant de `DatabaseInterface`, controleurs non-`final` pour le seam de test, double `FakeDatabase`, tests unit + integration auto-skippee, revue adversariale par panel. ### RBAC (merge ; dev = f979a23 ; PR #12) - `Authorizer` : `can(role_id, code)` / `permissionsFor(role_id)` / `roleCode(role_id)` ; verifie une PERMISSION (RG-T03), rechargee depuis la base a chaque appel (10.4 RG-3) ; un role `is_active = 0` ne confere rien. - `AuthenticatedController` (dans `App\Controllers`, pas le Core, pour ne pas inverser la dependance) : cable `SessionGuard` (RG-6/RG-T02) + `Authorizer`. - `MeController` -> `GET /api/me` : `401 AUTH_REQUIRED` si session absente/expiree/inactive, sinon identite + permissions. **Premier consommateur reel du `SessionGuard`** (enfin cable). - Revue : 3 findings corriges (`roleCode` ne filtrait pas `is_active` ; couverture du predicat `is_active` via `FakeDatabase.roleActive` + un test d'integration `AuthorizerDbTest` contre le vrai schema ; assertions de liaison par code de permission). 1 refute (le `SessionGuard` ne relit pas `role_id` en cours de session = by-design 10.4 RG-3 : la session stocke `role_id`, seules les permissions se rechargent). ### PIN (merge ; PR #13) - `PinVerifier` : `verify(user_id, pin)` contre `user.pin_hash` (argon2id, default-deny, filtre `is_active = 1`) ; `meetsLengthPolicy` (chiffres ASCII, bornes min/max `STAFF_PIN_MIN/MAX_LENGTH`, RG-T18). Primitif RG-T13 reutilise par chaque operation sensible en P3. - 119 tests verts (unit + integration, dont la garde du filtre `is_active` contre le vrai schema), PHPStan L6 propre. - Revue : 3 findings corriges (decoy argon2id sur le chemin sans PIN pour egaliser le timing ; politique de longueur durcie `ctype_digit` + max ; couverture du filtre `is_active`). 2 refutes (throttle PIN = concern orchestrateur P3 ; cast `(string)` redondant inoffensif). - Perimetre P2 = le primitif seul. Les operations sensibles gardees (annulation, prix/TVA, suppressions, correction d'inventaire, gestion user/RBAC, effacement PII), la definition d'un PIN (set/change) et le cablage PIN + `audit_log` dans la meme transaction sont P3 (flux deja specifie dans `docs/uml/security-sequence.md` pour CANCEL_ORDER). ### Etat Git ``` dev 7c35f8e (auth PR #11 + RBAC PR #12 + PIN PR #13 ; == forgejo/dev ; push-mirror -> GitHub) Branches feature supprimees (remote auto-merge + local). Working tree sur dev, propre. Hors-scope untracked : package*.json, SESSION_RESUME.md, journal P1 ``` ### A faire a la reprise - **P3 CRUD admin** : les pages admin deviennent des vues rendues serveur passant par `AuthenticatedController`. Chaque operation cable alors `SessionGuard` + `Authorizer::can(permission)` + `PinVerifier` (actions sensibles) + ecriture `audit_log` dans la meme transaction (RG-T08/RG-T14). C'est en P3 que `SessionGuard` / `Authorizer` / `PinVerifier` sont reellement appliques aux operations, et que les pages statiques (`.html` servies par Apache) deviennent protegeables. - **Modele d'attribution PIN sur poste partage** a trancher en P3 : PIN seul (identifie l'individu) vs identifiant equipier + PIN. Le primitif `verify(user_id, pin)` supporte les deux. - Differe : seed ingredients/recettes ; revoquer les anciens PAT GitHub. --- ## Session : 2026-06-15 (suite) — P2 Auth back-office mergee (PR #11) + doc API + convention snake_case ### Vue d'ensemble Livraison de la couche **authentification back-office** (P2), conçue via un panel de design (3 architectes : testabilite / securite / simplicite) puis durcie par une revue adversariale (6 findings confirmes corriges). Mergee sur `dev` en auto-merge sur CI verte (PR #11, squash = `1b0b20c`). En bonus : doc API et arbitrage de la convention de nommage. ### Ce qui a ete fait - **Prerequis compose** : `ARGON2_*`, `ACCOUNT_LOCKOUT_*`, `IP_THROTTLE_*`, `STAFF_PIN_MIN_LENGTH`, `PASSWORD_RESET_TTL` passes au conteneur `wakdo-app` (deja dans `.env.example`). - **Core etendu (additif)** : `Request::formBody()` (POST urlencode) + `Request::clientIp()` (IP reelle = dernier hop `X-Forwarded-For` derriere Traefik, validee, repli `REMOTE_ADDR`) ; `Database::transaction(callable): void` (atomicite RG-T08) + `DatabaseInterface` (seam de test) ; accesseurs lecture `Response` (`body`/`header`/`headers`). - **Domaine `App\Auth`** : `AuthService` (12.1 login + 12.2 logout), `PasswordResetService` (12.3), `SessionGuard` (RG-6 + RG-T02 — **ecrit et teste mais PAS encore cable** : c'est le travail RBAC), `ThrottlePolicy` (backoff degressif), `PasswordHasher` (argon2id + leurre de timing en cache statique process), `Csrf` (synchroniseur + rotation), `SessionManager` (seul a toucher `$_SESSION`/cookie, mode test memoire), `Mailer`/`LogMailer` (lien reset journalise, pas de SMTP en P2), `AuthResult`/`GuardResult`. - **Controllers + vues + routes** : `AuthController` + `PasswordResetController` (non-`final` pour le seam de test), vues serveur `auth/{login,forgot,reset}.php` (CSRF cache, `htmlspecialchars`), 7 routes sur le vhost admin (`/login`, `/logout`, `/forgot_password`, `/reset_password`, ...). - **Tests** : 98 verts (unit sans DB + integration DB auto-skippee). PHPStan L6 propre. - **Doc API** : `docs/api/conventions.md` (conventions + listing des endpoints, en service + projete). ### Decisions actees - **Login = vue PHP rendue serveur** (form POST + 302 vers `role.default_route`), pas une API JSON : le back-office est du MVC serveur. - **Convention de nommage des URL = minuscule + snake_case** (apres challenge utilisateur + fact-check : le minuscule est source RFC 3986, aucun standard n'impose `-` vs `_`, la coherence avec la DB et les champs JSON tranche pour `_`). Routes : `/forgot_password`, `/reset_password` ; `/api/` au pluriel snake (`/api/order_items`). Les champs JSON suivent le dictionnaire (snake_case). - **Bug attrape en E2E** : `PDO::ATTR_EMULATE_PREPARES = false` interdit de lier un meme placeholder nomme plusieurs fois dans une requete -> placeholders distincts. - **Corrections de revue** : parite du profil d'ecritures sur email inconnu (`UPDATE` no-op sur `id = 0`, anti-enumeration) ; increment du compteur IP `login_throttle` rendu atomique cote SQL (anti lost-update) ; leurre argon2id mis en cache statique (parite de timing sans surcout par requete). ### Boucle de verification locale (pas de PHP sur l'hote) ```bash # unit + analyse (image PHP du projet, conteneur jetable) : docker run --rm -v "$PWD":/app -w /app wakdo-wakdo-app php phpunit.phar -c phpunit.xml docker run --rm -v "$PWD":/app -w /app wakdo-wakdo-app php -d memory_limit=-1 phpstan.phar analyse --no-progress --error-format=raw # integration DB (auto-skip sans le flag) : docker run --rm --network wakdo_wakdo_internal --env-file .env -e WAKDO_DB_TESTS=1 -v "$PWD":/app -w /app wakdo-wakdo-app php phpunit.phar -c phpunit.xml ``` Les `*.phar` (phpunit 11.5.2 / phpstan 1.12.27) sont gitignores ; les telecharger si absents. ### Etat Git (post-session) ``` dev 1b0b20c (P2 auth merge, == forgejo/dev ; push-mirror -> GitHub auto) feat/p2-auth : supprimee cote remote par l'auto-merge ; branche locale stale (supprimable) Working tree : hors-scope habituels untracked (package*.json, SESSION_RESUME, journal P1) ``` ### A faire a la reprise — RBAC (demarre juste apres cette mise a jour) - **Service d'autorisation** : `can(role_id, permission_code)` via `role_permission` JOIN `permission`, recharge depuis la DB a chaque verification (mct/mlt 10.4 RG-3 ; la session ne stocke que `role_id`). Verifie une **permission**, pas un nom de role (RG-T03). - **Cabler `SessionGuard::check()`** en tete des routes protegees (idle/absolu/`is_active`), avec redirection vers `/login` si invalide. En P2 il n'y a pas encore de route protegee : on en cree une reelle pour brancher et tester la chaine (ex. `/` devient le landing authentifie, et/ou `/api/me`). - **PIN actions sensibles** (RG-T13) sur le sous-ensemble sensible : annulation, prix/TVA, RBAC, gestion utilisateur, correction d'inventaire (cf. `docs/uml/security-sequence.md`). - S'appuie sur le seed (5 roles + 23 permissions + matrice deja en base). --- ## Session : 2026-06-15 (P1 conception finie + traduction FR + P2 demarre : DB + seed + Core) ### Vue d'ensemble Session marathon, trois phases : 1. **Pivot security-by-design boucle (A->G)** : threat model, infra/config secu, CI/CD Forgejo Actions, diagrammes MCD + MLD. **P1 conception terminee.** 2. **Traduction FR** de la prose des 5 docs Merise (identifiants/code inchanges), via 2 workflows. Convention projet : **FR ASCII (sans accents)**. 3. **P2 demarre (le code !)** : DDL 21 tables + runners migrations/seed, seed data, Core PHP from-scratch (squelette MVC, namespace `App\` -> `src/app/`). Tout merge sur `dev`, identique Forgejo == GitHub. ### P2 back squelette (en cours, deja merge sur dev) - **DB foundation** (PR #6) : `db/migrations/0001_init_schema.sql` (21 tables, verifie executable sur MariaDB reel), `db/migrate.sh` + `db/seed.sh` (idempotents), `make migrate`/`make seed` cables. - **Seed** (PR #8) : 5 roles + 23 permissions + matrice (manager = `user.read` lecture seule) + 14 allergenes INCO + 1 admin (argon2id, `admin@wakdo.local` / `WakdoAdmin2026!` dev) + catalogue (9 cat / 53 produits / 13 menus + composition). **Differe** : ingredients/recettes (couche stock, P3). - **Core PHP** (PR #9 + #10) : `src/app/{Core,Controllers,Views}` (App\ -> src/app), front controller `src/public/admin/index.php`. Autoloader PSR-4, Config getenv, Database PDO (prepared, lazy), Router, HealthController (`GET /api/health` -> DB reelle, categories:9). PHPUnit (.phar) + PHPStan L6, sans Composer. ### Ce qui a ete fait (lots du pivot SbD) - **A** threat model STRIDE + classification 4 niveaux (`PROJECT_CONTEXT SS19` + `security-sequence.md`). - **B** `PROJECT_CONTEXT` : drift GitHub->Forgejo Actions corrige, couche secu integree, planning rechiffre (P0 22 / P1 38 / P7 22 ; **total 272h**), decision #16 SbD. - **C** infra/config : `.env.example` (argon2id/lockout/throttle IP+compte/retention RGPD), `php.ini` durci (allow_url_*off, cgi.fix_pathinfo=0, IDs session, disable_functions RCE), `.gitleaks.toml`, `scripts/forgejo-branch-protection.sh`, doc runner. **act_runner enregistre**. - **D** `SECURITY.md`, checklist secu dans PR template, **`.forgejo/workflows/ci.yml`** (secret-scan gitleaks + php-lint + static-tests PHPStan/PHPUnit *gardes* jusqu'a P2), `scripts/forgejo-pr-automerge.sh`. Auto-merge **teste et valide** (PR #2, #3, #4). - **E** diagrammes MCD : 4 sous-domaines en Mermaid + SVG (`mcd-{catalogue,ingredients-stock,order,rbac}`), vieux `.drawio` v0.1 supprimes, `mcd.md` SS3/SS11 reecrites. - **F** PR #3 `feat/p1-conception -> dev` **auto-mergee sur CI verte** (squash), branche supprimee. - **G** **push-mirror Forgejo->GitHub** configure+teste (sync auto a chaque commit) ; historique git verifie **sans secret** (gitleaks + scan manuel). Reste cote user : revoquer anciens PAT GitHub (Session 6). - **+** diagrammes **MLD** : 4 sous-domaines relationnels (Mermaid+SVG, `mld-*`), PR #4 auto-mergee. ### Etat Git (post-session) — tout aligne local == Forgejo == GitHub ``` main 5104040 (derniere release) dev c8f5370 (P1 conception FR + P2 : DB foundation + seed + Core skeleton src/app) Code applicatif : src/app/{Core,Controllers,Views} (App\ -> src/app), front src/public/admin/index.php Branches locales : dev, main (aucune feature en cours). Working tree : hors-scope BYAN + SESSION_RESUME (local) ``` ### Infra / forge / CI (a retenir) - **`git.acadenice.com` = Thanos, PROD** (serveur distinct 72.61.105.12). NE PAS confondre avec le forgejo local de stark `git.stark.a3n.fr`. Voir memoire `project_forge_topology`. - **CI Forgejo Actions** activee au niveau instance (`FORGEJO__actions__ENABLED=true`, fait par le user). Runner `forgejo-runner-wakdo` tourne sur stark, pointe la prod. **Apres restart du forgejo prod -> `docker restart forgejo-runner-wakdo`** (sinon boucle 404). - **CI static-tests = SANS Composer** : phpstan.phar + phpunit.phar epingles. Le runner (node:20-bookworm, PHP 8.2) installe `php-xml php-mbstring` (sinon PHPUnit manque dom/mbstring) — deja dans ci.yml. - **Auto-merge OPT-IN par label `auto-merge`** : le gate verifie le label EN SHELL via l'API (`GET issues/PR/labels` + grep), PAS via `if: contains(labels...)` de Forgejo (NON fiable : avait merge PR #9 sans label -> corrige PR #10). PR verte + label -> fusionne ; PR verte sans label -> reste ouverte. - **Required checks (dev+main)** : les 3 contextes precis `CI / {secret-scan,php-lint,static-tests} (pull_request)` (pas le glob `CI / *` qui incluait le job auto-merge skippe). Push-mirror -> GitHub auto. ### En attente du user - **Relecture des diagrammes** MCD + MLD (4+4 sous-domaines) — le user lisait les docs a la pause. Si un layout ne plait pas, ajuster via une petite PR. - Decision : auto-merger directement ou faire valider les diagrammes avant merge la prochaine fois. ### A faire a la reprise (P2 suite) - **Auth** : sessions PHP + argon2id (login), regeneration d'ID a la connexion, idle 4h / absolute 10h. **Prerequis** : passer les vars `ARGON2_*` / `SESSION_*` / lockout / throttle au conteneur wakdo-app (bloc `environment:` du `docker-compose.yml`) — PAS encore fait (seules DB_*/APP_*/SESSION_*/CORS_* y sont). - **RBAC** : middleware de permissions (teste une permission, pas un nom de role), protection routes admin + PIN pour actions sensibles. S'appuie sur le seed (roles/permissions/matrice deja en base). - **Seed ingredients/recettes** (differe) : decisions de modelisation (quels ingredients, quantites) avec le user. - **Hygiene** : revoquer les anciens PAT GitHub (Session 6). ### Reprendre ```bash cd /home/acadenice/corentin_wakdo git checkout dev && git fetch forgejo dev && git merge --ff-only forgejo/dev git log --oneline -6 dev ``` --- ## Session 2026-06-12 (relecture security-by-design + modele stock en % + lot A threat model) > Note : ce doc avait derive (fige a Session 7, 2026-05-21). Entre-temps : v0.2 prod-like > 19 entites + migration Forgejo (2026-06-04, voir `docs/journal/2026-06-04--*.md`) puis > demarrage du pivot security-by-design (2026-06-11). Le bloc ci-dessous repart de l'etat reel. ### Vue d'ensemble Consolidation du pivot security-by-design sur `feat/p1-conception`. Trois temps : 1. **Relecture des 3 decisions securite** (RGPD, oversell, brute-force) : les 3 directions validees. Le challenge a fait emerger une simplification (oversell) et un upgrade (stock %). 2. **Change-set applique aux 5 docs Merise** via 1 workflow (5 editeurs paralleles + 4 critiques adversariaux), puis correctifs manuels des residus rates par les critiques. 3. **Lot A ecrit** via 1 workflow (2 auteurs + 2 critiques) : threat model + classification dans `PROJECT_CONTEXT §19`, et `docs/uml/security-sequence.md`. ### Decisions actees cette session - **Stock en vrais %** : `ingredient` porte `stock_capacity` (INT, CHECK > 0 = reference 100% + garde anti div/0), `low_stock_pct` (def 10), `critical_stock_pct` (def 5) ; `stock_quantity` signe (peut etre negatif). `stock_pct = ROUND(stock_quantity/stock_capacity*100)` calcule. 3 bandes : normal / alerte (le manager retire via `is_available` OU re-stocke) / auto-OOS sous le critique. - **Disponibilite produit CALCULEE** (RG-T21) : commandable ssi `is_available=1 AND chaque ingredient non-retirable > critical`. Pas de cascade ni flag ; retrait manuel = override dur. - **`login_throttle` = table** (entite 21) : throttle brute-force per-IP, en plus du compteur per-compte sur `user`. - **Drop `SELECT ... FOR UPDATE`** : decrement stock = `UPDATE ... stock = stock - :units` atomique (plus de read-gate, plus de risque deadlock). `idempotency_key` conserve. - **Drift MCD §5.1 corrige** : `product_ingredient.quantity` -> `quantity_normal`/`quantity_maxi`. ### Etat Git (post-session) ``` Branche : feat/p1-conception 5 commits POSES cette session (non pushes - le push partira avec la PR) : fadf0bd DICT - SbD data layer, 21 entities a1692b6 MCD - SbD entities + % stock model, drift fix 14348ba MLD - audit_log + login_throttle tables, % stock columns 0f57a44 MCT - SbD operations, PIN gating, computed availability 5c34f6b MLT - RG-T13-T21, atomic decrement, throttle, RGPD Working tree UNCOMMITTED (tenu volontairement) : docs/PROJECT_CONTEXT.md (§19 threat model + classification ECRIT ; tenu car lot B va aussi toucher §7/§11) docs/uml/security-sequence.md (NOUVEAU, lot A, fini, verifie) docs/uml/{sequence-passer-commande,state-commande,use-cases}.md (drift-fix v0.2, pret, a grouper avec security-sequence.md) + journal 2026-06-04 untracked ; hors-scope BYAN (.claude, Makefile, docker-compose, package*) ``` ### A faire a la reprise (ordre) - **B** : `PROJECT_CONTEXT §7/§11` (retirer « MVP », 21 entites, rechiffrer planning) -> puis commit PROJECT_CONTEXT (§19 + §7/§11) + les 4 docs UML. - **C** : infra/config secu (`.env.example` argon2/lockout/retention/seuils, `php.ini` durci, secret-scan, ruling branch-protection). - **D** : SDLC (`SECURITY.md`, checklist PR template, jobs CI Forgejo PHPStan/secret-scan). - **E** : regenerer les drawio MCD/MLD pour 21 entites (les `.md` sont en Mermaid inline). - **F** : clore -> PR `feat/p1-conception -> dev` (base = `dev` !), rafraichir ce doc. - **G** : roter le token Forgejo expose ; decider push-mirror Forgejo->GitHub. ### Reprendre ```bash cd /home/acadenice/corentin_wakdo git branch --show-current # feat/p1-conception git log --oneline -6 # voir les 5 commits SbD git status --short # PROJECT_CONTEXT + UML uncommitted ``` --- ## Session precedente : 2026-05-21 (Session 7 - P1 conception : 5 docs Merise/UML + machine a etats commande unifiee) ### Vue d'ensemble Session centree sur la reprise de P1 conception. Trois resultats : 1. **Rapatriement P1 sur `feat/p1-conception`** : les fichiers P1 (mcd.md + diagrammes) flottaient dans le working tree de la branche demo `demo/p5-front-and-p3-admin`. Portes proprement sur `feat/p1-conception` (stash des fichiers BYAN hors-scope, switch, pop). Les 4 `.drawio` y etaient deja commites (`64f5a27`), identiques au working tree. 2. **5 docs P1 produits** via 2 agents (expert-merise-agile + architect), puis normalises : MCT, MLT, use-cases, state-commande, sequence-passer-commande. 3. **Machine a etats de commande unifiee** : resolution d'une contradiction qui preexistait entre `dictionary.md`, `PROJECT_CONTEXT.md` et le brief initial. Vocabulaire desormais coherent sur toute la doc. ### Etat Git actuel (post-Session 7) ``` Repo : /home/acadenice/corentin_wakdo/ Branche courante : feat/p1-conception (rien commite cette session) Working tree P1 (untracked, a commiter apres validation drawio) : docs/merise/mcd.md (MCD, refs encore vers SVG Mermaid - cf. pivot drawio non termine) docs/merise/mct.md (NEW - 24 operations metier) docs/merise/mlt.md (NEW - preconditions/regles/postconditions) docs/uml/use-cases.md (NEW) docs/uml/state-commande.md (NEW) docs/uml/sequence-passer-commande.md (NEW) docs/merise/_diagrams/*.mmd + *.svg (Mermaid leftover, a supprimer si on finit le pivot drawio) Working tree modifie (tracked) : docs/PROJECT_CONTEXT.md (ligne statut realignee sur machine canonique) .drawio : commites sur feat/p1-conception (clean), en attente validation visuelle user sur le site drawio. Hors-scope BYAN (persistants, jamais commites) : .claude/CLAUDE.md, .claude/rules/byan-agents.md, Makefile, package.json, package-lock.json ``` ### Decision majeure : machine a etats de commande (CANONIQUE) Trois vocabulaires se contredisaient (ENUM dictionnaire avec paiement / PROJECT_CONTEXT sans paiement / noms FR introduits par erreur dans le brief Merise). Tranche par le user : - **Deux phases** : le client compose (`pending_payment`) PUIS paie (`paid`), apres quoi la commande passe en preparation. Le paiement EXISTE dans le cycle. - **Termes en anglais** (code-facing), valeurs ENUM du dictionnaire. - **Machine retenue** : `pending_payment -> paid -> preparing -> ready -> delivered` - **`cancelled` atteignable depuis tout etat non remis** (`pending_payment`, `paid`, `preparing`, `ready`) : annulable a tout moment tant que non livree (modification / annulation / remboursement client). `delivered` et `cancelled` finaux. Applique partout : dictionary.md (deja correct), PROJECT_CONTEXT.md (corrige ligne 61), mct.md, mlt.md, state-commande.md, use-cases.md, sequence-passer-commande.md. ### Autres decisions actees Session 7 | Decision | Contexte | |---|---| | Outil diagramme MCD = drawio | User valide les 4 .drawio lui-meme sur le site (pas encore valides). Pivot Mermaid->drawio a finir cote pipeline + refs mcd.md | | Pas de parcours employe dedie | Les employes sont couverts par le diagramme de cas d'utilisation (use-cases) + diagramme d'etats. Ockham, evite le doublon | | Production parallele en respectant les dependances | On fait ce qui ne depend PAS du MCD (dependance nulle ou faible). On NE fait PAS ce qui en depend moyennement ou fortement (MLD, class-diagram) tant que les .drawio ne sont pas valides | | MOT saute (rappel) | Coherent Session 4 (raccourci agile MCT -> MLT direct) | ### Decisions secondaires EN SUSPENS (remontees par l'agent Merise, a trancher avant MLD) 1. **`source` (canal : kiosk/comptoir/drive) vs `mode_consommation` (fiscal : sur_place/a_emporter/drive)** : deux dimensions distinctes. `source` est absent du dictionnaire et du MCD. A ajouter avant de generer le DDL. 2. **`user_id` sur `commande`** : aucune tracabilite de l'equipier qui saisit / prend en charge / livre. A amender dans le MCD si stats par equipier souhaitees. (Points mineurs documentes dans mct.md section 14 et mlt.md section 13 : `service_day` non materialise, etc.) ### A faire lors de la reprise (ordre recommande) 1. **User valide les 4 `.drawio`** sur le site drawio (preview Markdown ne rend pas Mermaid sans extension ; les .drawio/.svg s'affichent en revanche). 2. **Trancher les 2 decisions secondaires** (`source` vs `mode_consommation`, `user_id` sur commande) - elles debloquent le MLD + class-diagram. 3. **Finir le pivot drawio** (si confirme) : cible Makefile `docs-render-drawio` (image `jgraph/drawio` dispo localement), regenerer les SVG depuis les .drawio, reecrire les refs dans mcd.md (actuellement vers SVG Mermaid), supprimer les `.mmd`/`.svg` Mermaid. 4. **Produire MLD + class-diagram** une fois le MCD valide et les decisions secondaires tranchees. 5. **Commiter le lot P1 conception** (option : 1 commit par doc) sur `feat/p1-conception`, puis PR vers `dev` (vigilance : base = `dev`, pas `main`). ### Commande exacte pour reprendre ```bash cd /home/acadenice/corentin_wakdo git status git branch --show-current # attendu : feat/p1-conception ls docs/merise/ # mcd.md, mct.md, mlt.md, dictionary.md ls docs/uml/ # use-cases.md, state-commande.md, sequence-passer-commande.md ``` --- ## Session precedente : 2026-05-09 (Session 6 - drawio + P5 front complet en remote control) ### Vue d'ensemble Session ~3-4h en remote control mobile qui a couvert 2 gros chantiers et un long detour sur l'automation des PRs : 1. **Pivot Mermaid -> drawio sur le MCD** : 4 fichiers `.drawio` XML generes pour gain de controle layout (planarite du global non resoluble par mmdc) 2. **Front P5 complet anticipe** : 2 runs d'agent UX (Sally) ont produit 7 pages HTML kiosk + 7 modules JS vanilla + JSON fallback statique. Flux complet welcome -> confirmation, live sur le vhost. 3. **Setup automation PR via API** : detour sur fine-grained PATs (3 tentatives KO sur policy org AcadeNice "approval required"), resolu avec un classic PAT `ghp_` en attendant l'approbation admin lundi. 2 PR ouvertes sur GitHub : - **#4** ready : front P5 complet (7 commits) - **#5** draft : 4 .drawio sources, en attente cleanup et suite Merise/UML ### Etat Git actuel (post-Session 6) ``` Repo : /home/acadenice/corentin_wakdo/ Remote : git@github-wakdo:AcadeNice/wakdo_corentin.git Branches : main 00a3f82 (v0.1.0) dev 68db2ee feat/p1-conception 64f5a27 (PR #5 draft : 4 .drawio committed) feat/p5-front-landing 6a7e772 (PR #4 ready : 7 commits P5 complet) <- HEAD post-session feat/infra-docker b09c461 (mergee, conservee) feat/p1-assets-import 24e733b (mergee, conservee) feat/p1-stubs-and-dictionary d1a9876 (mergee, conservee) Tags : v0.1.0 00a3f82 Infrastructure foundation Working tree out-of-scope (BYAN, persistent depuis sessions precedentes) : .claude/CLAUDE.md, .claude/rules/byan-agents.md, Makefile package.json, package-lock.json docs/SESSION_RESUME.md (ce fichier) Working tree P1 (uncommitted, voyage entre branches lors des switches) : docs/merise/mcd.md docs/merise/_diagrams/*.mmd (Mermaid leftover, a supprimer apres render drawio) docs/merise/_diagrams/*.svg (Mermaid render, idem) ``` ### PRs ouvertes | # | Titre | Branche | Base | Statut | |---|---|---|---|---| | 4 | feat(front): P5 kiosk complete flow with vanilla JS and JSON fallback | `feat/p5-front-landing` | `dev` | Ready for review | | 5 | docs(merise): MCD diagrams in drawio XML (4 files) | `feat/p1-conception` | `dev` | Draft | ### Decisions actees Session 6 | Decision | Contexte | |---|---| | Switch Mermaid -> drawio pour MCD | Planarite du global non resoluble par mmdc auto-layout, controle manuel requis | | 4 .drawio separes (1 par diagramme) | Plus simple a editer et diff que multi-page | | Front P5 anticipe pendant P1 | Data contract gele par brief ecole (JSON sources), front consomme JSON = consomme future API au mapping pres | | Classic PAT (`ghp_`) au lieu de fine-grained AcadeNice | Org AcadeNice policy "approval required", admin pas dispo le weekend | | Branche front renommee `p1` -> `p5` | Front borne = livrable P5 per plan SDLC (independant de la phase de realisation) | | Auto-validation 7 checks par l'agent | Remote control mobile = pas de validation visuelle facile, agent doit s'auto-verifier | | Mode JSON fallback statique dans `borne/data/` | Apache bind-mount ne sert pas `_sources/`, copie statique = solution simple. Swap point unique dans `data.js` pour P4 | | TVA 10% (taux restauration FR 2024 simplifie) | TODO P3 : valider avec comptable les variations sur place vs a emporter, alcool, etc. | | `gh` dans Docker = mauvaise idee | Stack Docker = runtime app, pas dev tooling. `gh` ou curl appartient a l'host. | | Token GitHub stocke dans `.env` (gitignore) | Standard, pas de leak en commits, lu via `source .env` au moment du curl | ### Ce qui a ete fait chronologiquement **Bloc 1 - Pivot Mermaid -> drawio + 4 sources XML** 1. Decision drawio uniquement, 4 fichiers separes, manual layout 2. Generation des 4 fichiers `.drawio` XML avec entites + cardinalites Merise `(min,max)` a partir des sources Mermaid 3. Commit `64f5a27` : `docs(merise): add drawio XML sources for MCD diagrams` **Bloc 2 - 1er agent UX (welcome + categories scaffold)** 4. Spawn agent UX-designer (Sally) en background avec scope 2 ecrans (welcome + categories), flag `isolation: "worktree"` 5. L'agent a base sa branche sur `feat/p1-conception` au lieu de `dev` (le worktree n'a pas vraiment isole comme attendu) 6. Rebase `feat/p1-front-landing --onto dev 64f5a27` pour droper le commit drawio comme parent 7. Renommage `feat/p1-front-landing` -> `feat/p5-front-landing` (front borne = livrable P5) **Bloc 3 - Setup automation PR (long detour sur les PATs)** 8. Push des 2 branches (SSH agent socket `/tmp/ssh-Evc7jT0fk2rs/agent.2611024`) 9. Tentative `gh` CLI dans Docker -> mauvaise idee, abandonne 10. Tentative fine-grained PAT #1 : Resource owner = Imugiii -> 404 sur wakdo_corentin (org repo invisible pour PAT a owner perso) 11. Fine-grained PAT #2 : meme probleme (Resource owner encore = Imugiii) 12. Fine-grained PAT #3 avec Resource owner = AcadeNice -> token en "Pending review" (org policy "approval required") 13. Fallback classic PAT (`ghp_`) -> fonctionne des generation, scope `repo`, admin sur le repo 14. PR #4 (front ready) + PR #5 (drawio draft) creees via `POST /repos/AcadeNice/wakdo_corentin/pulls` **Bloc 4 - 2e agent UX (P5 complet)** 15. Spawn agent UX en background sur `feat/p5-front-landing` avec scope etendu : 5 nouvelles pages + JS state + JSON fallback 16. Auto-validation 7 checks dans le brief (assets exist, links resolve, JSON valid, HTML closed, JS syntax, http server e2e, JSON fetch) 17. Livrable : 5 pages HTML, 7 modules JS, 2 JSON normalises copies dans `borne/data/`, CSS etendu de 438 -> 1257 lignes 18. 6 commits thematiques (`6f5daca` -> `6a7e772`), 7/7 auto-checks PASS 19. Push, mise a jour PR #4 (titre + body) via `PATCH /repos/.../pulls/4` 20. Test live kiosk : les endpoints repondent 200 (welcome, categories, products, product, cart, payment, confirmation, JSON, CSS, JS, images) ### Commande exacte pour reprendre ```bash cd /home/acadenice/corentin_wakdo git status git branch --show-current # Si HEAD = feat/p5-front-landing : tu peux tester le front sur https://corentin-wakdo.stark.a3n.fr/ # Pour reprendre P1 : git checkout feat/p1-conception ``` ### A faire lors de la reprise (ordre recommande) 1. **Review visuelle PR #4** : tester le flux kiosk complet sur https://corentin-wakdo.stark.a3n.fr/, valider, merger dans `dev` (via web ou via API) 2. **Drawio render automatique** : ajouter cible Makefile `make docs-render-drawio` qui utilise le container `rlespinasse/drawio-export` pour generer les SVG depuis les `.drawio` XML. Evite l'export manuel sur drawio web (galere sur mobile). 3. **Continuer P1 conception** sur `feat/p1-conception` : - `docs/merise/mct.md` - `docs/merise/mlt.md` - `docs/merise/mld.md` - `docs/uml/class-diagram.md` - `docs/uml/use-cases.md` - `docs/uml/state-commande.md` - `docs/uml/sequence-passer-commande.md` 4. **Commit final mcd.md** : une fois les SVG drawio generes, commit `mcd.md` + suppression des `.mmd`/anciens `.svg` Mermaid + Makefile mis a jour (drop `docs-render` mmdc, garder uniquement `docs-render-drawio`) 5. **Passage PR #5 draft -> ready** (via PATCH API) quand tout le P1 conception est dedans 6. **Hygiene secu PATs** : revoquer dans GitHub Settings : - 3 fine-grained `github_pat_...` (suffixes BE4y, UiZc, ljeC) - classic `ghp_Rr5EkM4...` (a rotater quand fine-grained AcadeNice approuve par admin lundi) ### Note technique - isolation worktree Le flag `isolation: "worktree"` sur l'Agent tool n'a pas cree de vrai worktree isole - les agents ont travaille directement sur le main repo (`git worktree list` ne montre qu'une entree). Pas grave en pratique mais a savoir pour les prochains spawns : instruire explicitement l'agent de ne pas switch de branche dans le main repo, ou de bosser en branche dediee pre-checked-out. --- ## Session precedente : 2026-04-30 soir (Session 5 - notes perso + demarrage P1 conception + setup pipeline diagrammes) ### Vue d'ensemble Session moyenne (~3h) qui a couvert : 1. **Cloture P1 dictionnaire** : commit + push + PR #3 mergee dans `dev` 2. **4 notes perso ecrites** (gitignore) : apache-fastcgi-pitfalls, docker-network-pools-rfc1918, enum-vs-table-reference, merise-yagni-quantite + index README mis a jour 3. **Demarrage P1 conception** sur nouvelle branche `feat/p1-conception` (renommee depuis `feat/p1-merise-conception` pour inclure UML) 4. **MCD redige** (`docs/merise/mcd.md`) avec 3 sous-domaines (Catalogue/Commande/RBAC) en Mermaid + tableau recap cardinalites Merise 5. **Pipeline mmdc setup** : .mmd sources + SVG generes + `make docs-render` target 6. **Blocage layout MCD global** : 10 entites + 10 associations = probleme planarite intrinseque, decision laissee en suspens Aucun commit fait sur la branche `feat/p1-conception` — tout reste dans le working tree pour reprise propre. ### Etat Git actuel (post-Session 5) ``` Repo : /home/acadenice/corentin_wakdo/ Remote : git@github-wakdo:AcadeNice/wakdo_corentin.git Branches : main 00a3f82 (v0.1.0) dev 68db2ee (= main + PR#1 + PR#2 + PR#3 mergees) feat/infra-docker b09c461 (mergee, conservee) feat/p1-assets-import 24e733b (mergee, conservee) feat/p1-stubs-and-dictionary d1a9876 (mergee via PR#3, conservee) feat/p1-conception 68db2ee (NOUVELLE, ZERO COMMIT, working tree only) Tags : v0.1.0 00a3f82 Infrastructure foundation Working tree sur feat/p1-conception (a commit a la prochaine session) : docs/merise/mcd.md (NEW - 411 lignes) docs/merise/_diagrams/mcd-global.mmd (NEW) docs/merise/_diagrams/mcd-global.svg (NEW) docs/merise/_diagrams/mcd-catalogue.mmd (NEW) docs/merise/_diagrams/mcd-catalogue.svg (NEW) docs/merise/_diagrams/mcd-commande.mmd (NEW) docs/merise/_diagrams/mcd-commande.svg (NEW) docs/merise/_diagrams/mcd-rbac.mmd (NEW) docs/merise/_diagrams/mcd-rbac.svg (NEW) Makefile (modified - target docs-render ajoute) docs/notes/README.md (modified, gitignore - 7 entries ajoutees) docs/notes/apache-fastcgi-pitfalls.md (NEW, gitignore) docs/notes/docker-network-pools-rfc1918.md (NEW, gitignore) docs/notes/enum-vs-table-reference.md (NEW, gitignore) docs/notes/merise-yagni-quantite.md (NEW, gitignore) Working tree out-of-scope (BYAN, deja modifies en sessions precedentes) : .claude/CLAUDE.md .claude/rules/byan-agents.md package.json, package-lock.json docs/SESSION_RESUME.md ``` ### Decisions actees Session 5 | Decision | Contexte | |---|---| | Branche renommee `feat/p1-conception` (au lieu de `feat/p1-merise-conception`) | Pour inclure UML dans le scope de la PR | | UML ajoute au scope P1 conception | RNCP 37805 attend Merise + UML, pas que Merise | | Granularite commits PR : option α (1 commit par doc) | Coherent avec l'historique, squashable en fin de PR si besoin | | Pipeline diagrammes : option B (mmdc local + SVG embed) | Rendu portable Cursor/GitHub/PDF/Notion, regenerable via `make docs-render` | | Ecriture des 4 notes perso AVANT le travail Merise | Sujets frais dans le contexte (Session 4 + dictionnaire) | | Auteur des notes = "BYAN" | Coherent avec section 17 PROJECT_CONTEXT (transparence methodologie) | | 4 hedgings appliques (`toujours`/`forcement` -> `tend a`/`implique`) | Hook PreToolUse fact-check intransigeant | ### Decision EN SUSPENS (a trancher en premier la prochaine session) **Layout du diagramme global MCD** : avec 10 entites et 10 associations (dont 2 polymorphiques sur `LIGNE_COMMANDE` -> PRODUIT et MENU), il y a un probleme de planarite : impossible de placer toutes les entites sans croiser au moins 2 lignes. Mermaid auto-layout galere, Excalidraw manuel n'aide pas vraiment. 3 options en attente d'arbitrage : - **A. Drop le global** — supprimer section 3 du MCD, garder section 6 (tableau recap des cardinalites) + section 4 (3 sous-domaines Mermaid propres). Coherent avec l'approche Merise (decomposer si > 5 entites). Defendable au jury : "j'ai decompose, tableau recap = vue integree". - **B. Excalidraw manuel** — refaire le global a la main dans Excalidraw, export `.excalidraw.svg` (avec scene embedee), embed dans le MCD. Coute 20-30 min de layout manuel, perd la regen automatique. - **C. Garder Mermaid en l'etat** — assumer que le layout est croise mais jouer le compromis "decomposition prime sur visuel global". Le user a dit "le choix n'est pas encore fait" (Session 5 fin de soiree, fatigue sur le sujet). A reprendre tete reposee. ### Ce qui a ete fait chronologiquement **Bloc 1 - Cloture dictionnaire (commit + PR)** 1. Verification etat initial : branche `feat/p1-stubs-and-dictionary` avec `b8f7d35` (stubs+fixes) commit, `docs/merise/dictionary.md` uncommitted 2. Commit `d1a9876` : `docs(merise): data dictionary v0.1 - 10 entities + Mermaid ER diagram + 7 modeling notes` 3. Push branche, PR #3 ouverte manuellement (gh CLI absent), mergee sur `dev` 4. `git fetch + checkout dev + merge --ff-only origin/dev` : sync OK sur `68db2ee` **Bloc 2 - 4 notes perso (gitignore)** 5. Bascule sur `Read` au lieu de `grep`/`sed` apres blocage du hook `tool-failure-guard` sur "internal error" string presente dans `vhost.conf` (pattern legitime du commentaire, faux positif Bash output) 6. `apache-fastcgi-pitfalls.md` (405 lignes) - 3 pieges Session 4 (DirectoryIndex, allowed_clients, R=200) + Q&A jury 7. `docker-network-pools-rfc1918.md` (376 lignes) - saturation pools Docker sur stark, choix `192.168.148.0/24`, RFC 1918, Q&A jury 8. `enum-vs-table-reference.md` (381 lignes) - matrice de decision ENUM vs table, application aux 4 ENUMs Wakdo, Q&A jury 9. `merise-yagni-quantite.md` (337 lignes) - YAGNI applique a `menu_produit`, audit source ecole 13 menus mono-portion, Q&A jury 10. `docs/notes/README.md` index mis a jour : 7 nouvelles entrees (3 Session 4 deja redigees + 4 nouvelles) **Bloc 3 - Setup branche conception + cadrage** 11. Branche `feat/p1-merise-conception` creee depuis `dev`, puis renommee en `feat/p1-conception` apres discussion sur l'ajout UML au scope 12. Decision : 8 documents prevus pour la PR : - Merise : MCD, MCT, MLT, MLD (4 docs dans `docs/merise/`) - UML : classes, use cases, etats, sequence (4 docs dans `docs/uml/`) 13. `docs/uml/` cree **Bloc 4 - MCD redige + setup pipeline diagrammes** 14. Premier draft MCD avec 4 diagrammes ASCII art (global + 3 sous-domaines) + tableau recap cardinalites Merise `(0,N)/(1,1)` 15. User trouve l'ASCII moche -> bascule sur Mermaid `erDiagram` inline 16. User ne voit pas le rendu Mermaid dans Cursor (pas d'extension installee) -> bascule sur SVG via mmdc 17. Setup `docs/merise/_diagrams/` : 4 fichiers `.mmd` extraits + 4 SVG generes via `npx mmdc` 18. MCD edite : 4 blocs Mermaid remplaces par `` 19. Makefile : target `docs-render` ajoute, scanne tous les `docs/**/_diagrams/*.mmd` du projet, regen SVG (testee, OK 4/4) 20. User constate que le global a des lignes croisees, tente Excalidraw, n'arrive pas a un layout logique -> decision laissee en suspens ### Commande exacte pour reprendre ```bash cd /home/acadenice/corentin_wakdo git status # confirmer working tree intact git branch --show-current # doit etre feat/p1-conception git log --oneline dev..HEAD # doit etre vide (zero commit sur la branche) ls docs/merise/ # mcd.md + _diagrams/ presents ls docs/notes/ # 4 notes Session 5 + README maj ``` ### A faire lors de la reprise (ordre recommande) 1. **Trancher le layout MCD global** (option A / B / C ci-dessus). Si A, editer mcd.md pour supprimer section 3, decrementer les numeros, et supprimer `_diagrams/mcd-global.{mmd,svg}`. Si B, faire le travail Excalidraw manuel. Si C, ne rien faire et continuer. 2. **Commit le MCD** (option α : 1 commit par doc) : ```bash git add docs/merise/mcd.md docs/merise/_diagrams/ Makefile git commit -m "docs(merise): MCD v0.1 + pipeline mmdc -> SVG via make docs-render" ``` 3. **Continuer P1 conception**, dans l'ordre : - `docs/merise/mct.md` - operations metier + acteurs + flux - `docs/merise/mlt.md` - workflow logique (preconditions / regles / postconditions) - `docs/merise/mld.md` - schema relationnel formel - `docs/uml/class-diagram.md` - vue OOP (prepare PHP P2) - `docs/uml/use-cases.md` - acteurs + goals (kiosk client, manager, ...) - `docs/uml/state-commande.md` - machine a etats `commande.statut` - `docs/uml/sequence-passer-commande.md` - flux passer commande 4. **Push + PR vers `dev`** quand les 7 docs restants sont commit. Vigilance : verifier `base = dev` (pas `main` !). 5. **Apres merge** : continuer P1 implementation (DDL + seed + fallback) sur une branche `feat/p1-implementation` separee. --- ## Session precedente : 2026-04-30 jour (Session 4 etendue - smoke test infra + import assets + P1 demarre) ### Vue d'ensemble Session tres longue (~6h cumulees) qui a couvert 3 grandes phases en une seule journee : 1. **Smoke test infra Docker** sur le serveur stark : `make init` valide bout en bout, 4 services healthy, certs Let's Encrypt provisionnes 2. **Import assets ecole** : 71 images normalisees + 2 JSON sources + maquette Figma PDF 3. **Demarrage P1 Merise** : stubs unblock-403 + dictionnaire de donnees v0.1 (10 entites) 3 PR ont ete fusionnees (1 incident main->dev recupere) et 1 PR reste ouverte (la branche de la 3e phase n'est pas encore push). ### Etat Git actuel (post-Session 4) ``` Repo : /home/acadenice/corentin_wakdo/ Remote : git@github-wakdo:AcadeNice/wakdo_corentin.git Branches : main 00a3f82 (v0.1.0 - infra foundation) dev 84d2559 (= main + PR#2 assets) feat/infra-docker b09c461 (mergee dans main via PR#1, conservee) feat/p1-assets-import 24e733b (mergee dans dev via PR#2, conservee) feat/p1-stubs-and-dictionary b8f7d35 (LOCAL UNIQUEMENT - NON PUSHEE) + dictionnaire UNCOMMITTED dans le working tree Tags : v0.1.0 00a3f82 Infrastructure foundation (annotated, pushe) Working tree out-of-scope (volontairement non commit) : .claude/CLAUDE.md, .claude/rules/* (modifies hors-projet, BYAN) package.json, package-lock.json (BYAN) docs/SESSION_RESUME.md (ce fichier - local perso) ``` ### Vue chronologique des PR ``` 00a3f82 (main, dev, v0.1.0) Merge PR #1 from feat/infra-docker - INCIDENT : PR ouverte par defaut sur 'main' au lieu de 'dev' - REMEDIATION : git checkout dev && git merge --ff-only origin/main && git push origin dev - LECON : verifier le selecteur 'base branch' sur GitHub avant 'Create pull request' - 9 commits infra : compose, dockerfiles, smoke test fixes, FQDN switch, journal session 4 84d2559 (dev) Merge PR #2 from feat/p1-assets-import - PR sur la bonne base 'dev' cette fois - 1 commit : import des 2 JSON sources + 71 images normalisees + maquette PDF ``` ### Ce qui a ete fait (chronologique session) **Phase 1 - smoke test infra (avant pause)** 1. Conflit `.env` BYAN/Wakdo traite par fusion en 1 fichier (gitignore) 2. Switch FQDN `acadenice.fr` -> `stark.a3n.fr` (zone wildcard existante, evite la provisioning DNS prerequise par le challenge HTTP-01 de Traefik) 3. Smoke `make init` casse 3 fois et corrige : - Subnet explicite `192.168.148.0/24` (pools Docker satures) - `init: true` sur cron (dcron PID 1 setpgid) - Healthz statique dans `/usr/local/apache2/htdocs/` (RewriteRule R=200 declenchait ErrorDocument template) 4. Validation HTTPS externe : 4 services healthy, certs OK, `/healthz` isole 5. Journal session ecrit (`docs/journal/2026-04-30--smoke-test-infra.md`) 6. PR #1 -> incident main au lieu de dev -> remediation FF dev=main 7. Tag `v0.1.0` annote sur le merge commit 8. Memoire `feedback_no_absolutes.md` enregistree (hook fact-check sensible) **Phase 2 - import assets ecole** 9. Drop zone `docs/_inbox/` recue (9 Mo, 71 images + 2 JSON + 1 PDF + 1 readme) 10. Diagnostic : naming "wacdo" vs notre "Wakdo", casse incoherente, 7 typos dans JSON 11. Rangement final : - `docs/merise/_sources/` (2 JSON + source-school.md provenance) - `docs/design/` (maquette PDF + README pointant Figma) - `src/public/borne/assets/images/` (71 images normalisees kebab-case lowercase) 12. Workaround `chown` via container ephemere (src/ etait owned root par Docker bind-mount) 13. PR #2 -> dev (workflow correct cette fois) **Phase 3 - demarrage P1 Merise** 14. Decisions cadrage P1 actees : - MOT skippe (raccourci agile MCT -> MLT direct) - Composition flexible (`menu_produit` avec `role` et `position`) - Pas de `quantite` sur menu_produit (YAGNI - 13 menus mono-portion) - 9 entites + 1 jointure RBAC : Categorie, Produit, Menu, MenuProduit, Commande, LigneCommande, User, Role, Permission, RolePermission - Pas de stock numerique (juste `est_disponible` boolean) - Pas de stats agregees (live queries) - Pas d'allergenes/nutrition pour MVP 15. Stubs minimaux pour debloquer le 403 : - `src/public/borne/index.html` (HTML statique avec logo, vhost kiosk) - `src/public/admin/index.php` (PHP qui prouve la chaine FastCGI E2E) 16. 2 bugs infra exposes par les stubs et fixes : - Apache `DirectoryIndex` ne contenait pas `index.php` (admin renvoyait 403) - PHP-FPM `listen.allowed_clients = any` rejete par PHP 8.3 (toutes les connexions Apache->PHP-FPM rejetees, FastCGI cassait silencieusement) 17. Validation HTTPS externe : kiosk -> 200 HTML, admin -> 200 PHP rendu (PHP_VERSION et timestamp dynamique substitues) 18. Commit `b8f7d35` : `feat(stubs): unblock 403 with kiosk and admin index pages, plus FastCGI fixes` 19. Dictionnaire de donnees v0.1 redige (`docs/merise/dictionary.md`) : - ~340 lignes, 10 entites detaillees - Diagramme entites-relations en Mermaid (rendu GitHub natif) - 7 notes de modelisation (FLOAT vs cents, ENUM vs table, STI, polymorphisme, audit fields, RFC 5321 emails, etc.) - Cross-validation avec `PROJECT_CONTEXT.md` et source ecole 20. 3 notes techniques perso (`docs/notes/`, gitignore) : - `rbac-roles-permissions.md` : pattern RBAC dynamique vs statique, UI matrice, Q&A jury - `monetary-int-cents.md` : INT centimes + TVA pour mille, Goldberg ACM 1991, Stripe convention, 5 pieges - `polymorphic-fk-snapshots.md` : 2 colonnes nullables + discriminator + snapshots, Karwin SQL Antipatterns, integrite historique commandes 21. Memoire `feedback_notes_author.md` mise a jour : auteur des notes = "BYAN" (pas un nom de LLM specifique), coherent avec la transparence projet section 17 PC --- ## En cours (a reprendre) **Branche locale `feat/p1-stubs-and-dictionary` avec 1 commit fait + dictionnaire UNCOMMITTED.** ### Commande exacte pour reprendre ```bash cd /home/acadenice/corentin_wakdo git status # confirmer ?? docs/merise/dictionary.md git branch --show-current # doit etre feat/p1-stubs-and-dictionary git log --oneline dev..HEAD # voir b8f7d35 (stubs+fixes) ``` ### A faire lors de la reprise 1. **Commit le dictionnaire** : ```bash git add docs/merise/dictionary.md git commit -m "docs(merise): data dictionary v0.1 - 10 entities + Mermaid ER diagram + 7 modeling notes Bottom-up derivation from school JSON sources + PROJECT_CONTEXT business rules. Covers : Categorie, Produit, Menu, MenuProduit, Commande, LigneCommande, User, Role, Permission, RolePermission. Decisions documented : prices in INT cents, VAT in per-mille, polymorphic FK with snapshots on ligne_commande, dynamic roles vs static permissions for RBAC." ``` 2. **Push + PR** : ```bash SSH_AUTH_SOCK=/tmp/ssh-Evc7jT0fk2rs/agent.2611024 git push -u origin feat/p1-stubs-and-dictionary ``` Puis ouvrir PR via : `https://github.com/AcadeNice/wakdo_corentin/compare/dev...feat/p1-stubs-and-dictionary?expand=1` **VIGILANCE** : verifier base = `dev` (pas `main` !) avant de cliquer Create. 3. **Continuer P1** sur une nouvelle branche `feat/p1-merise-models` (apres merge de la precedente) ou sur la meme branche etendue. Suite des etapes : - **MCD** : `docs/merise/mcd.md` avec un diagramme Mermaid plus formel (entites + associations + cardinalites min/max), distinct du diagramme preview du dictionnaire - **MCT** : `docs/merise/mct.md` - les operations metier (valider commande, encaisser paiement, marquer pret, ...) - **MLT** : `docs/merise/mlt.md` - workflow logique de chaque traitement (preconditions, regles, postconditions, sorties) - **MLD** : `docs/merise/mld.md` - schema relationnel formel - **DDL** : `db/migrations/0001_init_schema.sql` - SQL CREATE TABLE concret - **Seed** : `db/seeds/0001_demo_data.sql` - INSERT des 9 categories + 53 produits + 13 menus a partir des JSON sources, avec normalisation des prix en centimes - **Export fallback JSON** : `scripts/export-fallback.{sh|php}` qui genere `src/public/borne/data/*.json` depuis le seed (pour mode "Bloc 1 isole") 4. **Notes perso restantes a rediger** (basse priorite, peut s'etaler sur plusieurs sessions) : - `enum-vs-table-reference.md` : quand utiliser ENUM vs table referentielle - `docker-network-pools-rfc1918.md` : pool saturation Docker, choix subnet explicite - `apache-fastcgi-pitfalls.md` : les 3 bugs infra de cette session (DirectoryIndex, listen.allowed_clients, RewriteRule R=200) - `merise-yagni-quantite.md` : application concrete de YAGNI sur menu_produit 5. **Optionnels post-merge** (peuvent aller sur une branche `feat/infra-polish` separee apres P1) : - Investiguer redirect HTTP->HTTPS qui retourne 404 (interaction avec middleware global du Traefik d'hote) - Unifier le style init Docker (wakdo-app a tini explicite, wakdo-cron a `init: true` - incoherence stylistique a accepter ou unifier) --- ## Workflow git en vigueur - **Convention** : `feat/* -> dev` (squash merge), `dev -> main` (avec tag `vX.Y.Z` annote) - **Vigilance PR** : verifier explicitement `base branch = dev` (le defaut GitHub est `main`) - **Branches mergees** : conservees comme trace historique - **Procedure d'archive** si une branche est abandonnee non-mergee : ```bash git tag -a archive/feat-xxx -m "abandoned: " git push origin archive/feat-xxx git push origin --delete feat-xxx git branch -D feat-xxx ``` - **Tags previsionnels** : v0.1.0 (infra), v0.2.0 (P2 stubs+auth+CRUD basic), v0.3.0 (CRUD admin complet), ..., v1.0.0 (livrable jury) --- ## Decisions structurelles actees Session 4 | Decision | Pourquoi | |---|---| | Fusion `.env` BYAN+Wakdo | Outil tiers lit `.env` du cwd, separation `.env.wakdo` plus risquee | | FQDN sur `*.stark.a3n.fr` | Wildcard DNS existant, evite provisioning prerequis HTTP-01 | | Subnet explicite `192.168.148.0/24` (RFC 1918) | Pools Docker satures sur hote partage | | `init: true` sur cron | dcron en PID 1 sans init reaper boucle sur setpgid Operation not permitted | | Healthz statique htdocs | RewriteRule R=200 declenche template ErrorDocument | | `APP_ENV=dev` + `APP_DEBUG=true` | Phase de construction, flip vers prod avant demo jury | | Naming "wacdo" (source) vs "Wakdo" (projet) | wacdo preserve dans `_sources/` pour tracabilite ecole | | Casse images normalisee kebab-case lowercase | Anti-piege case-sensitive Linux dans Docker | | MOT (modele organisationnel des traitements) skippe | Raccourci agile MCT -> MLT direct | | Composition flexible `menu_produit` (role+position) | Defendable evolution future sans refacto | | Pas de `quantite` sur `menu_produit` | YAGNI - 13 menus mono-portion | | Prix en INT centimes + TVA en pour mille | Anti-FLOAT IEEE 754 (Goldberg ACM 1991) | | Snapshots libelle+prix sur `ligne_commande` | Integrite historique audit | | Polymorphisme `ligne_commande` -> `produit` OR `menu` | 2 cols nullable + discriminator + 2 FKs reelles | | RBAC : roles+role-permission dynamiques, permissions statiques | Permissions liees au code (declarees en migration) | | Pas de stock numerique en MVP | Juste `est_disponible` boolean | | Pas de stats agregees | Live queries SUM/GROUP BY suffisent | | Pas d'allergenes/nutrition | Hors source ecole, hors scope MVP | | ENUM pour valeurs metier stables | mode_consommation, statut, role -> 3-7 valeurs, ALTER si extension | | Auteur notes perso = "BYAN" | Coherent avec section 17 PC (transparence methodologie) | --- ## Prochaines etapes (apres merge `feat/p1-stubs-and-dictionary` -> `dev`) ``` P1 Conception Merise (semaines 2-3) - EN COURS 1. Dictionnaire de donnees v0.1 ECRIT (a commit) 2. MCD a faire 3. MCT a faire 4. (MOT skippe) 5. MLD a faire 6. MLT a faire 7. DDL a faire 8. Seed data a faire 9. JSON fallback a faire P2 Back squelette (semaines 4-6) - Core (Router, Autoloader, DB) - Auth (sessions PHP fichier + argon2id) - RBAC (Authorization service) - Front controller `index.php` P3 CRUD admin (semaines 7-10) - CRUD produits, menus, categories - UI roles + assignment matrice permissions - CRUD users P4 API REST (semaines 11-12) - Endpoints /api/categories, /api/menus, /api/produits, /api/orders - CORS + tests P5 Front borne (semaines 13-16) - Integration maquette + Ajax + a11y RGAA - Mode JSON-seuls (fallback) + mode API-connecte P6 Tests + finition (semaines 17-18) P7 DevOps final (semaine 19) - GitHub Actions, crons, docs P8 Prep soutenance (semaine 20) ``` --- ## Fichiers cles a consulter a la reprise | Fichier | Contenu | |---|---| | `docs/PROJECT_CONTEXT.md` | Source de verite projet (FQDN sur stark.a3n.fr, section 17 transparence IA) | | `docs/_ref/rncp-37805-referentiel.pdf` | Referentiel RNCP officiel | | `docs/_ref/rncp-37805-index.md` | Index texte compact des criteres (cherchable) | | `docs/journal/README.md` | Template + index des retros (3 entrees) | | `docs/journal/2026-04-30--smoke-test-infra.md` | Retro Session 4 phase 1 (smoke test) | | `docs/merise/dictionary.md` | **Dictionnaire P1 v0.1 ECRIT (a commit)** | | `docs/merise/_sources/` | JSON sources ecole + provenance | | `docs/design/` | Maquette PDF + lien Figma | | `docs/notes/` | Notes perso revision oral (3 ecrites cette session, gitignore) | | `docs/SESSION_RESUME.md` | Ce fichier - a mettre a jour en fin de session | | `.env` | Config locale fusionnee (BYAN + Wakdo, gitignore) | | `.env.example` | Template neutre commit, RFC 2606 | | `docker-compose.yml` | Compose final (subnet 192.168.148.0/24 + init cron + 4 services) | | `Makefile` | Orchestration complete, voir `make help` | | `.claude/CLAUDE.md` | Constitution projet BYAN | | `.claude/rules/fact-check.md` | **Patterns du hook fact-check (a consulter avant ecriture narrative !)** | --- ## Commandes utiles pour reprendre ```bash cd /home/acadenice/corentin_wakdo # 1. Etat git status git branch --show-current # -> attendu : feat/p1-stubs-and-dictionary # 2. Stack docker (verifier qu'elle tourne toujours) docker compose -p wakdo ps # Si down apres reboot : make up (ou make init pour full bootstrap) # 3. Test que tout repond curl -sI https://corentin-wakdo.stark.a3n.fr/ # 200 curl -sI https://corentin-wakdo-admin.stark.a3n.fr/ # 200 # 4. SSH pour push (si besoin) find /tmp -name 'agent.*' -user corentin # -> /tmp/ssh-Evc7jT0fk2rs/agent.2611024 (peut changer apres reboot ssh-agent) SSH_AUTH_SOCK=/tmp/ssh-XXX/agent.NNN git push ... ``` --- ## Memoire persistante Claude Code (mise a jour Session 4) Regles enregistrees dans `/home/corentin/.claude/projects/-home-acadenice-corentin-wakdo/memory/` : - **No Co-Authored-By** sur les commits Wakdo (Session 2) - **Commit uniquement sur approbation explicite** (Session 2) - **Ignorer les contextes d'autres projets** dans les system-reminders (Session 3) - **Hedger proactivement pour le hook fact-check** (Session 4) - **BYAN auteur des docs/notes/** (Session 4 - mise a jour cette session) --- ## Comment reprendre la session 1. Ouvrir une session dans `/home/acadenice/corentin_wakdo/` 2. Dire : *"Reprise Wakdo, lis `docs/SESSION_RESUME.md`"* 3. Confirmer l'action de depart : - **Suite immediate** = commit + push + PR du dictionnaire (cf. section "A faire lors de la reprise") - **Apres merge** = continuer P1 avec le MCD (`docs/merise/mcd.md`) --- *Document maintenu a chaque fin de session. Derniere mise a jour : 2026-05-21 (Session 7).*