docs(catalog) : M0 categories specs (back + front) #12

Merged
malio merged 4 commits from feature/M0-spec-categories into develop 2026-05-27 09:03:54 +00:00
Owner

Contexte

Premier passage du workflow MALIO sur un module concret. Cette MR introduit uniquement la documentation (2 specs Markdown) du Module 0 — Gestion des catégories. Aucun code applicatif n'est touché.

La spec back a été cadrée sur l'archi DDD réelle de Starseed (cf. .claude/rules/architecture.md + backend.md) après audit du repo (modules Core, Commercial, Sites). Elle introduit aussi un nouveau module Catalog (bounded context "référentiels partagés") — non créé dans cette MR, il viendra avec les tickets de dev.

Contenu

Fichier Lignes Objet
docs/specs/M0-categories/spec-back.md 700 Spec back v1.1 : modèle data, API REST (5 endpoints + CategoryType lecture seule), 13 RG (RG-1.01 → RG-1.13), validation, autorisation, audit, tests, hors-périmètre
docs/specs/M0-categories/spec-front.md 113 Spec front V0 client (validée 2026-05-22) : UI admin (datatable + drawer), 2 champs (Nom + Type), 3 actions (Ajouter / Consulter / Modifier), permissions par rôle

Décisions d'archi (auto-validation back-only)

Toutes les décisions sont documentées dans spec-back.md § 2 :

  • Module Catalog créé séparément de Commercial pour rester réutilisable par les futurs modules Tiers (M-Clients, M-Fournisseurs, M-Prestas)
  • IDs INT IDENTITY (cohérent avec User, Role, etc.)
  • Soft delete via deleted_at TIMESTAMP(0) WITHOUT TIME ZONE NULLpattern introduit par ce module (aucune autre entité Starseed ne le portait)
  • Index unique partiel Postgres sur (LOWER(name), category_type_id) WHERE deleted_at IS NULL → unicité case-insensitive parmi non soft-deleted, recréation possible après suppression logique
  • Granularité permissions = view + manage (aligné sur core.users.view + core.users.manage)
  • Référentiel CategoryType = entité séparée, table vide à la livraison, valeurs seedées plus tard (HP-1)

Règles métier (RG-1.01 → RG-1.13)

Chaque RG est numérotée, stable, testable, et constituera un critère d'acceptation côté ticket Lesstime (cf. spec-back.md § 7).

Couverture par catégorie :

  • Autorisation : RG-1.01 (Admin only)
  • Champ name : RG-1.02 (obligatoire), RG-1.03 (trim), RG-1.04 (longueur 2-120)
  • Champ categoryType : RG-1.05 (obligatoire), RG-1.06 (référence valide)
  • Unicité : RG-1.07 (case-insensitive sur couple, hors soft-deleted)
  • Liste : RG-1.08 (exclut soft-deleted), RG-1.09 (flag ?includeDeleted=true), RG-1.10 (tri name ASC)
  • Détail : RG-1.11 (404 si soft-deleted)
  • Suppression : RG-1.12 (soft delete), RG-1.13 (deletedAt non modifiable via PATCH)

Découpe en tickets Lesstime

TaskGroup #22 — M0 — Gestion des catégories créé sur le projet STARSEED. 9 tickets en backlog :

# Ticket Lesstime Effort Tag
0.1 #43 Migrer les tables Category et CategoryType S Backend
0.2 #44 Créer les entités Category et CategoryType M Backend
0.3 #45 Implémenter Provider et Processor Category M Backend
0.4 #46 Exposer le référentiel CategoryType en lecture seule S Backend
0.5 #47 Déclarer le module Catalog et synchroniser RBAC S Backend
0.6 #48 Écrire les tests PHPUnit RG-1.01 à RG-1.13 M Backend
0.7 #49 Créer la page Gestion des catégories (datatable + drawer) L Frontend
0.8 #50 Implémenter les composables useCategoriesAdmin et useCategoryForm M Frontend
0.9 #51 Écrire les tests Vitest des composables Catalog S Frontend

Total estimé : ~15-25h (9 mini-MR de 1-4h).

Hors-périmètre (HP)

Pas codés / pas inclus dans cette spec (cf. spec-back.md § 9) :

  • HP-1 : CRUD du référentiel CategoryType (spec dédiée à venir)
  • HP-2 : Référencement par les Tiers (les FK category_id sur Clients/Fournisseurs/Prestas viendront avec leurs modules)
  • HP-3 : Restauration d'une catégorie soft-deleted
  • HP-4 : Hard delete
  • HP-5 : i18n du name
  • HP-6 : Recherche serveur / filtres avancés
  • HP-7 : Catégories hiérarchiques (parent / enfant)
  • HP-8 : Seed des rôles métier Bureau / Compta / Commerciale / Usine

Checklist review

Pas de code → review légère, lecture des 2 .md suffit.

  • Frontmatter YAML cohérent (module, version, dates, validation client, taskgroup, tags)
  • Décisions d'archi argumentées (spec-back.md § 2)
  • Modèle data réaliste (SQL Postgres rédigé directement, pas de pseudo-code)
  • API REST complète (codes HTTP succès + erreurs, payloads, exemples)
  • RG numérotées et testables (un humain peut écrire un test PHPUnit à partir de chaque RG sans réinventer)
  • Mapping rôles MALIO ↔ permissions RBAC clair (cohérent avec règle ABSOLUE n°8 — 3 sources à toucher)
  • Hors-périmètre explicite

Stratégie de merge

Squash merge vers develop (1 PR = 1 commit propre dans l'historique).

Lien Lesstime

  • TaskGroup : #22 — M0 — Gestion des catégories (projet ERP / Starseed)
  • Tickets en backlog : #43#51

⚠️ À faire manuellement après merge dans l'UI Lesstime : rattacher les 9 tickets au groupe #22 et leur poser leur effort + tag + priorité (bug typing MCP empêche le wire automatique sur des champs integer sans type explicite dans le schéma).

## Contexte Premier passage du workflow MALIO sur un module concret. Cette MR introduit **uniquement la documentation** (2 specs Markdown) du **Module 0 — Gestion des catégories**. Aucun code applicatif n'est touché. La spec back a été cadrée sur l'archi DDD réelle de Starseed (cf. `.claude/rules/architecture.md` + `backend.md`) après audit du repo (modules `Core`, `Commercial`, `Sites`). Elle introduit aussi un **nouveau module `Catalog`** (bounded context "référentiels partagés") — non créé dans cette MR, il viendra avec les tickets de dev. ## Contenu | Fichier | Lignes | Objet | |---|---|---| | `docs/specs/M0-categories/spec-back.md` | 700 | Spec back v1.1 : modèle data, API REST (5 endpoints + CategoryType lecture seule), 13 RG (RG-1.01 → RG-1.13), validation, autorisation, audit, tests, hors-périmètre | | `docs/specs/M0-categories/spec-front.md` | 113 | Spec front V0 client (validée 2026-05-22) : UI admin (datatable + drawer), 2 champs (Nom + Type), 3 actions (Ajouter / Consulter / Modifier), permissions par rôle | ## Décisions d'archi (auto-validation back-only) Toutes les décisions sont documentées dans `spec-back.md § 2` : - **Module `Catalog`** créé séparément de `Commercial` pour rester réutilisable par les futurs modules Tiers (M-Clients, M-Fournisseurs, M-Prestas) - **IDs INT IDENTITY** (cohérent avec `User`, `Role`, etc.) - **Soft delete** via `deleted_at TIMESTAMP(0) WITHOUT TIME ZONE NULL` — *pattern introduit par ce module* (aucune autre entité Starseed ne le portait) - **Index unique partiel Postgres** sur `(LOWER(name), category_type_id) WHERE deleted_at IS NULL` → unicité case-insensitive parmi non soft-deleted, recréation possible après suppression logique - **Granularité permissions = `view` + `manage`** (aligné sur `core.users.view` + `core.users.manage`) - **Référentiel `CategoryType`** = entité séparée, table vide à la livraison, valeurs seedées plus tard (HP-1) ## Règles métier (RG-1.01 → RG-1.13) Chaque RG est numérotée, stable, testable, et constituera un critère d'acceptation côté ticket Lesstime (cf. `spec-back.md § 7`). Couverture par catégorie : - Autorisation : RG-1.01 (Admin only) - Champ `name` : RG-1.02 (obligatoire), RG-1.03 (trim), RG-1.04 (longueur 2-120) - Champ `categoryType` : RG-1.05 (obligatoire), RG-1.06 (référence valide) - Unicité : RG-1.07 (case-insensitive sur couple, hors soft-deleted) - Liste : RG-1.08 (exclut soft-deleted), RG-1.09 (flag `?includeDeleted=true`), RG-1.10 (tri `name ASC`) - Détail : RG-1.11 (404 si soft-deleted) - Suppression : RG-1.12 (soft delete), RG-1.13 (`deletedAt` non modifiable via PATCH) ## Découpe en tickets Lesstime TaskGroup `#22 — M0 — Gestion des catégories` créé sur le projet **STARSEED**. 9 tickets en backlog : | # | Ticket Lesstime | Effort | Tag | |---|---|---|---| | 0.1 | `#43` Migrer les tables Category et CategoryType | S | Backend | | 0.2 | `#44` Créer les entités Category et CategoryType | M | Backend | | 0.3 | `#45` Implémenter Provider et Processor Category | M | Backend | | 0.4 | `#46` Exposer le référentiel CategoryType en lecture seule | S | Backend | | 0.5 | `#47` Déclarer le module Catalog et synchroniser RBAC | S | Backend | | 0.6 | `#48` Écrire les tests PHPUnit RG-1.01 à RG-1.13 | M | Backend | | 0.7 | `#49` Créer la page Gestion des catégories (datatable + drawer) | L | Frontend | | 0.8 | `#50` Implémenter les composables useCategoriesAdmin et useCategoryForm | M | Frontend | | 0.9 | `#51` Écrire les tests Vitest des composables Catalog | S | Frontend | **Total estimé** : ~15-25h (9 mini-MR de 1-4h). ## Hors-périmètre (HP) Pas codés / pas inclus dans cette spec (cf. `spec-back.md § 9`) : - HP-1 : CRUD du référentiel `CategoryType` (spec dédiée à venir) - HP-2 : Référencement par les Tiers (les FK `category_id` sur Clients/Fournisseurs/Prestas viendront avec leurs modules) - HP-3 : Restauration d'une catégorie soft-deleted - HP-4 : Hard delete - HP-5 : i18n du `name` - HP-6 : Recherche serveur / filtres avancés - HP-7 : Catégories hiérarchiques (parent / enfant) - HP-8 : Seed des rôles métier Bureau / Compta / Commerciale / Usine ## Checklist review Pas de code → review légère, lecture des 2 `.md` suffit. - [ ] Frontmatter YAML cohérent (module, version, dates, validation client, taskgroup, tags) - [ ] Décisions d'archi argumentées (`spec-back.md § 2`) - [ ] Modèle data réaliste (SQL Postgres rédigé directement, pas de pseudo-code) - [ ] API REST complète (codes HTTP succès + erreurs, payloads, exemples) - [ ] RG numérotées et testables (un humain peut écrire un test PHPUnit à partir de chaque RG sans réinventer) - [ ] Mapping rôles MALIO ↔ permissions RBAC clair (cohérent avec règle ABSOLUE n°8 — 3 sources à toucher) - [ ] Hors-périmètre explicite ## Stratégie de merge **Squash merge** vers `develop` (1 PR = 1 commit propre dans l'historique). ## Lien Lesstime - TaskGroup : `#22 — M0 — Gestion des catégories` (projet ERP / Starseed) - Tickets en backlog : `#43` → `#51` > ⚠️ **À faire manuellement après merge** dans l'UI Lesstime : rattacher les 9 tickets au groupe #22 et leur poser leur effort + tag + priorité (bug typing MCP empêche le wire automatique sur des champs `integer` sans `type` explicite dans le schéma).
matthieu added 1 commit 2026-05-26 13:24:35 +00:00
docs(catalog) : add M0 categories specs (back + front)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 2m18s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 10m11s
3c9eaf5d69
matthieu requested review from tristan 2026-05-26 13:49:40 +00:00
tristan reviewed 2026-05-26 13:58:51 +00:00
@@ -0,0 +91,4 @@
CoreModule::class,
CommercialModule::class,
SitesModule::class,
CatalogModule::class, // ← AJOUTÉ
Owner

A voir. Comment on fait si le module est désactivé sachant que pour créer un client il est requis de sélectionner une catégorie.

A voir. Comment on fait si le module est désactivé sachant que pour créer un client il est requis de sélectionner une catégorie.
tristan reviewed 2026-05-26 14:04:07 +00:00
@@ -0,0 +547,4 @@
**Aucun code custom à écrire côté M0.** Il suffit que `Category` porte `#[Auditable]`. Le soft delete (UPDATE `deleted_at`) est tracé comme un UPDATE normal.
### 6.2 Pas de colonnes `created_by` / `updated_by` / `created_at` / `updated_at` sur `category`
Owner

Si il faut au moins les colonnes created_at et updated_at

Si il faut au moins les colonnes created_at et updated_at
tristan approved these changes 2026-05-26 14:07:26 +00:00
matthieu added 2 commits 2026-05-26 14:28:32 +00:00
docs(catalog) : mark CatalogModule REQUIRED=true after Tristan review #12
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 1m35s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 10m13s
e4b8df105e
Author
Owner

Réponse au commentaire #1255« Comment on fait si le module est désactivé sachant que pour créer un client il est requis de sélectionner une catégorie. »

Bonne question. Réponse v1.2 : CatalogModule::REQUIRED = true.

Comme la FK category_id sera NOT NULL côté Client (et Fournisseur, Prestataire — confirmé via la maquette de création client), désactiver Catalog ferait casser tout le métier au boot Doctrine. Donc on aligne sur le pattern de CoreModule : module obligatoire, impossible de le commenter dans config/modules.php sans casser l'app.

→ Commit e4b8df1 : REQUIRED = true + commentaire dans le code qui cite explicitement cette question.

Bonus pour la cohérence : Category est exposée aux autres modules via Shared/Domain/Contract/CategoryInterface.php (pattern Sites existant, résolution Doctrine via resolve_target_entities). Aucun import direct cross-module, on respecte la règle ABSOLUE n°1.

Cf. spec-back.md § 2.1 (module + REQUIRED) et § 2.3 (FK des Tiers).

> Réponse au commentaire #1255 — *« Comment on fait si le module est désactivé sachant que pour créer un client il est requis de sélectionner une catégorie. »* Bonne question. Réponse v1.2 : `CatalogModule::REQUIRED = true`. Comme la FK `category_id` sera **NOT NULL** côté Client (et Fournisseur, Prestataire — confirmé via la maquette de création client), désactiver Catalog ferait casser tout le métier au boot Doctrine. Donc on aligne sur le pattern de `CoreModule` : module obligatoire, impossible de le commenter dans `config/modules.php` sans casser l'app. → Commit [`e4b8df1`](https://gitea.malio.fr/MALIO-DEV/Starseed/commit/e4b8df1) : `REQUIRED = true` + commentaire dans le code qui cite explicitement cette question. Bonus pour la cohérence : `Category` est exposée aux autres modules via `Shared/Domain/Contract/CategoryInterface.php` (pattern Sites existant, résolution Doctrine via `resolve_target_entities`). Aucun import direct cross-module, on respecte la règle ABSOLUE n°1. Cf. spec-back.md § 2.1 (module + REQUIRED) et § 2.3 (FK des Tiers).
Author
Owner

Réponse au commentaire #1257« Si il faut au moins les colonnes created_at et updated_at »

Tu as raison. Spec v1.2 ajoute non pas 2 mais les 4 colonnes automatisées par un pattern Shared (pour ne pas avoir à le redécider à chaque entité).

Ce qui change :

  • Nouveau pattern dans src/Shared/ (Trait + Interfaces + Subscriber Doctrine prePersist/preUpdate) qui remplit created_at, updated_at, created_by, updated_by automatiquement pour toute entité métier qui use TimestampableBlamableTrait; + implements TimestampableInterface, BlamableInterface.
  • created_at / updated_at : NOT NULL, remplis systématiquement par le Subscriber.
  • created_by / updated_by : FK nullable vers user (ON DELETE SET NULL) — permet créations CLI/cron sans user en session, affiché « Système » côté front si null.
  • Côté entité Category : 3 lignes à ajouter (1 use Trait, 2 implements), pas de redéclaration manuelle des props.

Garde-fou pour pas oublier sur les futures entités : test PHPUnit d'architecture (tests/Architecture/EntitiesAreTimestampableBlamableTest) qui scanne src/Module/*/Domain/Entity/ et fait échouer la CI si une entité métier n'implémente pas les 2 interfaces. Whitelist explicite (EXCLUDED) pour les référentiels statiques type CategoryType qui n'ont pas besoin de traçabilité.

→ Commit 723a220 : pattern complet + 3 RG ajoutées (RG-1.15, RG-1.16, RG-1.17).

Lecture : spec-back.md § 2.5 (vue d'ensemble audit + dates), § 2.8 (pattern Shared), § 2.8.bis (garde-fous architecture), § 6 (réécrite), RG-1.15 / 1.16 / 1.17 dans § 7.

Ticket Lesstime dédié au pattern Shared : #52 (0.0) — prérequis du M0 et de tous les futurs modules métier.

> Réponse au commentaire #1257 — *« Si il faut au moins les colonnes created_at et updated_at »* Tu as raison. Spec v1.2 ajoute non pas 2 mais **les 4 colonnes** automatisées par un pattern Shared (pour ne pas avoir à le redécider à chaque entité). **Ce qui change :** - Nouveau pattern dans `src/Shared/` (Trait + Interfaces + Subscriber Doctrine `prePersist`/`preUpdate`) qui remplit `created_at`, `updated_at`, `created_by`, `updated_by` automatiquement pour toute entité métier qui `use TimestampableBlamableTrait;` + `implements TimestampableInterface, BlamableInterface`. - `created_at` / `updated_at` : NOT NULL, remplis systématiquement par le Subscriber. - `created_by` / `updated_by` : FK nullable vers `user` (`ON DELETE SET NULL`) — permet créations CLI/cron sans user en session, affiché « Système » côté front si null. - Côté entité Category : 3 lignes à ajouter (1 `use Trait`, 2 `implements`), pas de redéclaration manuelle des props. **Garde-fou pour pas oublier sur les futures entités** : test PHPUnit d'architecture (`tests/Architecture/EntitiesAreTimestampableBlamableTest`) qui scanne `src/Module/*/Domain/Entity/` et fait échouer la CI si une entité métier n'implémente pas les 2 interfaces. Whitelist explicite (`EXCLUDED`) pour les référentiels statiques type `CategoryType` qui n'ont pas besoin de traçabilité. → Commit [`723a220`](https://gitea.malio.fr/MALIO-DEV/Starseed/commit/723a220) : pattern complet + 3 RG ajoutées (RG-1.15, RG-1.16, RG-1.17). Lecture : spec-back.md § 2.5 (vue d'ensemble audit + dates), § 2.8 (pattern Shared), § 2.8.bis (garde-fous architecture), § 6 (réécrite), RG-1.15 / 1.16 / 1.17 dans § 7. Ticket Lesstime dédié au pattern Shared : **#52 (0.0)** — prérequis du M0 et de tous les futurs modules métier.
matthieu added 1 commit 2026-05-27 09:03:05 +00:00
docs(catalog) : add ticket 0.0 (Timestampable+Blamable Shared) to tickets table
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 1m36s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 10m12s
4195ed899d
malio merged commit 5db644d22e into develop 2026-05-27 09:03:54 +00:00
malio deleted branch feature/M0-spec-categories 2026-05-27 09:03:55 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: MALIO-DEV/Starseed#12