matthieu b495e4030a
Auto Tag Develop / tag (push) Failing after 28s
[ERP-54] Créer les entités Client + sous-entités + référentiels (#29)
## Contexte

Ticket Lesstime **#54** (1.1 / Backend / M) — spec `docs/specs/M1-clients/spec-back.md` § 3.4 / § 3.5.

> 🔗 **MR stackée sur ERP-53** — cible `feature/ERP-53-migrer-tables-client-m1`, **pas** `develop`. À repointer vers `develop` quand ERP-53 sera mergé (cf. `STACK-BRANCHES-PROCEDURE.md`). Le diff ne montre que les fichiers d'ERP-54.

## Contenu

**9 entités** (`src/Module/Commercial/Domain/Entity/`) :
- Métier : `Client`, `ClientContact`, `ClientAddress`, `ClientRib` — `#[Auditable]` + Timestampable/Blamable.
- Référentiels statiques lecture seule : `TvaMode`, `PaymentDelay`, `PaymentType`, `Bank` — whitelistés dans `EntitiesAreTimestampableBlamableTest::EXCLUDED`.

**8 repositories** interfaces (`Domain/Repository/`) + impl Doctrine (`Infrastructure/Doctrine/`).

> La spec § 3.5 ne définit que 8 entités (4 métier + 4 référentiels) ; pas de 9ᵉ entité malgré la formulation « 9 paires » du ticket.

## Décisions

- **Aucun `#[ApiResource]` dans ce ticket** : le bloc ApiResource du `Client` (§ 3.4) référence `ClientProvider`/`ClientProcessor` = périmètre **ERP-55**. L'inclure casserait `cache:clear`/`make test`/`schema:validate`. Les entités sont des entités Doctrine pures (ORM + Assert + Groups). Endpoints lecture seule des référentiels → ticket dédié.
- **Q4** : `Client` sans `#[ORM\UniqueConstraint]` — unicité du nom de société portée par l'index partiel Postgres `uq_client_company_name_active` (inexprimable en attribut ORM).
- **Audit RIB (29/05)** : aucun `#[AuditIgnore]` sur `ClientRib.iban`/`bic` (tous champs audités, audit admin-only).
- **Cross-module (règle n°1)** : M2M `Category` via le contrat `Shared\Domain\Contract\CategoryInterface` + `resolve_target_entities` (pas d'import direct Catalog→Commercial) ; `ClientAddress.sites` via `SiteInterface` existant.

## Infra nécessaire (découvert pendant le dev)

- `doctrine.yaml` : mapping ORM du module `Commercial` (mappings explicites par module) + résolution `CategoryInterface → Category`.
- `CommercialReferentialFixtures` **créée** (n'existait pas — ERP-53 avait seedé les CategoryType côté Catalog) : re-seed idempotent des 4 référentiels, sinon vidés au `db-reset` (désormais tables mappées).
- `ColumnCommentsCatalog` étendu (colonnes M1) pour le chemin `schema:update`/test — sinon `ColumnsHaveSqlCommentTest` (garde-fou n°12) échoue.
- Migration retrofit `Version20260528120000` (ERP-67) rendue résiliente (`$schema->hasTable()`) : elle rejouait tout le catalogue mais s'exécute avant la création des tables M1 → `relation tva_mode does not exist`. Conforme à son docblock (« les futures migrations posent leurs propres COMMENT »).
- `makefile test-db-setup` : recréation de l'index partiel `uq_client_company_name_active` (analogue de la ligne existante pour `category`).

## Vérifications

- `make php-cs-fixer-allow-risky` ✓
- `make db-reset` ✓ (bout en bout ; 4 référentiels + 4 CategoryType présents, 2 index partiels créés)
- `make test` ✓ **312/312** (Architecture vert, 0 régression M0)
- `doctrine:schema:validate` : Mapping **OK** ; « not in sync » = bruit cosmétique pré-existant du projet (clear COMMENT hors-ORM, drop index partiels, renommages d'index). Seul diff introduit : renommage cosmétique de l'index M2M `idx_client_category_category` (même colonne) — aucun écart de type/colonne/FK vs migration ERP-53.

---------

Co-authored-by: admin malio <malio@yuno.malio.fr>
Co-authored-by: Matthieu <contact@malio.fr>
Co-authored-by: Matthieu <mtholot19@gmail.com>
Reviewed-on: #29
Co-authored-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
Co-committed-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
2026-06-01 15:20:22 +00:00
2026-04-07 10:56:57 +02:00
2026-04-07 10:56:57 +02:00
2026-04-07 11:42:56 +02:00
2026-05-19 08:24:19 +02:00
2026-05-19 08:24:19 +02:00
2026-05-19 08:24:19 +02:00

Starseed

CRM/ERP — Symfony 8 (API Platform 4) + Nuxt 4

Stack

  • Backend : PHP 8.4, Symfony 8, API Platform 4, Doctrine ORM, PostgreSQL 16
  • Frontend : Nuxt 4 (SPA), Vue 3, Pinia, Tailwind CSS, @malio/layer-ui
  • Auth : JWT HTTP-only cookie (Lexik)
  • Infra : Docker Compose (dev + prod multi-stage)
  • CI/CD : Gitea Actions (auto-tag + build Docker)

Quick Start

make start           # Demarrer les containers Docker
make install         # Composer, migrations, fixtures, build Nuxt

Dev frontend (hot reload) :

make dev-nuxt        # Port 3003

Ports

Service Port
API (Nginx) 8083
Frontend 3004
PostgreSQL 5437

Commandes

Commande Description
make start Demarrer les containers
make stop Arreter les containers
make restart Redemarrer les containers
make install Install complet
make reset Tout supprimer et reinstaller
make dev-nuxt Serveur dev Nuxt (hot reload)
make shell Shell dans le container PHP
make cache-clear Vider le cache Symfony
make migration-migrate Lancer les migrations
make fixtures Charger les fixtures
make db-reset Reset BDD + migrations + fixtures
make test PHPUnit (tests back)
make nuxt-test Vitest (tests unitaires front)
make test-e2e Playwright (tests E2E front)
make test-e2e-ui Playwright UI interactive (debug)
make seed-e2e Seed les 6 personas E2E
make install-e2e-deps One-time : Chromium + libs systeme (sudo)
make php-cs-fixer-allow-risky Fix code style PHP
make logs-dev Tail logs Symfony

Tests

  • Back : make test (PHPUnit). Fixtures dediees sous tests/Fixtures/.
  • Front unitaire : make nuxt-test (Vitest, happy-dom). Composables, utils, stores — rapide, <30s.
  • Front E2E : make test-e2e (Playwright). Couvre login + matrice RBAC sidebar. Suite volontairement minimaliste (11 tests) — voir la regle d'or dans CLAUDE.md.

Bootstrap E2E (une fois par poste) :

make install-e2e-deps   # Telecharge Chromium + libs systeme via apt (sudo)

Workflow E2E :

# Terminal 1 : containers + dev server
make start && make seed-e2e && make dev-nuxt

# Terminal 2 : tests
make test-e2e

Architecture

Modular Monolith DDD : chaque module est un bounded context autonome, activable/desactivable par tenant. Le backend est la seule source de verite pour l'activation et l'organisation de la sidebar.

  • config/modules.php — liste des modules actifs
  • config/sidebar.php — structure de la sidebar (sections + items avec module owner)
  • GET /api/sidebar — retourne les sections filtrees par les modules actifs + les routes desactivees
  • Frontend : chaque frontend/modules/*/ est auto-detecte comme layer Nuxt, la sidebar est fetchee de l'API

Pour desactiver un module : commenter sa ligne dans config/modules.php, clear cache. Ses items de sidebar disparaissent et ses routes sont bloquees par le middleware front.

Pour reorganiser la sidebar (ex: deplacer un item d'une section a l'autre) : editer config/sidebar.php uniquement, le code des modules n'est pas touche.

Structure

src/                              # Backend Symfony
  Kernel.php
  Shared/                         # Noyau technique partage
    Domain/
      ValueObject/                # Email, ...
      Event/                      # DomainEventInterface
      Contract/                   # Interfaces inter-modules
    Application/
      Bus/                        # CommandBusInterface, QueryBusInterface
    Infrastructure/
      ApiPlatform/
        Resource/                 # AppVersion, ModulesResource, SidebarResource
        State/                    # AppVersionProvider, ModulesProvider, SidebarProvider
  Module/
    Core/                         # Module obligatoire (auth, users)
      CoreModule.php              # Declaration (ID, LABEL, REQUIRED)
      Domain/
        Entity/                   # User
        Repository/               # UserRepositoryInterface
        Event/                    # UserCreated
      Application/
        DTO/                      # UserOutput
      Infrastructure/
        Doctrine/                 # DoctrineUserRepository, Migrations/
        ApiPlatform/State/
          Provider/               # MeProvider
          Processor/              # UserPasswordHasherProcessor
        Console/                  # CreateUserCommand
        DataFixtures/             # AppFixtures
    Commercial/                   # Autre module (exemple)
      CommercialModule.php
config/
  modules.php                     # Source de verite activation
  sidebar.php                     # Source de verite navigation
  version.yaml
  packages/                       # Config Symfony
  jwt/                            # Cles JWT
migrations/                       # Anciennes migrations
frontend/                         # App Nuxt 4 (SPA)
  app/
    layouts/                      # default.vue, auth.vue
    middleware/                   # auth.global.ts, modules.global.ts
  shared/                         # Code partage (hors modules)
    composables/                  # useApi, useAppVersion, useSidebar
    components/ui/                # AppTopNav, ...
    stores/                       # auth, ui
    services/                     # auth
    types/                        # SidebarSection, UserData
    utils/                        # api (Hydra)
  modules/                        # Modules auto-detectes comme layers Nuxt
    core/
      nuxt.config.ts              # Marqueur layer
      pages/                      # index, login, logout
    commercial/
      nuxt.config.ts
      pages/                      # commercial.vue
  app.vue
  nuxt.config.ts                  # Scanne modules/*/ automatiquement
  i18n/locales/                   # Traductions (sidebar.*, etc.)
  assets/                         # CSS, images
  public/                         # Fichiers statiques
infra/
  dev/                            # Docker dev (Dockerfile, nginx, php.ini, xdebug)
  prod/                           # Docker prod (multi-stage, nginx, php-prod.ini)
.gitea/workflows/                 # CI Gitea (auto-tag, build Docker)
.claude/
  skills/create-module/           # Skill Claude Code pour scaffolder un module

CI/CD

  • Auto Tag : push sur develop → bump config/version.yaml → tag vX.Y.Z
  • Build Docker : push tag v* → build image multi-stage → push Gitea Registry

Secrets requis dans Gitea :

  • RELEASE_TOKEN — PAT avec droits write:repository
  • REGISTRY_TOKEN — token pour le registry Docker

Credentials (dev)

Username Password Role
admin admin ROLE_ADMIN
alice alice ROLE_USER
bob bob ROLE_USER

Conventions

Commits

<type>(<scope optionnel>) : <message>

Types : build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test

S
Description
No description provided
Readme 5.1 MiB
Languages
PHP 70.9%
TypeScript 15.5%
Vue 11%
Makefile 1.4%
Dockerfile 0.5%
Other 0.7%