1623 lines
94 KiB
Markdown
Executable file
1623 lines
94 KiB
Markdown
Executable file
# 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_<id>`) + 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 (`<title>Wakdo - Bienvenue</title>`), 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 `<a>`) gardait `aria-disabled="true"` car
|
||
`.disabled` est un no-op sur un `<a>` -> 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 <service>` 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<low`) ; `stock_movement` append-only (`sale`/`cancellation`/`restock`/`inventory_correction`).
|
||
- **Permissions** : `ingredient.manage` + `stock.manage` = admin+manager ; `stock.count` + `stock.read` = tous les roles.
|
||
- **A LA REPRISE** : dire **"go PR-A"** -> 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\<Entite>Repository` (DatabaseInterface) : requetes preparees, unicite.
|
||
2. `<Entite>Controller extends AdminController` : par action -> `guard(<permission>)` -> (mutation :
|
||
`Csrf::validate`) -> validation serveur + allowlist -> repo -> redirect + `setFlash`, ou re-rendu 422.
|
||
3. Vues `admin/<entite>/{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/<ressource>` 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 `<img src="_diagrams/*.svg">`
|
||
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 <branch-tip-sha> -m "abandoned: <reason>"
|
||
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).*
|