Catalogue
Catalogue
Périmètre : produits (équipements et services), catégories hiérarchiques,
attributs, variantes et modalités de vente (achat, abonnement, location,
service). Le catalogue est la source de vérité pour la tarification et la
configuration des devis/commandes/contrats. À distinguer des Asset (instances
physiques d'un produit).
/workspace/{products,product-categories,product-variants,product-modalities}
et les routes API à plat sous /api/workspace/{products,product-categories,product-variants,product-modalities}
(le préfixe /catalog/ n'existe pas). Source de cette page : docs/12-domain-catalog.md.Vocabulaire & entités
| Terme | Entité | Définition |
|---|---|---|
| Produit | Product | Référence catalogue (modèle, forfait…). Distinct de l'instance physique Asset. |
| Catégorie | ProductCategory | Classification hiérarchique drag-drop pour la navigation. |
| Variante | ProductVariant | Déclinaison d'un produit (taille, couleur, capacité). Hérite du prix parent si non surchargé. |
| Attribut de variante | ProductVariant.attributesJson | Attributs de déclinaison stockés en JSON ({ color: "white", size: "500L" }). Pas d'entité ProductAttribute dédiée. |
| Modalité | ProductSellModality | Façon de vendre/louer : ONE_SHOT, SUBSCRIPTION, LEASE, SERVICE. Un produit peut en avoir plusieurs. |
| Référence (SKU) | Product.reference | Référence interne unique par organisation. ProductVariant porte sa propre sku. |
Le schéma complet est dans
docs/04-data-model.md§5. Le stock est porté parProduct.stockQuantity/stockThreshold; les variantes ont leur propre stock.
Écrans
| Écran | Route | Contenu |
|---|---|---|
| Liste produits | /workspace/products | DataTable : référence, nom, catégorie, prix HT, stock, modalités, statut. Filtres + recherche. |
| Création / édition | /workspace/products/[id|new] | Identité, tarification, stock, catégorie, statut (ACTIVE / ARCHIVED). |
| Catégories | /workspace/product-categories | Liste + création/édition (/new, /[id]). Hiérarchie via position / parentId. |
| Variantes | /workspace/product-variants | Déclinaisons d'un produit (/new, /[id]). |
| Modalités | /workspace/product-modalities | Modalités de vente d'un produit (/new, /[id]). |
| Catalogue client | /client/catalog | (futur) Vue portail client — navigation catégorie, filtres, demande de devis. |
Modèle de données (points clés)
Product.referenceest unique par organisation ; contrainte DB@@unique([organizationId, reference]).ProductVariant.unitPriceHt: si renseigné, prime surProduct.defaultUnitPriceHt; sinon héritage automatique.- Soft delete via
Product.deletedAt— hard delete interdit si le produit est référencé dans un devis, une commande ou une facture. - Stock négatif autorisé (back-order) mais alerte visuelle déclenchée.
ProductSellModalityporte les paramètres propres à chaque type de vente (cf. tableau des modalités ci-dessous).
Types de modalités
| Type | Paramètres principaux |
|---|---|
ONE_SHOT (achat) | Prix HT, TVA, conditions |
SUBSCRIPTION | Prix HT/période, période (mensuel/trimestriel/annuel), durée min d'engagement |
LEASE (location) | Durée min/max (mois), caution éventuelle, conditions LLD/LCD |
SERVICE | Unité (intervention, heure, km), tarif HT/unité |
API
Toutes les routes exigent une permission catalog.product:* (vérifiée côté API et UI).
Les routes sont à plat : aucun préfixe /catalog/. Il n'existe que trois permissions
catalogue : catalog.product:read, catalog.product:create, catalog.product:update
(catégories, variantes et modalités sont gouvernées par ces mêmes permissions).
Produits (products)
| Méthode | Route | Permission |
|---|---|---|
GET | /api/workspace/products | catalog.product:read |
POST | /api/workspace/products | catalog.product:create |
GET | /api/workspace/products/[id] | catalog.product:read |
PATCH | /api/workspace/products/[id] | catalog.product:update |
L'archivage se fait via PATCH /api/workspace/products/[id] avec { "status": "ARCHIVED" }
(il n'existe pas de route /archive dédiée).
Catégories (product-categories)
| Méthode | Route | Permission |
|---|---|---|
GET | /api/workspace/product-categories | catalog.product:read |
POST | /api/workspace/product-categories | catalog.product:update |
GET | /api/workspace/product-categories/[id] | catalog.product:read |
PATCH | /api/workspace/product-categories/[id] | catalog.product:update |
Variantes (product-variants)
| Méthode | Route | Permission |
|---|---|---|
GET | /api/workspace/product-variants | catalog.product:read |
POST | /api/workspace/product-variants | catalog.product:update |
GET | /api/workspace/product-variants/[id] | catalog.product:read |
PATCH | /api/workspace/product-variants/[id] | catalog.product:update |
Modalités (product-modalities)
| Méthode | Route | Permission |
|---|---|---|
GET | /api/workspace/product-modalities | catalog.product:read |
POST | /api/workspace/product-modalities | catalog.product:update |
GET | /api/workspace/product-modalities/[id] | catalog.product:read |
PATCH | /api/workspace/product-modalities/[id] | catalog.product:update |
POST /api/workspace/companies/import), il n'existe aucune route
d'import produits. De même, il n'y a ni route de suppression (DELETE) ni de
réorganisation (reorder) des catégories.Exemple de référence d'endpoint :
/api/workspace/products/[id]Auth Met à jour un produit. Sert aussi à l'archivage en passant status: "ARCHIVED".
Permission catalog.product:update. Audit catalog.product.update.
Corps (partiel)
"ACTIVE" | "ARCHIVED". Un produit ARCHIVED est masqué des sélecteurs de devis/commande.Requête
curl -s -X PATCH "$API/api/workspace/products/$ID" \
-H "Cookie: $SESSION" \
-H "Content-Type: application/json" \
-d '{ "status": "ARCHIVED" }'
Réponse
{ "id": "prd_…", "reference": "REF-99", "status": "ARCHIVED" }
Workflows
Stock & alertes
OrderLine / MaintenanceOperationPart validée
→ décrément Product.stockQuantity
→ si stock ≤ stockThreshold → notification responsable achats
→ (futur) création SupplierQuote pré-remplie (réapprovisionnement)
Archivage produit
PATCH /products/[id] { status: "ARCHIVED" }
├──→ produit masqué dans le sélecteur de devis / commande
└──→ visible en lecture dans l'historique contrats / factures passées
La suppression définitive reste un soft delete (Product.deletedAt), interdite si
le produit est référencé dans un devis, une commande ou une facture.
Règles métier
- Référence (
reference) unique par organisation (contrainte DB). - TVA par défaut (
defaultVatRate) éditable parmi les taux FR : 20 %, 10 %, 5,5 %, 2,1 %, 0 %. - Variante : prix surchargé (
unitPriceHt) prime ; sinon héritage du produit parent. - Suppression hard interdite si produit référencé dans devis, commande ou facture — soft delete uniquement.
- Stock négatif autorisé temporairement (back-order) — alerte visuelle déclenchée, aucun blocage automatique.
- Un produit peut cumuler plusieurs modalités (
ONE_SHOT+LEASEpar exemple).