103 lines
9.1 KiB
Markdown
103 lines
9.1 KiB
Markdown
# Ticket Executor - Learnings
|
|
|
|
## Session 2026-03-17 (26 tickets)
|
|
|
|
### T-001 — Secrets .env
|
|
- **Pattern**: Replace secrets with `change_me_in_env_local` placeholder, move real values to `.env.local`
|
|
- **Gotcha**: `.env.local` must contain ALL overridden secrets
|
|
|
|
### T-002 — Security API Gitea
|
|
- **Pattern**: Ajouter `security: "is_granted('ROLE_USER')"` sur les opérations ApiResource
|
|
- **Learning**: Vérifier d'abord les ressources déjà sécurisées pour ne pas dupliquer
|
|
|
|
### T-003 — SVG Upload
|
|
- **Pattern**: Double protection - bloquer à l'upload (retirer du MIME allowlist) + defense-in-depth (Content-Disposition: attachment au download)
|
|
- **Learning**: Toujours vérifier upload ET download controllers
|
|
|
|
### T-004 — MCP create-task / Repos numérotation
|
|
- **Gotcha critique**: PostgreSQL n'autorise PAS `FOR UPDATE` avec des fonctions d'agrégation (`MAX`)
|
|
- **Fix**: Utiliser `pg_advisory_xact_lock()` au lieu de `FOR UPDATE` pour les queries avec agrégation
|
|
- **Pattern**: Offset les lock keys (+1000000) pour éviter collisions entre Task et ClientTicket
|
|
|
|
### T-005 — Filter ROLE_CLIENT projects
|
|
- **Pattern**: Créer une Doctrine Extension (`QueryCollectionExtensionInterface` + `QueryItemExtensionInterface`) pour filtrer par relation
|
|
- **Learning**: Symfony autoconfigure enregistre l'extension automatiquement
|
|
|
|
### T-006 — Block client doc upload
|
|
- **Pattern**: Vérifier le rôle dans le Processor AVANT de résoudre l'IRI de la tâche
|
|
- **Learning**: Le portail client envoie un `clientTicket` IRI (pas de `task` IRI), donc le check sur `taskIri` non-vide suffit
|
|
|
|
### T-007 — MCP role checks
|
|
- **Pattern**: Injecter `Security` dans chaque Tool, vérifier au début de `__invoke()`
|
|
- **Learning**: 22 tools à modifier - bien séparer ROLE_ADMIN (users/clients) vs ROLE_USER (le reste)
|
|
|
|
### T-009 — Password hashing
|
|
- **Pattern**: Champ `plainPassword` non-persisté, writable uniquement, hashé dans le Processor
|
|
- **Learning**: Modifier aussi le frontend (DTO + composant) quand on renomme un champ API
|
|
|
|
### T-010 — Rate limiting
|
|
- **Gotcha**: `login_throttling` nécessite `symfony/rate-limiter` installé, pas juste dans composer.json
|
|
- **Learning**: Toujours vérifier que les packages sont installés, pas juste déclarés
|
|
|
|
### T-012 — Harmoniser repos numérotation
|
|
- **Pattern**: Aligner les contrats (retourner le max, pas le next) et mettre le +1 côté appelant
|
|
- **Learning**: Vérifier TOUS les appelants d'une méthode renommée
|
|
|
|
### T-015 — useAvatarService
|
|
- **Learning**: Quand on migre vers `useApi()`, ajouter la détection FormData pour ne pas écraser le Content-Type multipart
|
|
|
|
### T-020 — i18n
|
|
- **Pattern**: Ajouter `useI18n()` dans le setup script avant de pouvoir utiliser `t()` dans le JS
|
|
- **Learning**: Les templates peuvent utiliser `$t()` directement sans import
|
|
|
|
### T-022 — Retirer twig-bundle
|
|
- **Pattern**: Retirer de composer.json + bundles.php + supprimer config YAML + templates
|
|
- **Learning**: API Platform ne requiert PAS twig, c'est juste suggéré pour Swagger UI
|
|
|
|
## Session 2026-06-19 (LST-56 / 0.1 — Socle back modular monolith)
|
|
|
|
### Contexte
|
|
- Ticket exécuté via plan TDD dédié (`docs/superpowers/plans/2026-06-19-lst-56-socle-back.md`) délégué à un sous-agent (contexte isolé), pilotage MCP/chrono/vérif depuis la session principale.
|
|
- 4 tâches, 14 nouveaux tests (110 total, 216 assertions, vert), 4 commits (un par tâche).
|
|
|
|
### Patterns
|
|
- **Strangler 100 % additif** : nouveau noyau `src/Shared/` (Domain/Contract, Domain/Module, Domain/Sidebar, Domain/Trait, Application, Infrastructure/{ApiPlatform,Doctrine,Security,Database}) sans toucher au métier — `make test` reste vert sans migration.
|
|
- **Endpoints DTO purs** : logique métier dans classes pures testées unitairement (`ModuleRegistry`, `SidebarFilter`), exposées par Providers API Platform minces (`ModulesProvider`/`SidebarProvider`) sur des Resources DTO.
|
|
- **resolve_target_entities** : contrat `Shared\Domain\Contract\UserInterface` mappé sur `App\Entity\User` (sera re-pointé vers `Module\Core\User` en 1.1). Inert tant qu'aucune entité n'utilise le trait.
|
|
|
|
### Gotchas
|
|
- **API Platform 4 découvre les Resources sous `src/Shared/...` sans config `mapping.paths`** — le 404 anticipé dans le plan ne s'est pas produit, aucun ajout dans `api_platform.yaml` nécessaire.
|
|
- **Hook pre-commit php-cs-fixer** normalise le style du code fourni dans le plan : `\DateTimeImmutable`→`DateTimeImmutable` importé, FQN→`use`, `static::createClient()`→`self::`. Pur style, tests inchangés. Ne pas lutter contre.
|
|
- **`config/reference.php`** : fichier auto-généré qui apparaît modifié dans `git status` — ne jamais le committer.
|
|
|
|
### Time tracking
|
|
- Le sous-agent a stoppé lui-même le timer d'implémentation (id 1005, 35 min) — garder le time-tracking sur la session principale pour rester maître du chrono si un sous-agent a accès aux tools MCP lesstime.
|
|
|
|
## Session 2026-06-19 (LST-62 / 0.2 — Socle front : shell + auto-détection layers Nuxt)
|
|
|
|
### Contexte
|
|
- Plan TDD dédié (`docs/superpowers/plans/2026-06-19-lst-62-socle-front.md`), 7 tasks. Exécution en 3 sous-agents (Task 1 back ; Tasks 2-4 fondations front ; Tasks 5-7 middlewares/layout/i18n), pilotage chrono/MCP/vérif sur la session principale.
|
|
- 7 commits + 1 commit doc de correction du plan. Back : 115 tests verts (110 + 5 nouveaux cas gate rôle).
|
|
|
|
### Patterns
|
|
- **Gate de rôle additif dans la sidebar** : clé `roles` optionnelle sur section/item dans `config/sidebar.php` ; `SidebarFilter::filter($sections, $activeModuleIds, $activeRoles = [])` masque sans polluer `disabledRoutes` (réservé au filtrage par module). `SidebarProvider` injecte `Symfony\Bundle\SecurityBundle\Security` et passe `array_values($user->getRoles())`. ROLE_ADMIN seulement (pas le RBAC fin, qui viendra en 1.1/1.2).
|
|
- **Layout front aligné Starseed** (vérifié dans le code Starseed) : `srcDir: '.'`, `dir.layouts/middleware → app/`, code transverse auto-importé sous `shared/{composables,stores,utils}` via `imports.dirs` EXPLICITE, scan `readdirSync('modules/')` → `extends` + dossiers `modules/*/composables` ajoutés dynamiquement à `imports.dirs`. `useApi`/`auth`/`ui` déplacés par `git mv` (historique préservé) ; `timer.ts`/`mail.ts` restent dans `stores/` (métier non migré).
|
|
- **Singletons module-level** : `useSidebar`/`useModules` portent leur état en `ref` au niveau module ; reset explicite au logout depuis `auth.global.ts` (l'approche Starseed via callback `onAuthSessionCleared()` est une alternative non retenue ici).
|
|
|
|
### Gotchas
|
|
- **`nuxt typecheck` n'est PAS un gate vert sur ce stack** : le baseline Lesstime est rouge (~230 lignes `error TS`) et la RÉFÉRENCE Starseed (même Nuxt 4.3.1, même layout) ship en prod avec **325 erreurs**. Classes structurelles tolérées : `Cannot find name 'ref'/'useApi'/'useRoute'/'navigateTo'/'defineStore'…` dans `shared/` (Nuxt 4 type `shared/` sous un `tsconfig.shared.json` isolé sans les globals d'auto-import, alors que `imports.dirs` les expose au RUNTIME — vérifié dans `.nuxt/imports.d.ts`), erreurs `nuxt.config.ts` (`node:fs`/`process`/`__dirname`, pas de `@types/node`, compilé au runtime par Nuxt), `useApi.ts` 'Property url'. **Le vrai gate** = zéro `Cannot find module '~/shared/…'` (= vrai import cassé) + auto-imports présents dans `.nuxt/imports.d.ts` + smoke runtime. Un sous-agent consciencieux s'est arrêté à tort sur ces erreurs ("bloqueur irréductible") → toujours vérifier le gate contre la réf Starseed avant de conclure à un blocage.
|
|
- **Vérif backend live > typecheck front** : le gate de rôle a été prouvé via curl réel (`/api/login_check` → cookie BEARER → `GET /api/sidebar`) : `alice` (ROLE_USER) n'a que la section générale, `admin` (ROLE_ADMIN) a Administration, non-auth = 401. Plus fiable que le typecheck sur ce stack.
|
|
- **i18n `fr.json`** : une clé racine `sidebar` préexistait (avec un `myTasks` orphelin) → fusionner les sous-namespaces plutôt que dupliquer la clé racine (JSON invalide sinon).
|
|
|
|
### Statut / time tracking
|
|
- Ticket laissé en **"En attente de validation" (4)**, pas "Terminé" : smoke visuel front (dev server + navigateur) et sign-off du **délta cosmétique d'ordre de sidebar** (décision 3 du plan) relèvent du PO. Implémentation + AC API validés.
|
|
- Time-tracking 100 % sur la session principale cette fois (consigne des sous-agents : ne jamais toucher aux outils `mcp__lesstime__*`) — respecté.
|
|
|
|
## Meta-learnings
|
|
- **Parallélisation**: Les tickets touchant des fichiers indépendants peuvent tourner en parallèle sans problème
|
|
- **Commits concurrents**: NE PAS lancer deux sous-agents qui committent sur le même repo en parallèle (collision `.git/index.lock`) — séquencer.
|
|
- **Gate de vérif fourni par le plan**: si un plan fixe un seuil (ex "typecheck 0 erreur"), le confronter à la réalité du projet/réf AVANT de bloquer dessus ; corriger le plan si le seuil est faux.
|
|
- **MCP status**: Toujours mettre "En cours" AVANT de commencer, "Terminé" APRÈS validation
|
|
- **PostgreSQL gotchas**: Tester les queries SQL avec agrégation + locking sur PostgreSQL, pas MySQL
|
|
- **Agents**: Les agents simples (1-3 fichiers) terminent en ~30s, les complexes (22 fichiers) en ~8min
|