Files
Lesstime/.claude/skills/ticket-executor/LEARNINGS.md
T
2026-06-19 15:37:03 +02:00

9.1 KiB

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 : \DateTimeImmutableDateTimeImmutable 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