Compare commits

..

2 Commits

Author SHA1 Message Date
gitea-actions 43d80df1e1 chore: bump version to v0.1.40
Auto Tag Develop / tag (push) Successful in 7s
Build & Push Docker Image / build (push) Successful in 27s
2026-05-27 09:15:00 +00:00
matthieu 5db644d22e docs(catalog) : M0 categories specs (back + front) (#12)
Auto Tag Develop / tag (push) Successful in 10s
## 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).

---------

Co-authored-by: Matthieu Tholot <mtholot19@gmail.com>
Reviewed-on: #12
Reviewed-by: Autin <tristan@yuno.malio.fr>
Co-authored-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
Co-committed-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
2026-05-27 09:03:54 +00:00
3 changed files with 1156 additions and 1 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
parameters:
app.version: '0.1.39'
app.version: '0.1.40'
File diff suppressed because it is too large Load Diff
+113
View File
@@ -0,0 +1,113 @@
---
# === IDENTITÉ ===
module: M0
nom: "Gestion des catégories"
ecran: gestion-categories
owner_spec: Matthieu
backup_spec: Tristan
version: V0
date_redaction: 2026-05-22
# === LIENS ===
maquette_figma: null # pas de Figma — UI admin standard
regles_metier: [RG-1.01, RG-1.02, RG-1.03, RG-1.04, RG-1.05, RG-1.06, RG-1.07, RG-1.08, RG-1.09, RG-1.10, RG-1.11, RG-1.12, RG-1.13]
roles: [Admin, Bureau, Compta, Commerciale, Usine]
lien_spec_back: ./spec-back.md
# === VALIDATION CLIENT #1 ===
client_validation_1:
statut: validee # V0 client validée le 22/05/2026
date: 2026-05-22
canal: ecrit
valide_par: "Matthieu (CP MALIO) — validation implicite, périmètre projet"
resume: "Module 0 — Gestion des catégories. Page admin (datatable + drawer). 2 champs (Nom + Type), 3 actions (Ajouter / Consulter / Modifier). Admin only."
trace_archivee: "uploads/c4ebb6b4-M0categories.docx (V0 d'origine .docx) — restitué ci-dessous en Markdown."
# === LIEN LESSTIME ===
lesstime_taskgroup_id: 22
lesstime_project_id: 6 # ERP / Starseed
statut_global: en_dev # tickets créés en backlog Lesstime le 2026-05-26
---
# Module 0 — Gestion des catégories (V0 front)
> **Origine** : spec front V0 livrée le 22/05/2026 (`c4ebb6b4-M0categories.docx` + `f665acfb-M0categoriesV0.pdf`). Restitution Markdown fidèle pour intégration au workflow MALIO. Le contenu original n'est pas modifié — toute reformulation et précision (en particulier côté back) vit dans [`spec-back.md`](./spec-back.md).
## But
Permettre à un administrateur Starseed de gérer un référentiel de **catégories** depuis l'interface admin du logiciel. Ces catégories seront utilisées plus tard pour classifier les tiers (clients, fournisseurs, prestataires).
## Accès
- **Depuis** : menu principal → **Administration** → entrée « Gestion des catégories »
- **Rôles autorisés** : **Admin uniquement** (Bureau / Compta / Commerciale / Usine n'ont **aucun** accès, ni lecture ni écriture).
## Navigation
L'écran est la page d'entrée du Module **Administration**. Titre de la page : « **Gestion des catégories** ».
- Affichage principal : un **datatable** listant toutes les catégories existantes.
- **Clic sur une ligne** → ouverture d'un **drawer** latéral en mode **consultation / modification** (cf. § Action « Consulter »).
- **Bouton « + Ajouter »** (en haut à droite du datatable) → ouverture d'un **drawer** en mode **création** (cf. § Action « Ajouter »).
- Pas d'onglet, pas de pagination explicite (volumétrie cible faible).
## Actions
| Action | Déclencheur | Comportement |
|---|---|---|
| **Ajouter** | Clic sur le bouton « + Ajouter » | Ouvre le drawer en mode création, formulaire vide. Validation → POST → la catégorie apparaît dans le datatable. |
| **Consulter** | Clic sur une ligne du datatable | Ouvre le drawer avec les champs pré-remplis en lecture (et passage en édition si l'utilisateur modifie un champ). |
| **Modifier** | Modification d'un champ dans le drawer ouvert en consultation | Validation → PATCH → la ligne du datatable se met à jour. |
> **Note V0** : la **suppression** n'était pas mentionnée dans la V0 client. Côté workflow MALIO, suite à la revue back (cf. `spec-back.md` § Q3), un soft delete est ajouté (corbeille logique). L'UI peut intégrer ce point lors d'une V1 — au M0 le bouton « Supprimer » n'est pas obligatoire, mais doit être facilement ajoutable.
## Formulaire — Champs
Le formulaire (drawer) contient **2 champs**, tous deux obligatoires :
| Champ | Type | Obligatoire | Contenu / valeur par défaut | Règle |
|---|---|---|---|---|
| **Nom** | Texte libre | **Oui** | vide à la création | Pas de règle métier détaillée en V0. Détails côté back : RG-1.02 / RG-1.03 / RG-1.04 (obligatoire, trim, longueur 2120). |
| **Type de catégorie** | Select | **Oui** | vide à la création | Le contenu du Select n'était pas précisé en V0. Décision back : entité de référence `CategoryType` séparée (RG-1.05 / RG-1.06). Le référentiel sera alimenté plus tard (cf. HP-1 dans `spec-back.md`). |
> **Note V0** : la V0 ne précisait ni si le `Type de catégorie` est un enum hardcodé ni si c'est une autre entité. Décision tranchée côté back avant découpe en tickets : **entité de référence** (`category_types`), table créée vide au M0.
## Permissions par rôle
| Rôle | Vue (`GET`) | Création (`POST`) | Édition (`PATCH`) | Suppression (`DELETE`) |
|---|---|---|---|---|
| **Admin** | ✅ | ✅ | ✅ | ✅ (soft delete — ajout post-V0) |
| Bureau | ❌ | ❌ | ❌ | ❌ |
| Compta | ❌ | ❌ | ❌ | ❌ |
| Commerciale | ❌ | ❌ | ❌ | ❌ |
| Usine | ❌ | ❌ | ❌ | ❌ |
→ Les rôles non-Admin ne voient **pas** l'entrée de menu et reçoivent **403** sur toute requête vers les endpoints `/api/categories/*` (cf. RG-1.01 dans `spec-back.md`).
## Composants UI à utiliser (Starseed / `@malio/layer-ui`)
- **Datatable** : `<MalioDataTable>` (avec colonnes `Nom` + `Type` + actions, tri par défaut sur Nom).
- **Drawer** : drawer latéral standard `@malio/layer-ui` (à confirmer côté front avec le composant exact).
- **Input texte** : `<MalioInputText>` pour le champ Nom.
- **Select** : `<MalioSelect>` pour le champ Type de catégorie, alimenté par `GET /api/category_types`.
- **Bouton** : `<MalioButton>` (« + Ajouter », « Enregistrer », « Annuler »).
- **Toasts succès / erreur** : standards via `useApi()`.
## Points laissés ouverts par la V0 (résolus côté back)
| # | Zone d'ombre V0 | Résolution (cf. `spec-back.md`) |
|---|---|---|
| 1 | Suppression non mentionnée | **Soft delete** ajouté (RG-1.12 + RG-1.13). UI peut ajouter le bouton plus tard. |
| 2 | Unicité du nom non précisée | **Unicité sur `(name, type)` case-insensitive**, parmi non-soft-deleted (RG-1.07). |
| 3 | Nature du `Type de catégorie` (enum vs entité) | **Entité de référence** `CategoryType` (table vide au M0, créée par migration). |
| 4 | Volumétrie & pagination | **300 max** → pagination front (`<MalioDataTable>`), pas de pagination serveur. Tri serveur `name ASC` par défaut. |
| 5 | Audit / traçabilité | Pattern `#[Auditable]` Starseed standard. Trace dans la table `audit_log` (qui / quoi / quand / diff). **Pas** de colonnes `created_by` / `updated_by` sur l'entité (cohérent avec User / Role dans Starseed). Historique consultable via `/api/audit-log?entityType=Category&entityId={id}`. |
| 6 | Référencement par d'autres entités | **Aucune FK entrante au M0.** Les modules Tiers (M-Clients / M-Fournisseurs / M-Prestas) ajouteront leur propre `category_id` plus tard. |
---
## 📦 Tickets Lesstime générés
**TaskGroup Lesstime** : `#22 — M0 — Gestion des catégories` (projet `ERP / Starseed`, projectId=6)
> Détail complet, table des tickets et action manuelle dans Lesstime → voir [`spec-back.md § Tickets Lesstime générés`](./spec-back.md#-tickets-lesstime-générés).