Files
Starseed/docs/specs/M5-tickets-pesee/prompts/ERP-181-module-logistique.md
T
Matthieu 312c119c06 feat(logistique) : entité WeighingTicket + dette site.code (ERP-183)
Entité WeighingTicket
- Entité métier complète (#[Auditable], TimestampableBlamableTrait, relations
  ORM Client/Supplier/Site) + contrat de sérialisation à 3 maillons
  (weighing_ticket:read / :item:read + contextes par opération).
- Getters calculés displayDate et plateFreeFormat (#[SerializedName]),
  sécurité view/manage, pas de Delete/archive.
- Validation #[Assert\*] messages FR + #[Assert\Callback] RG-5.03 (->atPath()),
  libellé i18n audit.entity.logistique_weighingticket.
- Repository : interface Domain + DoctrineWeighingTicketRepository
  (recherche + tri number DESC, deletedAt IS NULL).

Dette site.code
- Site.code mappé VARCHAR(8) (groupes read/write), dérivation auto au
  PrePersist (2 premiers chiffres du CP), UniqueConstraint uq_site_code.
- Migration Version20260617160000 : ALTER COLUMN code SET NOT NULL + COMMENT.
- Fixtures (codes 86/17/82) et SiteApiTest ajustés.

Câblage
- doctrine.yaml : mapping ORM du module Logistique (absent du scaffold ERP-181).
- ColumnCommentsCatalog : site.code + table weighing_ticket.

Specs M5 versionnées (spec-back / spec-front / prompts).
2026-06-18 14:37:16 +02:00

2.6 KiB

Prompt d'implémentation — M5 · ERP-181 (1.1) — Scaffolder le module Logistique + RBAC

Projet Starseed (modular monolith DDD). Tâche back. Lis d'abord CLAUDE.md + .claude/rules/architecture.md + .claude/rules/backend.md, puis la spec : docs/specs/M5-tickets-pesee/spec-back.md (§ 2.1, § 5).

Mission

Créer le nouveau module Logistique et poser son socle RBAC, avant toute entité. Aucun écran fonctionnel ici, juste le squelette + permissions + sidebar + 3 miroirs RBAC.

Étapes

  1. Scaffolder via le skill projet create-module : src/Module/Logistique/ avec Domain/ Application/ Infrastructure/ et LogistiqueModule.php :
    • const string ID = 'logistique' ; const string LABEL = 'Logistique' ; const bool REQUIRED = false.
    • permissions() retourne :
      • ['code' => 'logistique.weighing_tickets.view', 'label' => 'Voir les tickets de pesée']
      • ['code' => 'logistique.weighing_tickets.manage', 'label' => 'Créer / modifier les tickets de pesée']
  2. Enregistrer LogistiqueModule::class dans config/modules.php.
  3. Créer le layer front minimal frontend/modules/logistique/nuxt.config.ts (kebab-case, auto-détecté).
  4. Ajouter à config/sidebar.php une section/item « Logistique » :
    ['label' => 'sidebar.logistique.weighing_tickets', 'to' => '/weighing-tickets',
     'icon' => 'mdi-scale', 'module' => 'logistique', 'permission' => 'logistique.weighing_tickets.view'],
    
    • la clé i18n sidebar.logistique.* dans frontend/i18n/locales/fr.json.
  5. Règle ABSOLUE n°8 — 3 miroirs RBAC alignés ensemble :
    • config/sidebar.php (item + permission ci-dessus),
    • frontend/tests/e2e/_fixtures/personas.ts (persona Usine gagne weighing_tickets.view + manage et expectedAdminLinks ; Compta/Commerciale : aucun accès),
    • src/Module/Core/Infrastructure/Console/SeedE2ECommand.php (miroir back du même persona).
  6. make shellphp bin/console app:sync-permissions.

Garde-fous (règles ABSOLUES)

  • declare(strict_types=1); partout ; commentaires en français, code en anglais.
  • Permission au format module.resource.action snake_case.
  • Ne PAS créer d'entité ni de migration ici (ticket 1.2).
  • Pas de hardcode sidebar côté front : elle vient de /api/sidebar.

Vérification

  • make test (les tests Architecture ne cassent pas).
  • make php-cs-fixer-allow-risky.
  • GET /api/modules retourne logistique ; GET /api/sidebar : item présent pour Admin/Bureau/Usine, absent pour Compta/Commerciale.
  • Les 3 miroirs RBAC sont cohérents (sinon test E2E faux positif).