P1 conception: security-by-design layer (Merise 21 entities, Forgejo CI/CD, hardening) #3
4 changed files with 622 additions and 287 deletions
232
docs/uml/security-sequence.md
Normal file
232
docs/uml/security-sequence.md
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
# Diagramme de sequence securite - Annulation de commande avec PIN (CANCEL_ORDER)
|
||||
|
||||
**Phase UML** : P1 - Conception, complement UML (passe security-by-design)
|
||||
**Statut** : v0.2 - flux sensible PIN-gate + audit_log (controle anti-fraude interne)
|
||||
**Date** : 2026-06-12
|
||||
**Branche** : `feat/p1-conception`
|
||||
**Auteur methodologie** : BYAN
|
||||
|
||||
---
|
||||
|
||||
## 1. Objet du document
|
||||
|
||||
Ce document decrit le **flux temporel securise** de l'annulation d'une commande
|
||||
en back-office (`CANCEL_ORDER`). L'annulation est une action de **manipulation
|
||||
d'argent** : annuler une commande deja `paid` peut servir a masquer un
|
||||
detournement d'especes (l'equipier encaisse, annule, garde le cash). Le flux
|
||||
ci-dessous materialise le controle qui adresse ce risque : une **re-authentification
|
||||
par PIN par equipier** (`RG-T13`) avant l'execution, et l'ecriture d'une ligne
|
||||
**`audit_log` immuable** dans la meme transaction que l'effet (`RG-T14`), de sorte
|
||||
que chaque annulation est rattachee a une personne meme sur un poste partage.
|
||||
|
||||
Le diagramme reste au niveau conceptuel / logique. Il nomme les echanges entre
|
||||
participants sans detailler l'implementation PHP ni le SQL exact. Il complete
|
||||
l'operation `CANCEL_ORDER` du `docs/merise/mlt.md` (7.1), la transition T5 de
|
||||
`docs/uml/state-commande.md` (`paid -> cancelled`, re-credit du stock) et le cas
|
||||
d'utilisation "Annuler une commande" de `docs/uml/use-cases.md` (UC13).
|
||||
|
||||
**Sources** :
|
||||
- `docs/merise/mlt.md` 7.1 `CANCEL_ORDER` (PRE-1..PRE-3, RG-1..RG-6, POST, ERR)
|
||||
- `docs/merise/mlt.md` section 2 : `RG-T13` (PIN sensible), `RG-T14` (audit_log), `RG-T11` (re-credit dans la meme transaction), `RG-T07` (garde de concurrence), `RG-T08` (transaction atomique)
|
||||
- `docs/merise/dictionary.md` 3.14 (`user.pin_hash`, argon2id) et 3.20 (`audit_log`)
|
||||
- `docs/uml/state-commande.md` T5 (`paid -> cancelled`, `stock_movement` type `cancellation`)
|
||||
|
||||
---
|
||||
|
||||
## 2. Participants
|
||||
|
||||
| Participant | Role | Couche |
|
||||
|---|---|---|
|
||||
| **Equipier** | Counter / Drive / Admin titulaire de `order.cancel`, sur poste partage | Acteur |
|
||||
| **Admin UI** | Interface back-office (Bloc 3, formulaire d'annulation + saisie PIN) | Presentation |
|
||||
| **Controleur** | Back-end REST sous `/api/*` (Bloc 2), orchestre la transaction | Application |
|
||||
| **Verif PIN** | Service de verification du PIN (`password_verify` argon2id) | Application |
|
||||
| **BDD** | Base de donnees MariaDB | Persistance |
|
||||
|
||||
La session est **partagee par poste de travail** pour le routine 95% ; le PIN
|
||||
re-introduit une attribution individuelle sur le sous-ensemble sensible
|
||||
(`mlt.md` `RG-T13`). Le PIN n'est pas une session : il est verifie a chaque action
|
||||
sensible et sert a capturer le `user_id` qui sera ecrit dans `audit_log`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Diagramme de sequence
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
actor Equipier
|
||||
participant AdminUI as Admin UI
|
||||
participant Ctrl as Controleur
|
||||
participant PIN as Verif PIN
|
||||
participant BDD
|
||||
|
||||
Note over Equipier,BDD: Phase 1 - Demande et controle de permission
|
||||
|
||||
Equipier->>AdminUI: demander l'annulation d'une commande
|
||||
AdminUI->>Ctrl: POST /api/orders/{id}/cancel
|
||||
Ctrl->>Ctrl: verifier session active + is_active = 1 (RG-T02)
|
||||
Ctrl->>BDD: lire role_permission (permission order.cancel ?) (RG-T03, PRE-1)
|
||||
BDD-->>Ctrl: permission presente
|
||||
Ctrl->>BDD: lire customer_order (existe ? statut ?) (PRE-2, PRE-3)
|
||||
BDD-->>Ctrl: status courant
|
||||
|
||||
alt status hors ['pending_payment','paid'] (delivered ou cancelled)
|
||||
Ctrl-->>AdminUI: 422 CANNOT_CANCEL_IN_STATE {current_status}
|
||||
AdminUI-->>Equipier: refus, aucun changement d'etat (ERR-1)
|
||||
else status annulable
|
||||
Note over Equipier,BDD: Phase 2 - Re-authentification PIN (RG-T13)
|
||||
|
||||
Ctrl-->>AdminUI: demander la saisie du PIN
|
||||
Equipier->>AdminUI: saisir le PIN
|
||||
AdminUI->>Ctrl: soumettre le PIN (re-auth action sensible)
|
||||
Ctrl->>PIN: verifier le PIN soumis
|
||||
PIN->>BDD: lire user.pin_hash de l'equipier
|
||||
BDD-->>PIN: pin_hash (argon2id)
|
||||
PIN->>PIN: password_verify(pin, pin_hash)
|
||||
|
||||
alt PIN incorrect
|
||||
PIN-->>Ctrl: echec
|
||||
Ctrl-->>AdminUI: refus du PIN, action rejetee
|
||||
AdminUI-->>Equipier: PIN incorrect, aucun changement d'etat
|
||||
else PIN correct
|
||||
PIN-->>Ctrl: succes, acting user_id capture (RG-T13)
|
||||
|
||||
Note over Equipier,BDD: Phase 3 - Transaction atomique (RG-T08, RG-T11)
|
||||
|
||||
Ctrl->>BDD: BEGIN transaction
|
||||
Ctrl->>BDD: UPDATE customer_order SET status = 'cancelled', cancelled_at = NOW() WHERE id = :id AND status IN ('pending_payment','paid') (RG-1, RG-T07)
|
||||
BDD-->>Ctrl: lignes affectees
|
||||
|
||||
alt 0 ligne affectee (annulation concurrente)
|
||||
Ctrl->>BDD: ROLLBACK
|
||||
Ctrl-->>AdminUI: 409 INVALID_TRANSITION (ERR-2)
|
||||
AdminUI-->>Equipier: deja annulee par un autre poste
|
||||
else 1 ligne affectee
|
||||
opt statut anterieur = paid (re-credit du stock)
|
||||
Ctrl->>BDD: UPDATE ingredient SET stock_quantity = stock_quantity + :units (par ingredient consomme) (RG-3)
|
||||
Ctrl->>BDD: INSERT stock_movement (type cancellation, delta +units, order_id, user_id de l'equipier) (RG-3)
|
||||
end
|
||||
Ctrl->>BDD: INSERT audit_log (action_code order.cancel, actor_user_id, actor_role_id, entity_type customer_order, entity_id, summary [statut anterieur + montant re-credite]) (RG-6, RG-T14)
|
||||
Ctrl->>BDD: COMMIT
|
||||
BDD-->>Ctrl: transaction validee
|
||||
Ctrl-->>AdminUI: 200 annulation confirmee (OUT-1)
|
||||
AdminUI-->>Equipier: commande annulee, trace enregistree
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Notes de modelisation : chaque pas et sa regle
|
||||
|
||||
Le tableau ci-dessous mappe chaque interaction du diagramme a la regle
|
||||
`mlt.md` 7.1 ou a la regle transverse correspondante, et a l'entite ecrite.
|
||||
|
||||
| # | Interaction | Regle (mlt.md) | Entite ecrite / lue |
|
||||
|---|---|---|---|
|
||||
| 1 | Verifier session active + `is_active = 1` | `RG-T02` | `user` (lecture) |
|
||||
| 2 | Verifier `order.cancel` via `role_permission` | `RG-T03`, 7.1 PRE-1 | `role_permission` (lecture) |
|
||||
| 3 | Charger la commande et lire son `status` | 7.1 PRE-2, PRE-3 | `customer_order` (lecture) |
|
||||
| 4 | Bloquer si `status` est `delivered` ou `cancelled` | 7.1 ERR-1 | aucune ecriture (HTTP 422) |
|
||||
| 5 | Demander + verifier le PIN (`password_verify` argon2id) | `RG-T13`, 7.1 RG-6 | `user.pin_hash` (lecture) |
|
||||
| 6 | Rejeter si PIN incorrect, sans changement d'etat | `RG-T13` | aucune ecriture |
|
||||
| 7 | Capturer l'`acting user_id` pour l'audit | `RG-T13` | (en memoire, sert aux pas 11-12) |
|
||||
| 8 | `BEGIN` transaction | `RG-T08` | transaction |
|
||||
| 9 | `UPDATE customer_order SET status='cancelled'` avec garde `AND status IN (...)` | 7.1 RG-1, `RG-T07` | `customer_order` (ecriture) |
|
||||
| 10 | `ROLLBACK` + 409 si 0 ligne affectee (concurrence) | 7.1 ERR-2, `RG-T07` | aucune ecriture nette |
|
||||
| 11 | Re-credit conditionnel du stock si statut anterieur `paid` | 7.1 RG-3, `RG-T11` | `ingredient`, `stock_movement` (type `cancellation`) |
|
||||
| 12 | `INSERT audit_log` dans la meme transaction | 7.1 RG-6, `RG-T14` | `audit_log` (ecriture) |
|
||||
| 13 | `COMMIT` (tout ou rien) | `RG-T08`, `RG-T11` | transaction |
|
||||
| 14 | Reponse 200 de confirmation | 7.1 OUT-1 | aucune ecriture |
|
||||
|
||||
### 4.1 Re-credit conditionnel du stock (`RG-T11`)
|
||||
|
||||
Le re-credit ne s'applique que si la commande etait au statut `paid` avant
|
||||
l'annulation (7.1 RG-3). Une commande `pending_payment` n'avait pas encore
|
||||
decremente le stock (le decrement a lieu a la transition `paid`), donc il n'y a
|
||||
rien a re-crediter. Pour chaque `order_item` d'une commande `paid`, les unites
|
||||
consommees sont recalculees (format `normal`/`maxi`, ajustees par les
|
||||
`order_item_modifier`), `ingredient.stock_quantity` est re-incremente et un
|
||||
`stock_movement` de type `cancellation` est insere. `RG-T11` garantit que ce
|
||||
re-credit et l'`UPDATE` du statut sont dans la **meme transaction** : il n'y a pas
|
||||
de decrement orphelin si une etape echoue.
|
||||
|
||||
### 4.2 Garde de concurrence (`RG-T07`)
|
||||
|
||||
L'`UPDATE` porte la clause `AND status IN ('pending_payment','paid')`. Si deux
|
||||
postes tentent d'annuler la meme commande au meme instant, seul le premier
|
||||
obtient une ligne affectee ; le second recoit 0 ligne et le controleur repond
|
||||
409 `INVALID_TRANSITION` apres `ROLLBACK` (7.1 ERR-2). Cette garde optimiste
|
||||
reduit le risque d'une double annulation et d'un double re-credit du stock.
|
||||
|
||||
### 4.3 PIN distinct de la session (`RG-T13`)
|
||||
|
||||
La session reste **partagee par poste** pour le flux routine. Le PIN est verifie
|
||||
a chaque action du sous-ensemble sensible (annulation, prix/VAT, RBAC, gestion
|
||||
utilisateur, correction d'inventaire), et c'est lui qui fournit l'`actor_user_id`
|
||||
ecrit dans `audit_log`. Le `pin_hash` est un hash argon2id (`dictionary.md` 3.14),
|
||||
compare via `password_verify` ; il fait partie des champs RESTRICTED tenus hors
|
||||
des logs et des reponses API.
|
||||
|
||||
---
|
||||
|
||||
## 5. Menace adressee : repudiation et detournement d'especes
|
||||
|
||||
L'annulation d'une commande `paid` est le geste qui permet le schema de fraude
|
||||
"encaisser puis annuler pour garder le cash" (insider cash-skim). Sans controle,
|
||||
sur un poste a session partagee, une annulation ne serait rattachee a personne :
|
||||
l'auteur pourrait nier l'avoir faite (repudiation). Le flux ci-dessus reduit le
|
||||
risque de ce schema en combinant deux mecanismes concrets :
|
||||
|
||||
- **PIN par equipier (`RG-T13`)** : l'annulation exige une re-authentification
|
||||
individuelle. Sur un poste partage, cela rattache l'acte a une personne et non
|
||||
au seul poste. Le PIN tend a dissuader l'usage opportuniste d'une session
|
||||
laissee ouverte par un collegue.
|
||||
- **`audit_log` immuable (`RG-T14`)** : chaque annulation ecrit une ligne
|
||||
`audit_log` (`action_code = order.cancel`, `actor_user_id`, `actor_role_id`,
|
||||
`entity_type`, `entity_id`, `summary` avec le statut anterieur et le montant
|
||||
re-credite) dans la **meme transaction** que l'`UPDATE` du statut. La table
|
||||
n'accepte ni `UPDATE` ni `DELETE` au niveau applicatif (`dictionary.md` 3.20).
|
||||
Une annulation ne peut donc pas exister sans sa trace, et la trace ne peut pas
|
||||
etre effacee par l'auteur.
|
||||
|
||||
L'effet combine : un pic d'annulations rattachees a un meme `actor_user_id`
|
||||
devient visible et opposable lors d'une revue. Ceci ne supprime pas le risque,
|
||||
mais le **reduit** en transformant un acte anonyme et niable en un acte attribue
|
||||
et trace. La residualite (collusion, partage de PIN) releve de controles
|
||||
organisationnels hors du modele de donnees.
|
||||
|
||||
> Note : `audit_log` enregistre des **noms de champs** et un `summary`
|
||||
> non-personnel (`details` stocke les noms de champs modifies, pas de PII),
|
||||
> conformement a `RG-T14` et a la classification de `PROJECT_CONTEXT.md` section 19.
|
||||
> L'attribution `stock_movement.user_id` du re-credit complete la trace cote stock
|
||||
> sans double journalisation.
|
||||
|
||||
---
|
||||
|
||||
## 6. Coherence avec les autres livrables
|
||||
|
||||
| Verification | Resultat |
|
||||
|---|---|
|
||||
| Statuts annulables coherents avec `state-commande.md` | Oui : `pending_payment` et `paid` (T3, T5) ; `delivered` non annulable (7.1 ERR-1) |
|
||||
| Transition `paid -> cancelled` avec re-credit | Couverte par T5 et 7.1 RG-3 (`stock_movement` type `cancellation`) |
|
||||
| Entites ecrites presentes au dictionnaire | `customer_order` (3.10), `ingredient`, `stock_movement`, `audit_log` (3.20) |
|
||||
| Regle PIN appliquee | `RG-T13` (sous-ensemble sensible inclut 7.1) ; `user.pin_hash` (3.14) |
|
||||
| Regle audit appliquee | `RG-T14` ; colonnes conformes a `audit_log` (3.20) |
|
||||
| Atomicite re-credit + statut + audit | `RG-T08` + `RG-T11` (une transaction, `COMMIT` / `ROLLBACK`) |
|
||||
| Codes d'erreur | 422 `CANNOT_CANCEL_IN_STATE` (ERR-1), 409 `INVALID_TRANSITION` (ERR-2) |
|
||||
|
||||
---
|
||||
|
||||
## 7. Arbitrage tranche
|
||||
|
||||
Le flux retient la re-authentification **par PIN** plutot qu'une re-saisie du mot
|
||||
de passe complet : le PIN couvre le sous-ensemble sensible sans casser le routine
|
||||
95% a session partagee (`RG-T13`), tout en fournissant l'attribution
|
||||
individuelle. L'`audit_log` est ecrit dans la **meme transaction** que l'effet
|
||||
(`RG-T14` + `RG-T08`) : une annulation sans trace ne peut pas etre committee. Le
|
||||
re-credit du stock est conditionnel au statut anterieur `paid` (`RG-T11`), ce qui
|
||||
ecarte un re-credit indu sur une commande `pending_payment` qui n'a pas ete
|
||||
decrementee. Les codes d'erreur (`CANNOT_CANCEL_IN_STATE`, `INVALID_TRANSITION`)
|
||||
reprennent ceux de `mlt.md` 7.1, sans en inventer de nouveaux.
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
# Diagramme de sequence - Passer une commande (borne client)
|
||||
|
||||
**Phase UML** : P1 - Conception, complement UML (apres MCD)
|
||||
**Statut** : v0.1
|
||||
**Date** : 2026-05-21
|
||||
**Statut** : v0.2 - prod-like, creation atomique (create + pay)
|
||||
**Date** : 2026-06-11
|
||||
**Branche** : `feat/p1-conception`
|
||||
**Auteur methodologie** : BYAN
|
||||
|
||||
|
|
@ -12,18 +12,24 @@
|
|||
|
||||
Ce document decrit le **flux temporel** du parcours "passer une commande" cote
|
||||
**Client sur la borne kiosk** : navigation dans les categories, selection d'un
|
||||
produit ou composition d'un menu, gestion du panier, validation avec saisie du
|
||||
numero de retrait, paiement, puis confirmation.
|
||||
produit ou composition d'un menu (slots + format Normal/Maxi + modifiers
|
||||
d'ingredients), gestion du panier, validation avec saisie du numero de retrait,
|
||||
et confirmation. Dans le modele v0.2, la **creation et le paiement sont
|
||||
atomiques** : un seul appel `POST /api/orders` cree la commande, la fait passer a
|
||||
`paid`, decremente le stock et journalise les mouvements, dans une meme
|
||||
transaction.
|
||||
|
||||
Le diagramme reste au niveau **conceptuel / logique**. Il nomme les echanges
|
||||
entre participants sans detailler l'implementation PHP (controllers, models)
|
||||
ni le SQL exact. Il complete le cas d'utilisation "Passer une commande" de
|
||||
`docs/uml/use-cases.md` et la machine a etats de `docs/uml/state-commande.md`.
|
||||
Le diagramme reste au niveau conceptuel / logique. Il nomme les echanges entre
|
||||
participants sans detailler l'implementation PHP ni le SQL exact. Il complete le
|
||||
cas d'utilisation "Passer une commande" de `docs/uml/use-cases.md` (4.1), la
|
||||
machine a etats de `docs/uml/state-commande.md` (T1/T2) et l'operation
|
||||
`CREATE_ORDER` du `docs/merise/mct.md` (3.3).
|
||||
|
||||
**Sources** :
|
||||
- `docs/PROJECT_CONTEXT.md` section 2 (processus metier), section 7 (endpoints API)
|
||||
- `docs/merise/dictionary.md` (`commande`, `ligne_commande`, `menu`, `produit`)
|
||||
- `docs/uml/state-commande.md` (transitions `pending_payment -> paid`)
|
||||
- `docs/merise/dictionary.md` 3.10-3.13 (`customer_order`, `order_item`, `order_item_selection`, `order_item_modifier`)
|
||||
- `docs/merise/mct.md` 3.3 CREATE_ORDER (transaction, snapshots, decrement stock)
|
||||
- `docs/uml/state-commande.md` (transitions T1/T2, atomicite `pending_payment -> paid`)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -71,16 +77,18 @@ sequenceDiagram
|
|||
|
||||
alt Produit a la carte
|
||||
Client->>Borne: selectionner un produit
|
||||
Client->>Borne: regler taille / options
|
||||
opt Personnaliser les ingredients
|
||||
Client->>Borne: retirer / ajouter un ingredient
|
||||
end
|
||||
Borne->>Borne: ajouter la ligne au panier local
|
||||
else Composition d'un menu
|
||||
Client->>Borne: selectionner un menu
|
||||
Borne->>API: GET /api/menus (composition du menu)
|
||||
API->>BDD: lire menu et composition
|
||||
BDD-->>API: menu + produits par role
|
||||
Borne->>API: GET /api/menus (slots + options eligibles)
|
||||
API->>BDD: lire menu, menu_slot, menu_slot_option
|
||||
BDD-->>API: menu + slots + options
|
||||
API-->>Borne: composition (JSON)
|
||||
Borne-->>Client: afficher les choix par slot (burger, accompagnement, boisson, sauce)
|
||||
Client->>Borne: choisir chaque composant + tailles
|
||||
Borne-->>Client: afficher les slots (boisson, accompagnement, sauce) + format Normal/Maxi
|
||||
Client->>Borne: choisir chaque slot + format + modifiers du burger
|
||||
Borne->>Borne: ajouter la ligne menu au panier local
|
||||
end
|
||||
|
||||
|
|
@ -94,36 +102,35 @@ sequenceDiagram
|
|||
Borne-->>Client: panier mis a jour
|
||||
end
|
||||
|
||||
Note over Client,BDD: Phase 4 - Validation du panier et saisie du numero
|
||||
Note over Client,BDD: Phase 4 - Validation, saisie du numero, creation atomique (create + pay)
|
||||
|
||||
Client->>Borne: valider la commande
|
||||
Client->>Borne: saisir le numero de retrait
|
||||
Borne->>Borne: valider le panier (au moins 1 ligne)
|
||||
Borne->>API: POST /api/orders (lignes + mode_consommation + numero)
|
||||
Borne->>Borne: valider le panier (au moins 1 ligne, numero non vide)
|
||||
Borne->>API: POST /api/orders (lignes + selections + modifiers + service_mode + numero)
|
||||
|
||||
API->>API: recalculer les totaux cote serveur
|
||||
API->>BDD: creer la commande (statut pending_payment)
|
||||
API->>BDD: creer les lignes (snapshot libelle + prix)
|
||||
BDD-->>API: commande persistee {id, numero, statut: pending_payment}
|
||||
API-->>Borne: 201 Created {id, numero, statut: pending_payment, total}
|
||||
Borne-->>Client: afficher le total a regler
|
||||
API->>API: recalculer les totaux cote serveur (HT / TVA / TTC, taux par produit)
|
||||
API->>BDD: BEGIN transaction
|
||||
API->>BDD: INSERT customer_order (status pending_payment, source kiosk)
|
||||
API->>BDD: INSERT order_item (snapshot libelle + prix + vat_rate)
|
||||
API->>BDD: INSERT order_item_selection (par slot de menu rempli)
|
||||
API->>BDD: INSERT order_item_modifier (par modification d'ingredient)
|
||||
API->>BDD: UPDATE ingredient.stock_quantity (decrement, ajuste par modifiers)
|
||||
API->>BDD: INSERT stock_movement (type sale, par unite consommee)
|
||||
API->>BDD: UPDATE customer_order status -> paid, paid_at = NOW()
|
||||
API->>BDD: COMMIT
|
||||
BDD-->>API: commande persistee {id, order_number, status: paid}
|
||||
|
||||
Note over Client,BDD: Phase 5 - Paiement (pending_payment -> paid)
|
||||
Note over Client,BDD: Phase 5 - Confirmation
|
||||
|
||||
Client->>Borne: payer la commande
|
||||
Borne->>API: POST /api/orders/{id}/pay
|
||||
API->>BDD: enregistrer le paiement, passer la commande a paid (paye_a)
|
||||
BDD-->>API: commande mise a jour {id, numero, statut: paid}
|
||||
|
||||
Note over Client,BDD: Phase 6 - Confirmation
|
||||
|
||||
API-->>Borne: 200 OK {id, numero, statut: paid}
|
||||
Borne-->>Client: ecran de confirmation avec le numero
|
||||
API-->>Borne: 201 Created {id, order_number, status: paid, total_ttc}
|
||||
Borne-->>Client: ecran de confirmation avec le numero de retrait
|
||||
|
||||
Note over Client,BDD: Cas d'erreur
|
||||
|
||||
alt Panier vide ou donnees invalides
|
||||
API-->>Borne: 4xx {error: code, message}
|
||||
alt Panier vide, produit indisponible ou donnees invalides
|
||||
API->>BDD: ROLLBACK (si transaction entamee)
|
||||
API-->>Borne: 4xx {error: {code, message}}
|
||||
Borne-->>Client: message d'erreur, retour au panier
|
||||
end
|
||||
```
|
||||
|
|
@ -132,27 +139,31 @@ sequenceDiagram
|
|||
|
||||
## 4. Notes de modelisation
|
||||
|
||||
### 4.1 Recalcul des totaux cote serveur
|
||||
### 4.1 Recalcul des totaux cote serveur (controle de securite)
|
||||
|
||||
La Borne affiche un total **provisoire** calcule localement pour l'experience
|
||||
utilisateur. L'API recalcule les totaux a la reception du `POST /api/orders` a
|
||||
partir des prix en base, puis fige les snapshots
|
||||
(`prix_unitaire_ttc_cents_snapshot`, `libelle_snapshot` dans `ligne_commande`,
|
||||
voir `dictionary.md` 3.6). Le total affiche par le client n'est pas considere
|
||||
comme la source de verite : ceci limite la falsification du prix cote client.
|
||||
partir des prix en base (HT, TVA ligne par ligne via `vat_rate`, TTC), puis fige
|
||||
les snapshots (`unit_price_cents_snapshot`, `vat_rate_snapshot`,
|
||||
`label_snapshot` sur `order_item`, voir `dictionary.md` 3.11). Le total affiche
|
||||
par le client n'est pas considere comme la source de verite : ceci limite la
|
||||
falsification du prix cote client.
|
||||
|
||||
### 4.2 Transitions de statut
|
||||
### 4.2 Creation atomique (create + pay)
|
||||
|
||||
Le parcours materialise les transitions T1 et T2 de
|
||||
`docs/uml/state-commande.md`, en deux phases successives conformes a la regle
|
||||
metier :
|
||||
`docs/uml/state-commande.md` dans **un seul appel et une seule transaction** :
|
||||
|
||||
- `POST /api/orders` cree la commande composee en `pending_payment` (T1).
|
||||
- `POST /api/orders/{id}/pay` enregistre le paiement et fait passer la commande
|
||||
a `paid` (T2), avec l'horodatage `paye_a`.
|
||||
- `POST /api/orders` cree la commande en `pending_payment` (T1) puis la fait
|
||||
passer a `paid` (T2) avant le `COMMIT`. `paid_at` est renseigne.
|
||||
- La saisie du numero de retrait tient lieu de paiement (cadre RNCP) ; il n'y a
|
||||
pas d'appel `POST /api/orders/{id}/pay` separe (supprime par rapport au v0.1).
|
||||
- Le decrement du stock (`ingredient.stock_quantity`) et la journalisation
|
||||
(`stock_movement` type `sale`) sont inclus dans la meme transaction que
|
||||
l'insert de la commande : soit tout reussit, soit tout est annule (`ROLLBACK`).
|
||||
|
||||
La separation des deux appels reflete les deux phases du cycle de vie :
|
||||
composer la commande, puis la payer.
|
||||
Le statut `pending_payment` n'est donc pas observable en dehors de la
|
||||
transaction (coherent avec `mct.md` section 13).
|
||||
|
||||
### 4.3 Panier local jusqu'a la validation
|
||||
|
||||
|
|
@ -166,9 +177,20 @@ navigateur peut etre envisage plus tard.
|
|||
|
||||
`PROJECT_CONTEXT.md` section 4 prevoit un mode de repli ou la Borne lit des
|
||||
fichiers JSON statiques si l'API est indisponible. Ce mode concerne uniquement
|
||||
les lectures (phases 1 a 2). La validation (phase 4) et le paiement (phase 5)
|
||||
requierent l'API ; sans elle, la commande n'est ni persistee ni payee. Ce cas
|
||||
degrade n'est pas detaille dans le diagramme nominal ci-dessus.
|
||||
les lectures (phases 1 a 2). La validation et la creation (phase 4) requierent
|
||||
l'API ; sans elle, la commande n'est ni persistee ni payee. Ce cas degrade
|
||||
n'est pas detaille dans le diagramme nominal ci-dessus.
|
||||
|
||||
### 4.5 Garde-fous securite a venir (passe security-by-design)
|
||||
|
||||
Le flux ci-dessus est la cible **fonctionnelle** v0.2. La passe security-by-design
|
||||
ajoutera, en complement (append, sans reecrire ce flux), des garde-fous sur le
|
||||
`POST /api/orders` anonyme : cle d'idempotence (`idempotency_key` UNIQUE pour
|
||||
dedupliquer les POST rejoues), limitation de debit / anti-spam, et verrou
|
||||
pessimiste `SELECT ... FOR UPDATE` sur les ingredients pendant le decrement
|
||||
(anti-oversell multi-bornes). Ces ajouts dependent de decisions encore a
|
||||
trancher (oversell/idempotence, throttling) et seront documentes dans un artefact
|
||||
`docs/uml/security-sequence.md` dedie.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -176,18 +198,21 @@ degrade n'est pas detaille dans le diagramme nominal ci-dessus.
|
|||
|
||||
| Verification | Resultat |
|
||||
|---|---|
|
||||
| Endpoints utilises existent dans `PROJECT_CONTEXT.md` section 7 | `GET /api/categories`, `GET /api/products`, `GET /api/menus`, `POST /api/orders` ; `POST /api/orders/{id}/pay` est a confirmer en section 7 du brief |
|
||||
| Entites manipulees presentes au MCD | Oui : `categorie`, `produit`, `menu`, `menu_produit`, `commande`, `ligne_commande` |
|
||||
| Statuts utilises coherents avec `state-commande.md` | Oui : `pending_payment` puis `paid` (T1, T2), valeurs ENUM anglaises |
|
||||
| Format de reponse JSON | Coherent avec `PROJECT_CONTEXT.md` section 7 (`{data, error}`) et la reponse `{id, number, status}` du POST orders |
|
||||
| Endpoints utilises existent dans `PROJECT_CONTEXT.md` section 7 | `GET /api/categories`, `GET /api/products`, `GET /api/menus`, `POST /api/orders` ; l'appel `POST /api/orders/{id}/pay` du v0.1 est supprime (creation atomique) |
|
||||
| Entites manipulees presentes au MCD / dictionnaire | Oui : `category`, `product`, `menu`, `menu_slot`, `menu_slot_option`, `ingredient`, `customer_order`, `order_item`, `order_item_selection`, `order_item_modifier`, `stock_movement` |
|
||||
| Statuts utilises coherents avec `state-commande.md` | Oui : `pending_payment` puis `paid` (T1, T2), atomiques |
|
||||
| Operation MCT correspondante | `mct.md` 3.3 CREATE_ORDER (transaction unique, snapshots, decrement stock, transition atomique) |
|
||||
| Format de reponse JSON | Coherent avec `PROJECT_CONTEXT.md` section 7 (`{data, error}`) et la reponse `{id, order_number, status, total_ttc}` du POST orders |
|
||||
|
||||
---
|
||||
|
||||
## 6. Arbitrage tranche
|
||||
|
||||
La phase de paiement est integree au flux conformement a la regle metier des
|
||||
deux phases (composer puis payer). La sequence suit la machine canonique de
|
||||
`state-commande.md` : creation en `pending_payment` (T1) puis paiement vers
|
||||
`paid` (T2), avec des valeurs ENUM en anglais. Point a confirmer au MCT :
|
||||
l'endpoint de paiement (`POST /api/orders/{id}/pay`) doit etre reporte dans la
|
||||
section 7 du brief s'il n'y figure pas encore.
|
||||
La phase de paiement separee du v0.1 (`POST /api/orders/{id}/pay`) est supprimee :
|
||||
la creation et le passage a `paid` sont atomiques dans `POST /api/orders`,
|
||||
conformement au MCT v0.2 (3.3) et a la regle metier (saisie du numero = substitut
|
||||
de paiement). Le decrement de stock et la journalisation `stock_movement` sont
|
||||
inclus dans la meme transaction, garantissant la coherence stock/commande. Les
|
||||
valeurs ENUM sont en anglais (`pending_payment`, `paid`). Les garde-fous de
|
||||
securite (idempotence, rate-limit, verrou pessimiste) relevent de la passe
|
||||
security-by-design et seront ajoutes en complement (section 4.5).
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# Diagramme d'etats-transitions - Commande
|
||||
|
||||
**Phase UML** : P1 - Conception, complement UML (apres MCD)
|
||||
**Statut** : v0.1
|
||||
**Date** : 2026-05-21
|
||||
**Statut** : v0.2 - prod-like, machine a 4 etats
|
||||
**Date** : 2026-06-11
|
||||
**Branche** : `feat/p1-conception`
|
||||
**Auteur methodologie** : BYAN
|
||||
|
||||
|
|
@ -10,38 +10,41 @@
|
|||
|
||||
## 1. Objet du document
|
||||
|
||||
Ce document formalise la **machine a etats** de l'attribut `commande.statut`.
|
||||
Ce document formalise la **machine a etats** de l'attribut `customer_order.status`.
|
||||
Il decrit les etats possibles d'une commande, les transitions autorisees entre
|
||||
ces etats, les **evenements** qui les declenchent et les **gardes** (conditions)
|
||||
qui les conditionnent.
|
||||
|
||||
Il complete le MCD (`docs/merise/mcd.md` section 9, qui esquisse le cycle de
|
||||
vie) et le dictionnaire (`docs/merise/dictionary.md` 3.5, qui declare l'ENUM).
|
||||
Il complete le MCD (`docs/merise/mcd.md`, cycle de vie de la commande), le
|
||||
dictionnaire (`docs/merise/dictionary.md` 3.10, qui declare l'ENUM `status`) et
|
||||
le MCT (`docs/merise/mct.md` section 13, qui resume les transitions par
|
||||
operation).
|
||||
|
||||
---
|
||||
|
||||
## 2. Source de verite et regle metier
|
||||
|
||||
La regle metier confirmee fixe deux phases successives dans le cycle de vie
|
||||
d'une commande : le client **compose** sa commande, **puis** il **paie**. Une
|
||||
fois payee, la commande entre en preparation. Le paiement fait partie integrante
|
||||
du cycle. Les valeurs d'etat sont en anglais et alignees sur l'ENUM du
|
||||
dictionnaire.
|
||||
Le modele v0.2 (prod-like) reduit la machine a **quatre etats**. La regle metier
|
||||
distingue la **composition payee** de la **remise** : une commande est creee et
|
||||
payee en une operation atomique (la saisie du numero de retrait tient lieu de
|
||||
paiement dans le cadre RNCP), puis elle est remise au client en un geste unique.
|
||||
|
||||
| Source | Valeurs de statut |
|
||||
|---|---|
|
||||
| `dictionary.md` 3.5 (ENUM SQL) | `pending_payment`, `paid`, `preparing`, `ready`, `delivered`, `cancelled` |
|
||||
| Regle metier confirmee | composer -> payer -> preparer -> pret -> remettre |
|
||||
| `dictionary.md` 3.10 (ENUM SQL) | `pending_payment`, `paid`, `delivered`, `cancelled` |
|
||||
| `mct.md` section 13 (transitions) | creer+payer -> remettre, annulation depuis tout etat non terminal |
|
||||
|
||||
**Machine a etats canonique** : la machine ci-dessous est la seule autorisee.
|
||||
Elle suit l'ENUM du dictionnaire et la regle metier des deux phases :
|
||||
> Le dictionnaire (`dictionary.md` 3.10) et la machine ci-dessous partagent la
|
||||
> meme ENUM a 4 valeurs, ce qui maintient la coherence entre le modele de
|
||||
> donnees et le modele d'etats (cross-validation, mantra #34).
|
||||
|
||||
- `pending_payment` : commande composee, en attente de paiement.
|
||||
- `paid` : paiement effectue ; la commande peut entrer en file de preparation.
|
||||
|
||||
> Le dictionnaire (`dictionary.md` 3.5) et la machine ci-dessous partagent la
|
||||
> meme ENUM, ce qui maintient la coherence entre le modele de donnees et le
|
||||
> modele d'etats (cross-validation, mantra #34).
|
||||
**Etats supprimes par rapport au v0.1** : `preparing` et `ready`. En contexte
|
||||
fast-food, l'affichage cuisine (KDS) est un dispositif visuel : l'equipier lit
|
||||
le ticket et agit. Ces deux etats intermediaires ajoutaient des transitions sans
|
||||
valeur metier proportionnelle. La cuisine est en **lecture seule** ; la remise
|
||||
(`DELIVER_ORDER`) est le geste unique qui fait avancer le statut. Le KPI est le
|
||||
temps total `delivered_at - paid_at` (SLA ~10 min) ; la couleur du KDS est
|
||||
calculee a l'affichage depuis `now - paid_at`, sans etat stocke supplementaire.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -49,12 +52,16 @@ Elle suit l'ENUM du dictionnaire et la regle metier des deux phases :
|
|||
|
||||
| Etat | Valeur ENUM | Signification | Acteur qui declenche l'entree |
|
||||
|---|---|---|---|
|
||||
| En attente de paiement | `pending_payment` | Commande composee, panier fige, en attente de paiement. | Client (kiosk) ou Accueil (counter/drive) |
|
||||
| Payee | `paid` | Paiement effectue ; la commande peut entrer en file de preparation. | Client (paiement) ou Accueil |
|
||||
| En preparation | `preparing` | Prise en charge par la Preparation, en cuisine. | Preparation |
|
||||
| Prete | `ready` | Preparation terminee, prete au comptoir. | Preparation |
|
||||
| Livree | `delivered` | Remise effectuee au client. Etat **final**. | Accueil |
|
||||
| Annulee | `cancelled` | Commande abandonnee ou annulee. Etat **final**. | Client, Accueil ou Administration |
|
||||
| En attente de paiement | `pending_payment` | Etat initial transitoire : commande composee, en attente de paiement. Non observable hors transaction (voir section 7). | Client (kiosk) ou Counter/Drive (back-office) |
|
||||
| Payee | `paid` | Paiement effectue ; la commande entre en file de preparation (lecture seule cuisine). | Client (kiosk) ou Counter/Drive |
|
||||
| Livree | `delivered` | Remise effectuee au client. Etat **final**. | Counter ou Drive |
|
||||
| Annulee | `cancelled` | Commande abandonnee ou annulee avant remise. Etat **final**. | Counter, Drive ou Admin |
|
||||
|
||||
`pending_payment` est l'etat par defaut a l'INSERT (`dictionary.md` 3.10), mais
|
||||
la transition vers `paid` est realisee dans la **meme transaction** que la
|
||||
creation (operations `CREATE_ORDER` / `CREATE_COUNTER_ORDER` du MCT). Il est donc
|
||||
conserve dans l'ENUM pour la lisibilite du cycle et pour laisser la porte
|
||||
ouverte a un paiement reel ulterieur sans migration destructive.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -62,19 +69,13 @@ Elle suit l'ENUM du dictionnaire et la regle metier des deux phases :
|
|||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> pending_payment : creer commande (kiosk / counter / drive)
|
||||
[*] --> pending_payment : creer la commande (kiosk / counter / drive)
|
||||
|
||||
pending_payment --> paid : payer\n[panier contient au moins 1 ligne]
|
||||
pending_payment --> cancelled : abandonner\n[avant paiement]
|
||||
pending_payment --> paid : payer\n[atomique dans CREATE_ORDER / CREATE_COUNTER_ORDER\nsaisie du numero = substitut de paiement]
|
||||
pending_payment --> cancelled : annuler\n[avant remise]
|
||||
|
||||
paid --> preparing : prendre en charge\n[acteur Preparation, file triee par heure croissante]
|
||||
paid --> cancelled : annuler\n[Accueil ou Administration]
|
||||
|
||||
preparing --> ready : declarer preparee\n[acteur Preparation]
|
||||
preparing --> cancelled : annuler\n[rupture produit / decision Administration]
|
||||
|
||||
ready --> delivered : remettre au client\n[acteur Accueil]
|
||||
ready --> cancelled : annuler\n[client absent / non recuperee]
|
||||
paid --> delivered : remettre au client\n[acteur Counter / Drive, geste unique]
|
||||
paid --> cancelled : annuler\n[Counter / Drive / Admin, re-credit du stock]
|
||||
|
||||
delivered --> [*]
|
||||
cancelled --> [*]
|
||||
|
|
@ -86,29 +87,29 @@ stateDiagram-v2
|
|||
|
||||
| # | De | Vers | Evenement declencheur | Garde (condition) | Acteur |
|
||||
|---|---|---|---|---|---|
|
||||
| T1 | (initial) | `pending_payment` | Creation de la commande composee | Au moins un item ajoute au panier en cours | Client / Accueil |
|
||||
| T2 | `pending_payment` | `paid` | Paiement de la commande | La commande contient au moins une `ligne_commande` ; le paiement aboutit | Client / Accueil |
|
||||
| T3 | `pending_payment` | `cancelled` | Abandon avant paiement | Commande pas encore payee | Client / Accueil |
|
||||
| T4 | `paid` | `preparing` | Prise en charge en file | La commande est la plus ancienne non traitee (tri par heure de livraison croissante) | Preparation |
|
||||
| T5 | `paid` | `cancelled` | Annulation avant preparation | Decision operationnelle | Accueil / Administration |
|
||||
| T6 | `preparing` | `ready` | Declaration "preparee" | Preparation terminee | Preparation |
|
||||
| T7 | `preparing` | `cancelled` | Annulation pendant preparation | Rupture produit ou decision Administration | Preparation / Administration |
|
||||
| T8 | `ready` | `delivered` | Remise physique au client | Le client se presente avec le bon numero | Accueil |
|
||||
| T9 | `ready` | `cancelled` | Annulation apres preparation | Client non present / commande non recuperee | Accueil / Administration |
|
||||
| T1 | (initial) | `pending_payment` | Creation de la commande composee | Au moins une ligne (`order_item`) ; numero de retrait non vide | Client / Counter / Drive |
|
||||
| T2 | `pending_payment` | `paid` | Paiement (atomique a la creation) | La commande contient au moins une `order_item` ; decrement du stock et insert dans la meme transaction | Client / Counter / Drive |
|
||||
| T3 | `pending_payment` | `cancelled` | Abandon avant paiement | Commande pas encore payee | Counter / Drive / Admin |
|
||||
| T4 | `paid` | `delivered` | Remise physique au client | La commande est `paid` ; l'acteur detient `order.deliver` ; source compatible avec son role (`role_visible_source`) | Counter / Drive |
|
||||
| T5 | `paid` | `cancelled` | Annulation avant remise | L'acteur detient `order.cancel` ; le stock consomme est re-credite (`stock_movement` type `cancellation`) | Counter / Drive / Admin |
|
||||
|
||||
### Invariants de la machine a etats
|
||||
|
||||
- `delivered` et `cancelled` sont des etats **finaux** : aucune transition n'en
|
||||
sort.
|
||||
- Aucune transition ne revient en arriere (pas de `preparing -> paid`). Une
|
||||
erreur operationnelle se traite par annulation puis nouvelle commande, pour
|
||||
preserver l'integrite de l'historique et des snapshots de prix.
|
||||
- La transition vers `cancelled` est possible depuis tous les etats **sauf**
|
||||
`delivered` (une commande remise ne s'annule pas dans ce modele). Ceci est
|
||||
coherent avec `mcd.md` section 9 : "Annuler : transition vers `cancelled`
|
||||
(depuis tout statut sauf `delivered`)".
|
||||
- `paye_a` (DATETIME, `dictionary.md` 3.5) est renseigne au moment de la
|
||||
transition T2 (`pending_payment -> paid`) et reste NULL avant.
|
||||
- Aucune transition ne revient en arriere. Une erreur operationnelle se traite
|
||||
par annulation puis nouvelle commande, pour preserver l'integrite de
|
||||
l'historique et des snapshots (`label_snapshot`, `unit_price_cents_snapshot`,
|
||||
`vat_rate_snapshot` sur `order_item`).
|
||||
- La transition vers `cancelled` est possible depuis `pending_payment` et
|
||||
`paid`, mais pas depuis `delivered` (une commande remise ne s'annule pas dans
|
||||
ce modele). Coherent avec `mct.md` 7.1 (`CANCEL_ORDER`).
|
||||
- `paid_at` (DATETIME, `dictionary.md` 3.10) est renseigne a la transition T2.
|
||||
`delivered_at` est renseigne a T4. `cancelled_at` est renseigne a T3/T5. Les
|
||||
trois colonnes sont NULL tant que la transition correspondante n'a pas eu lieu.
|
||||
- La cuisine (`kitchen`) ne declenche aucune transition : son acces a la file
|
||||
des commandes `paid` est en **lecture seule** (`mct.md` 5.1,
|
||||
`LIST_ORDERS_DISPLAY`).
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -116,29 +117,36 @@ stateDiagram-v2
|
|||
|
||||
| Verification | Resultat |
|
||||
|---|---|
|
||||
| Tous les etats du diagramme existent dans l'ENUM `dictionary.md` 3.5 | Oui (6 valeurs, toutes utilisees) |
|
||||
| La regle "annulation possible sauf depuis delivered" de `mcd.md` 9 | Respectee (T5, T7, T9 ; pas de transition depuis `delivered`) |
|
||||
| Cycle de vie esquisse dans `mcd.md` 9 | Couvert : `pending_payment` -> `paid` (payer), `paid` -> `preparing` (preparer), `preparing` -> `ready` (marquer pret), `ready` -> `delivered` (remettre) |
|
||||
| Acteurs de `use-cases.md` | Preparation declenche T4/T6/T7 ; Accueil declenche T8/T9 ; Administration peut annuler |
|
||||
| Tous les etats du diagramme existent dans l'ENUM `dictionary.md` 3.10 | Oui (4 valeurs, toutes utilisees) |
|
||||
| La regle "annulation possible sauf depuis delivered" de `mct.md` 7.1 | Respectee (T3, T5 ; pas de transition depuis `delivered`) |
|
||||
| Transition `paid -> delivered` en geste unique de `mct.md` 6.1 | Couvert par T4 (`DELIVER_ORDER`) |
|
||||
| Atomicite `pending_payment -> paid` de `mct.md` 3.3 / 4.1 / section 13 | Couvert par T2 (saisie du numero = substitut de paiement) |
|
||||
| Acteurs de `use-cases.md` | Counter/Drive declenchent T4/T5 ; Admin peut annuler (T3/T5) ; Kitchen en lecture seule |
|
||||
| Timestamps de phase `paid_at` / `delivered_at` / `cancelled_at` | Renseignes a T2 / T4 / T3-T5 |
|
||||
|
||||
---
|
||||
|
||||
## 7. Arbitrage tranche
|
||||
|
||||
La divergence historique entre l'ENUM du dictionnaire et un parcours sans
|
||||
paiement est resolue par la regle metier confirmee : le cycle de vie comporte
|
||||
deux phases successives, la composition de la commande puis son paiement. Le
|
||||
paiement fait partie integrante du cycle.
|
||||
|
||||
La machine canonique retenue est donc :
|
||||
La machine retenue est reduite a quatre etats (Decision 4,
|
||||
`docs/notes/revue-alignement-p1.md` section 7) :
|
||||
|
||||
```
|
||||
pending_payment -> paid -> preparing -> ready -> delivered
|
||||
(cancelled atteignable depuis pending_payment, paid, preparing)
|
||||
pending_payment -> paid -> delivered
|
||||
| |
|
||||
+------------+--------> cancelled (depuis pending_payment ou paid)
|
||||
```
|
||||
|
||||
Cette machine est la source de verite partagee par `dictionary.md` 3.5,
|
||||
`use-cases.md` (cas "Payer la commande" cote Client) et
|
||||
`sequence-passer-commande.md` (etape paiement entre validation du panier et
|
||||
confirmation). La colonne `paye_a` est renseignee a la transition T2. A
|
||||
revalider lors du MCT.
|
||||
**Note sur la transition `pending_payment -> paid`** : dans le cadre RNCP, le
|
||||
paiement est remplace par la saisie du numero de commande (kiosk) ou par la
|
||||
validation de l'equipier (counter/drive). La transition est **atomique** dans
|
||||
`CREATE_ORDER` et `CREATE_COUNTER_ORDER` : le statut `pending_payment` n'est pas
|
||||
observable en dehors de la transaction de creation. Il reste declare dans l'ENUM
|
||||
pour exprimer le cycle de vie complet et pour autoriser un paiement reel
|
||||
ulterieur (cout d'une valeur d'ENUM).
|
||||
|
||||
Les etats `preparing` et `ready` du v0.1 sont supprimes : la cuisine est un
|
||||
affichage visuel en lecture seule, et la remise fusionne preparation+remise en
|
||||
un geste unique (`DELIVER_ORDER`). Effet de bord propage : les operations
|
||||
`MARK_IN_PREPARATION` et `MARK_READY` disparaissent du MCT (voir `mct.md`
|
||||
sections 1 et 13).
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# Diagramme de cas d'utilisation - Wakdo
|
||||
|
||||
**Phase UML** : P1 - Conception, complement UML (apres MCD)
|
||||
**Statut** : v0.1
|
||||
**Date** : 2026-05-21
|
||||
**Statut** : v0.2 - prod-like, 5 roles RBAC + catalogue de 23 permissions
|
||||
**Date** : 2026-06-11
|
||||
**Branche** : `feat/p1-conception`
|
||||
**Auteur methodologie** : BYAN
|
||||
|
||||
|
|
@ -12,174 +12,247 @@
|
|||
|
||||
Ce document recense les **cas d'utilisation** de Wakdo, c'est-a-dire les
|
||||
fonctionnalites observables du systeme du point de vue de ses acteurs. Il
|
||||
complete le MCD (`docs/merise/mcd.md`) et le dictionnaire
|
||||
(`docs/merise/dictionary.md`) en passant de la vue **donnees** a la vue
|
||||
**usages**.
|
||||
complete le MCD (`docs/merise/mcd.md`), le dictionnaire
|
||||
(`docs/merise/dictionary.md`) et le MCT (`docs/merise/mct.md`, 26 operations) en
|
||||
passant de la vue **donnees / traitements** a la vue **usages**.
|
||||
|
||||
Le diagramme reste au niveau conceptuel. Il ne prejuge pas de l'ecran ou de
|
||||
l'endpoint qui realisera chaque cas, mais identifie qui fait quoi.
|
||||
Le diagramme reste au niveau conceptuel : il identifie qui fait quoi, sans
|
||||
prejuger de l'ecran ou de l'endpoint qui realise chaque cas. Chaque cas
|
||||
back-office est rattache a la **permission** qui le conditionne (catalogue fige
|
||||
de 23 codes, `dictionary.md` 3.17), conformement a la regle RBAC
|
||||
permission-driven : le code teste une permission, pas un nom de role.
|
||||
|
||||
**Sources** :
|
||||
- `docs/PROJECT_CONTEXT.md` sections 2 (acteurs, processus), 7 (scope RBAC)
|
||||
- `docs/merise/dictionary.md` (entites `commande`, `role`, `user`)
|
||||
- `docs/PROJECT_CONTEXT.md` sections 2 (acteurs, processus), 7 (scope back-office)
|
||||
- `docs/merise/dictionary.md` 3.14-3.18 (`user`, `role`, `role_visible_source`, `permission`, `role_permission`)
|
||||
- `docs/merise/mct.md` (operations, acteurs, permissions par operation)
|
||||
|
||||
---
|
||||
|
||||
## 2. Acteurs - perimetre et challenge de pertinence
|
||||
|
||||
Le brief (`PROJECT_CONTEXT.md` section 2 et section 7) definit les acteurs
|
||||
metier. Avant de les retenir, chaque acteur propose dans la consigne initiale
|
||||
est confronte au perimetre reel du projet.
|
||||
Le brief initial (`PROJECT_CONTEXT.md` section 2) decrivait quatre acteurs
|
||||
metier (Client, Accueil, Preparation, Administration) adosses a 3 roles RBAC. Le
|
||||
modele v0.2 (prod-like, Decision 4 de `revue-alignement-p1.md` section 7) raffine
|
||||
le back-office en **5 roles** pour coller a l'organisation reelle d'un fast-food
|
||||
multi-canal. Chaque acteur candidat est confronte au perimetre reel.
|
||||
|
||||
| Acteur candidat | Statut | Justification (perimetre reel) |
|
||||
| Acteur candidat (brief) | Statut v0.2 | Justification (perimetre reel) |
|
||||
|---|---|---|
|
||||
| **Client (borne kiosk)** | Retenu | Acteur central du Bloc 1. Compose et valide une commande sur la borne tactile autonome (canal `kiosk`). Non authentifie. |
|
||||
| **Manager / Admin** | Retenu, fusionne en **Administration** | Le brief ne distingue pas "manager" et "admin" comme deux roles. Le role RBAC reel est `admin` (section 7). Il porte le CRUD catalogue, la gestion des utilisateurs/roles et les stats. On nomme l'acteur **Administration** pour coller au vocabulaire du brief. |
|
||||
| **Cuisine** | Retenu, renomme **Preparation** | Correspond au role RBAC `preparation` (section 7). Voit la file des commandes a preparer triees par heure de livraison croissante et fait avancer leur statut. Le terme "Cuisine" est un synonyme metier ; le role technique est `preparation`. |
|
||||
| **Caisse** | Ecarte comme acteur distinct | Challenge : il n'existe pas de role RBAC `caisse` (les 3 roles sont `admin`, `preparation`, `accueil`). Le paiement existe dans le cycle (cote Client sur la borne et cote Accueil au comptoir/drive), mais aucun acteur "Caisse" dedie n'est modelise. L'equivalent operationnel le plus proche est l'**Accueil** (role `accueil`) qui saisit les commandes au comptoir/drive et remet les commandes livrees. |
|
||||
| **Accueil** | Retenu (non liste dans la consigne mais present au brief) | Role RBAC `accueil`. Saisit les commandes au comptoir (canal `counter`) ou au drive (canal `drive`), puis remet les commandes au client (passage a `delivered`). C'est l'acteur qui recouvre le besoin que la consigne attribuait a "Caisse". |
|
||||
| **Client (borne kiosk)** | Retenu (acteur `CUSTOMER`) | Acteur central du Bloc 1. Compose et valide une commande sur la borne tactile autonome (canal `kiosk`). **Non authentifie**. |
|
||||
| **Accueil** | **Scinde** en `counter` et `drive` | Le besoin "Accueil" recouvre deux canaux operationnels distincts : le comptoir (`counter`) et le drive (`drive`). Le v0.2 les separe car le tag `source` de la commande et le filtre de dashboard (`role_visible_source`) different. Tous deux saisissent des commandes, les remettent et les annulent. |
|
||||
| **Preparation** | Retenu, renomme `kitchen` | Role RBAC `kitchen`. Voit la file des commandes `paid` triees par `paid_at` croissant. **Lecture seule** : ne declenche aucune transition de statut (le KDS est un dispositif visuel ; la remise revient a `counter`/`drive`). |
|
||||
| **Administration** | **Scinde** en `admin` et `manager` | Le v0.1 fusionnait "Manager/Admin". Le v0.2 distingue : `admin` (gestion des utilisateurs, des roles et permissions, suppressions catalogue) et `manager` (catalogue create/update, stock/reappro, stats), sans acces aux utilisateurs ni au RBAC. Resout le point ouvert v0.1 "Manager vs Admin". |
|
||||
| **Caisse** | Ecarte (recouvert par `counter`/`drive`) | Aucun role `caisse` n'existe. L'encaissement est atomique a la creation de commande (saisie du numero = substitut de paiement) ; il est realise par le Client (kiosk) ou par `counter`/`drive` (back-office). Resout le point ouvert v0.1 "Caisse absente du RBAC". |
|
||||
| **Systeme** | Retenu (acteur `SYS`) | Logique interne (generation du numero, reponse API de confirmation). Apparait dans le MCT (3.4 `DISPLAY_CONFIRMATION`) ; non represente comme acteur humain au diagramme. |
|
||||
|
||||
### Decision sur les acteurs retenus
|
||||
|
||||
Quatre acteurs sont conserves au diagramme :
|
||||
Six acteurs sont conserves : un acteur public et cinq roles back-office.
|
||||
|
||||
1. **Client** (borne, non authentifie)
|
||||
2. **Administration** (role `admin`)
|
||||
3. **Preparation** (role `preparation`, ex-"Cuisine")
|
||||
4. **Accueil** (role `accueil`, recouvre le besoin "Caisse")
|
||||
1. **Customer** (borne kiosk, non authentifie)
|
||||
2. **Admin** (role `admin`)
|
||||
3. **Manager** (role `manager`)
|
||||
4. **Kitchen** (role `kitchen`, ex-"Preparation", lecture seule)
|
||||
5. **Counter** (role `counter`, ex-"Accueil" comptoir)
|
||||
6. **Drive** (role `drive`, ex-"Accueil" drive)
|
||||
|
||||
> Decision actee : il n'y a **pas** de parcours employe dedie modelise a part.
|
||||
> Les cas d'usage des employes (Administration, Preparation, Accueil) sont
|
||||
> couverts directement ici. Cette decision suit le mantra du Rasoir d'Ockham
|
||||
> (#37) : on evite une couche de modelisation redondante tant qu'aucun besoin
|
||||
> ne la justifie.
|
||||
> Regle RBAC permission-driven (`dictionary.md` 3.15) : les rattachements
|
||||
> acteur -> cas ci-dessous refletent la **matrice de permissions par defaut au
|
||||
> seed**. Le gardien reel est la permission, pas le nom du role : un role
|
||||
> personnalise (ex. "chef-patissier") dote des bonnes permissions ouvre les
|
||||
> memes cas, sans changement de code. Les 5 roles seed sont un point de depart,
|
||||
> pas une liste fermee.
|
||||
|
||||
---
|
||||
|
||||
## 3. Diagramme de cas d'utilisation
|
||||
|
||||
Mermaid ne fournit pas de type `usecase` natif. La representation ci-dessous
|
||||
utilise un `flowchart` : les acteurs sont des noeuds a gauche, les cas
|
||||
d'utilisation sont des noeuds arrondis regroupes par sous-systeme, et les
|
||||
fleches portent les relations (`<<include>>`, `<<extend>>`) la ou elles
|
||||
ont du sens.
|
||||
Mermaid ne fournit pas de type `usecase` natif. La representation utilise un
|
||||
`flowchart` : les acteurs sont a gauche, les cas d'utilisation regroupes par
|
||||
sous-systeme. La permission qui conditionne chaque cas back-office est precisee
|
||||
en section 4.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
%% Acteurs
|
||||
Client(("Client<br/>borne kiosk"))
|
||||
Admin(("Administration<br/>role admin"))
|
||||
Prep(("Preparation<br/>role preparation"))
|
||||
Accueil(("Accueil<br/>role accueil"))
|
||||
Customer(("Customer<br/>borne kiosk<br/>non authentifie"))
|
||||
Admin(("Admin<br/>role admin"))
|
||||
Manager(("Manager<br/>role manager"))
|
||||
Kitchen(("Kitchen<br/>role kitchen<br/>lecture seule"))
|
||||
Counter(("Counter<br/>role counter"))
|
||||
Drive(("Drive<br/>role drive"))
|
||||
|
||||
%% Sous-systeme Borne client
|
||||
subgraph BORNE["Borne client - Bloc 1"]
|
||||
subgraph BORNE["Borne client - Bloc 1 (public)"]
|
||||
UC1(["Consulter le catalogue"])
|
||||
UC2(["Composer un menu"])
|
||||
UC3(["Passer une commande"])
|
||||
UC4(["Saisir le numero de retrait"])
|
||||
UC5(["Recevoir la confirmation"])
|
||||
UC6(["Payer la commande"])
|
||||
UC2(["Composer le panier"])
|
||||
UC3(["Consulter les allergenes"])
|
||||
UC4(["Passer une commande"])
|
||||
UC5(["Saisir le numero de retrait"])
|
||||
UC6(["Recevoir la confirmation"])
|
||||
end
|
||||
|
||||
%% Sous-systeme Back-office
|
||||
subgraph BACK["Back-office - Bloc 2"]
|
||||
UC10(["Gerer le catalogue<br/>categories, produits, menus"])
|
||||
UC11(["Gerer les utilisateurs et roles"])
|
||||
UC12(["Consulter les statistiques"])
|
||||
UC20(["Consulter la file de preparation"])
|
||||
UC21(["Faire avancer une commande"])
|
||||
UC30(["Saisir une commande<br/>comptoir ou drive"])
|
||||
UC31(["Remettre la commande au client"])
|
||||
UC40(["S'authentifier"])
|
||||
%% Sous-systeme Operations commande
|
||||
subgraph OPS["Operations commande - back-office"]
|
||||
UC10(["Saisir une commande<br/>comptoir / drive"])
|
||||
UC11(["Consulter la file de preparation"])
|
||||
UC12(["Remettre la commande"])
|
||||
UC13(["Annuler une commande"])
|
||||
end
|
||||
|
||||
%% Relations Client
|
||||
Client --> UC1
|
||||
Client --> UC2
|
||||
Client --> UC3
|
||||
Client --> UC6
|
||||
Client --> UC5
|
||||
%% Sous-systeme Catalogue
|
||||
subgraph CAT["Catalogue - back-office"]
|
||||
UC20(["Gerer produits"])
|
||||
UC21(["Gerer menus et slots"])
|
||||
UC22(["Gerer categories"])
|
||||
UC23(["Gerer ingredients,<br/>compositions, allergenes"])
|
||||
end
|
||||
|
||||
%% include / extend cote borne
|
||||
UC3 -. include .-> UC4
|
||||
UC3 -. include .-> UC6
|
||||
%% Sous-systeme Stock
|
||||
subgraph STK["Stock - back-office"]
|
||||
UC30(["Consulter le stock"])
|
||||
UC31(["Compter l'inventaire"])
|
||||
UC32(["Reapprovisionner"])
|
||||
end
|
||||
|
||||
%% Sous-systeme Administration
|
||||
subgraph ADM["Administration - back-office"]
|
||||
UC40(["Gerer les utilisateurs"])
|
||||
UC41(["Gerer roles et permissions"])
|
||||
UC42(["Consulter les statistiques"])
|
||||
end
|
||||
|
||||
%% Transverse
|
||||
UC50(["S'authentifier"])
|
||||
UC51(["Se deconnecter"])
|
||||
|
||||
%% Relations Customer
|
||||
Customer --> UC1
|
||||
Customer --> UC2
|
||||
Customer --> UC4
|
||||
Customer --> UC6
|
||||
UC2 -. include .-> UC1
|
||||
UC3 -. extend .-> UC2
|
||||
UC2 -. extend .-> UC3
|
||||
UC4 -. include .-> UC5
|
||||
UC4 -. include .-> UC2
|
||||
|
||||
%% Relations Administration
|
||||
%% Relations Counter / Drive (operations commande + stock)
|
||||
Counter --> UC10
|
||||
Counter --> UC11
|
||||
Counter --> UC12
|
||||
Counter --> UC13
|
||||
Drive --> UC10
|
||||
Drive --> UC11
|
||||
Drive --> UC12
|
||||
Drive --> UC13
|
||||
UC10 -. include .-> UC1
|
||||
|
||||
%% Kitchen (lecture seule)
|
||||
Kitchen --> UC11
|
||||
|
||||
%% Stock (kitchen / counter / drive / manager / admin)
|
||||
Kitchen --> UC30
|
||||
Kitchen --> UC31
|
||||
Counter --> UC30
|
||||
Counter --> UC31
|
||||
Drive --> UC30
|
||||
Drive --> UC31
|
||||
Manager --> UC30
|
||||
Manager --> UC31
|
||||
Manager --> UC32
|
||||
|
||||
%% Catalogue (manager + admin)
|
||||
Manager --> UC20
|
||||
Manager --> UC21
|
||||
Manager --> UC22
|
||||
Manager --> UC23
|
||||
Admin --> UC20
|
||||
Admin --> UC21
|
||||
Admin --> UC22
|
||||
Admin --> UC23
|
||||
|
||||
%% Administration (admin) + stats (manager + admin)
|
||||
Admin --> UC40
|
||||
Admin --> UC10
|
||||
Admin --> UC41
|
||||
Admin --> UC42
|
||||
Admin --> UC30
|
||||
Admin --> UC31
|
||||
Admin --> UC32
|
||||
Admin --> UC11
|
||||
Admin --> UC12
|
||||
Admin --> UC13
|
||||
Manager --> UC42
|
||||
|
||||
%% Relations Preparation
|
||||
Prep --> UC40
|
||||
Prep --> UC20
|
||||
Prep --> UC21
|
||||
|
||||
%% Relations Accueil
|
||||
Accueil --> UC40
|
||||
Accueil --> UC30
|
||||
Accueil --> UC31
|
||||
UC30 -. include .-> UC1
|
||||
|
||||
%% Authentification mutualisee
|
||||
UC10 -. include .-> UC40
|
||||
UC11 -. include .-> UC40
|
||||
UC20 -. include .-> UC40
|
||||
UC30 -. include .-> UC40
|
||||
%% Authentification mutualisee (tout cas back-office)
|
||||
UC10 -. include .-> UC50
|
||||
UC11 -. include .-> UC50
|
||||
UC20 -. include .-> UC50
|
||||
UC30 -. include .-> UC50
|
||||
UC40 -. include .-> UC50
|
||||
UC42 -. include .-> UC50
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Description des cas d'utilisation
|
||||
|
||||
### 4.1 Acteur Client (borne kiosk)
|
||||
### 4.1 Acteur Customer (borne kiosk, non authentifie)
|
||||
|
||||
| Cas | Description | Entites manipulees |
|
||||
| Cas | Operation MCT | Description | Entites manipulees |
|
||||
|---|---|---|---|
|
||||
| Consulter le catalogue | 3.1 LOAD_CATALOGUE | Parcourir categories, produits et menus disponibles, charges via `GET /api/categories`, `/api/products`, `/api/menus` (ou JSON fallback). | `category`, `product`, `menu`, `menu_slot`, `menu_slot_option` |
|
||||
| Composer le panier | 3.2 COMPOSE_CART | Ajouter produits a la carte ou menus ; remplir les slots d'un menu (`order_item_selection`), choisir le format Normal/Maxi, ajouter/retirer des ingredients (`order_item_modifier`). Panier volatil cote front, aucun ecrit BDD a ce stade. | `product`, `menu`, `menu_slot`, `menu_slot_option`, `ingredient`, `product_ingredient` |
|
||||
| Consulter les allergenes | (derive de 3.1) | Afficher en modal les allergenes d'un produit, **calcules** par jointure `product_ingredient -> ingredient_allergen -> allergen` (INCO 1169/2011). Etend la composition. | `allergen`, `ingredient_allergen`, `product_ingredient` |
|
||||
| Passer une commande | 3.3 CREATE_ORDER | Valider le panier et saisir le numero de retrait. Creation atomique : INSERT `customer_order` (`pending_payment` puis `paid` dans la meme transaction), `order_item` + selections + modifiers snapshotes, decrement du stock + `stock_movement`. | `customer_order`, `order_item`, `order_item_selection`, `order_item_modifier`, `ingredient`, `stock_movement` |
|
||||
| Saisir le numero de retrait | (inclus dans 3.3) | Renseigner le numero qui identifie le client. Tient lieu de paiement (cadre RNCP). Cas inclus par "Passer une commande". | `customer_order.order_number` |
|
||||
| Recevoir la confirmation | 3.4 DISPLAY_CONFIRMATION | Afficher l'ecran de confirmation avec le numero, apres reponse `201` (statut `paid`). La borne se reinitialise. | `customer_order` |
|
||||
|
||||
### 4.2 Acteurs Counter et Drive (roles `counter`, `drive`)
|
||||
|
||||
| Cas | Operation MCT | Permission | Description | Entites |
|
||||
|---|---|---|---|---|
|
||||
| Saisir une commande comptoir/drive | 4.1 CREATE_COUNTER_ORDER | `order.create` | Composer une commande pour un client au comptoir (`counter`) ou au drive (`drive`). Logique identique a CREATE_ORDER ; `source` auto-tague depuis `role.order_source`. Numero `C-`/`D-YYYY-MM-DD-NNN`. | `customer_order`, `order_item`, `order_item_selection`, `order_item_modifier`, `ingredient`, `stock_movement` |
|
||||
| Consulter la file de preparation | 5.1 LIST_ORDERS_DISPLAY | `order.read` | Voir les commandes `paid` triees par `paid_at` croissant, filtrees par `role_visible_source` (counter voit kiosk+counter ; drive voit drive). Couleur KDS = `now - paid_at`. | `customer_order`, `order_item`, `order_item_selection`, `order_item_modifier`, `role_visible_source` |
|
||||
| Remettre la commande | 6.1 DELIVER_ORDER | `order.deliver` | Geste unique `paid -> delivered`, `delivered_at = NOW()`. | `customer_order` |
|
||||
| Annuler une commande | 7.1 CANCEL_ORDER | `order.cancel` | Transition vers `cancelled` depuis `pending_payment`/`paid`, `cancelled_at = NOW()`. Re-credit du stock si `paid`. | `customer_order`, `ingredient`, `stock_movement` |
|
||||
|
||||
### 4.3 Acteur Kitchen (role `kitchen`, lecture seule)
|
||||
|
||||
| Cas | Operation MCT | Permission | Description | Entites |
|
||||
|---|---|---|---|---|
|
||||
| Consulter la file de preparation | 5.1 LIST_ORDERS_DISPLAY | `order.read` | Voir toutes les sources (kiosk, counter, drive) en lecture seule. **Aucune transition de statut** : le KDS est un affichage visuel. | `customer_order`, `order_item`, `order_item_selection`, `order_item_modifier`, `role_visible_source` |
|
||||
|
||||
### 4.4 Stock (Kitchen, Counter, Drive, Manager, Admin)
|
||||
|
||||
| Cas | Operation MCT | Permission | Description | Entites |
|
||||
|---|---|---|---|---|
|
||||
| Consulter le stock | 9.3 READ_STOCK | `stock.read` | Lister les ingredients avec stock courant ; alerte rupture calculee a l'affichage (`stock_quantity <= low_stock_threshold`). | `ingredient`, `stock_movement` |
|
||||
| Compter l'inventaire | 9.2 INVENTORY_COUNT | `stock.count` | Saisir un comptage physique ; le systeme enregistre l'ecart (`inventory_correction`). Inclut les equipiers (kitchen/counter/drive). | `ingredient`, `stock_movement` |
|
||||
| Reapprovisionner | 9.1 RESTOCK | `stock.manage` | Enregistrer une livraison en conditionnements (`+= N * pack_size`). Reserve manager/admin. | `ingredient`, `stock_movement` |
|
||||
|
||||
### 4.5 Catalogue (Manager, Admin)
|
||||
|
||||
| Cas | Operation MCT | Permissions | Description | Entites |
|
||||
|---|---|---|---|---|
|
||||
| Gerer produits | 8.1-8.3 CREATE/UPDATE/DELETE_PRODUCT | `product.create`/`update` (manager+admin), `product.delete` (admin seul) | CRUD produits (nom, prix, `vat_rate`, image, dispo). La suppression physique est reservee a `admin` et bloquee si reference (FK RESTRICT). | `product`, `category` |
|
||||
| Gerer menus et slots | 8.4-8.6 CREATE/UPDATE/DELETE_MENU | `menu.create`/`update` (manager+admin), `menu.delete` (admin seul) | CRUD menus avec leur configuration de slots (`menu_slot`, `menu_slot_option`) et le burger fixe. | `menu`, `menu_slot`, `menu_slot_option`, `product` |
|
||||
| Gerer categories | 8.7 MANAGE_CATEGORY | `category.manage` (manager+admin) | CRUD categories ; desactivation `is_active=0`. | `category` |
|
||||
| Gerer ingredients, compositions, allergenes | 8.8 MANAGE_INGREDIENT | `ingredient.manage` (manager+admin) | CRUD `ingredient` ; composition `product_ingredient` (quantites Normal/Maxi, retirable/ajoutable, supplement) ; mapping `ingredient_allergen` (14 allergenes UE). | `ingredient`, `product_ingredient`, `ingredient_allergen`, `allergen` |
|
||||
|
||||
### 4.6 Administration (role `admin`) + Stats (Manager, Admin)
|
||||
|
||||
| Cas | Operation MCT | Permissions | Description | Entites |
|
||||
|---|---|---|---|---|
|
||||
| Gerer les utilisateurs | 10.1-10.3 CREATE/UPDATE/DEACTIVATE_USER | `user.create`/`update`/`deactivate` (admin) ; `user.read` (admin+manager) | CRUD comptes back-office avec hash argon2id ; desactivation sans suppression (historique preserve). | `user`, `role` |
|
||||
| Gerer roles et permissions | 10.4 MANAGE_RBAC | `role.manage` (admin) | Editer la matrice `role_permission`, creer/modifier des roles personnalises (`default_route`, `order_source`), regler `role_visible_source`. Permissions statiques (declarees en migration). | `role`, `permission`, `role_permission`, `role_visible_source` |
|
||||
| Consulter les statistiques | 11.1 READ_STATS | `stats.read` (admin+manager) | Agregats par `service_day` (coupure 10h), top produits, taux d'annulation, temps moyen de remise `delivered_at - paid_at`, repartition par `source`/`service_mode`. | `customer_order`, `order_item` |
|
||||
|
||||
### 4.7 Cas transverses - Authentification
|
||||
|
||||
| Cas | Operation MCT | Description |
|
||||
|---|---|---|
|
||||
| Consulter le catalogue | Parcourir les categories, produits et menus disponibles. Charges via `GET /api/categories`, `/api/products`, `/api/menus` (ou JSON fallback). | `categorie`, `produit`, `menu` |
|
||||
| Composer un menu | Choisir burger + accompagnement + boisson + sauce, regler les options de taille (normale / grande) et de personnalisation. Etend "Passer une commande" car un menu compose est une variante d'item au panier. | `menu`, `menu_produit`, `produit` |
|
||||
| Passer une commande | Valider le panier, declencher la creation de la commande composee. Inclut la saisie du numero de retrait et le paiement. | `commande`, `ligne_commande` |
|
||||
| Saisir le numero de retrait | Renseigner le numero qui identifie le client au comptoir. Cas inclus par "Passer une commande". | `commande.numero` |
|
||||
| Payer la commande | Regler la commande une fois le panier compose et valide. Materialise la transition `pending_payment -> paid` de `state-commande.md`. Cas inclus par "Passer une commande". | `commande.statut`, `commande.paye_a` |
|
||||
| Recevoir la confirmation | Afficher l'ecran de confirmation avec le numero, apres paiement. | `commande` |
|
||||
|
||||
> Note de coherence : le cycle de vie comporte deux phases successives, la
|
||||
> composition de la commande puis son paiement (regle metier confirmee). Le cas
|
||||
> "Payer la commande" est retenu cote Client et materialise la transition
|
||||
> `pending_payment -> paid` de l'ENUM `statut`
|
||||
> (`dictionary.md` 3.5, `state-commande.md`).
|
||||
|
||||
### 4.2 Acteur Administration (role admin)
|
||||
|
||||
| Cas | Description | Entites manipulees |
|
||||
|---|---|---|
|
||||
| Gerer le catalogue | CRUD sur categories, produits et menus (libelles, prix, images, disponibilite, composition de menu). | `categorie`, `produit`, `menu`, `menu_produit` |
|
||||
| Gerer les utilisateurs et roles | CRUD sur les comptes back-office et leurs roles ; consultation de la matrice de permissions. | `user`, `role`, `permission`, `role_permission` |
|
||||
| Consulter les statistiques | Voir les commandes du jour de service, le chiffre d'affaires, les produits les plus commandes. | `commande`, `ligne_commande` |
|
||||
|
||||
### 4.3 Acteur Preparation (role preparation, ex-Cuisine)
|
||||
|
||||
| Cas | Description | Entites manipulees |
|
||||
|---|---|---|
|
||||
| Consulter la file de preparation | Afficher les commandes a preparer triees par heure de livraison croissante, tous canaux confondus. | `commande`, `ligne_commande` |
|
||||
| Faire avancer une commande | Declarer une commande "preparee", ce qui declenche une transition de statut (voir `state-commande.md`). | `commande.statut` |
|
||||
|
||||
### 4.4 Acteur Accueil (role accueil, recouvre Caisse)
|
||||
|
||||
| Cas | Description | Entites manipulees |
|
||||
|---|---|---|
|
||||
| Saisir une commande | Creer une commande pour un client au comptoir (`counter`) ou au drive (`drive`), en consultant le catalogue. | `commande`, `ligne_commande`, `produit`, `menu` |
|
||||
| Remettre la commande au client | Declarer une commande "livree" au moment de la remise physique. | `commande.statut` |
|
||||
|
||||
### 4.5 Cas transverse - S'authentifier
|
||||
|
||||
Tous les acteurs du back-office (Administration, Preparation, Accueil) passent
|
||||
par "S'authentifier" avant d'acceder a leurs cas. Modelise comme cas inclus
|
||||
(`<<include>>`) par chaque cas back-office pour eviter de surcharger le
|
||||
diagramme. Le Client de la borne n'est pas authentifie (canal `kiosk` public).
|
||||
| S'authentifier | 12.1 AUTHENTICATE_USER | Tous les roles back-office passent par ce cas avant d'acceder a leurs cas (relation `<<include>>`). Verification argon2id, regeneration de session (anti-fixation), `is_active=1` requis, redirection vers `role.default_route`. Le Customer du kiosk n'est pas authentifie. |
|
||||
| Se deconnecter | 12.2 LOGOUT_USER | Destruction de session (`session_destroy()`) sur clic ou expiration (idle 4h / absolu 10h). |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -188,35 +261,32 @@ diagramme. Le Client de la borne n'est pas authentifie (canal `kiosk` public).
|
|||
| Relation | Type | Justification |
|
||||
|---|---|---|
|
||||
| Passer une commande -> Saisir le numero de retrait | include | La saisie du numero fait partie integrante de toute validation de commande. |
|
||||
| Passer une commande -> Payer la commande | include | Le paiement suit la composition du panier et fait partie integrante du parcours (phase 2 du cycle de vie). |
|
||||
| Composer un menu -> Consulter le catalogue | include | Composer un menu suppose de parcourir les produits eligibles a chaque slot. |
|
||||
| Passer une commande -> Composer un menu | extend | Le menu est un cas optionnel : une commande peut ne contenir que des produits a la carte. La composition etend le parcours seulement si le client choisit un menu. |
|
||||
| Saisir une commande (Accueil) -> Consulter le catalogue | include | L'equipier consulte le catalogue pour saisir au comptoir / drive. |
|
||||
| Cas back-office -> S'authentifier | include | Acces conditionne a une session authentifiee. |
|
||||
| Passer une commande -> Composer le panier | include | Une commande resulte d'un panier compose. |
|
||||
| Composer le panier -> Consulter le catalogue | include | Composer suppose de parcourir les produits eligibles (a la carte ou par slot). |
|
||||
| Composer le panier -> Consulter les allergenes | extend | La consultation des allergenes est un cas optionnel declenche a la demande du client sur un produit. |
|
||||
| Saisir une commande (Counter/Drive) -> Consulter le catalogue | include | L'equipier consulte le catalogue pour saisir au comptoir/drive. |
|
||||
| Cas back-office -> S'authentifier | include | Acces conditionne a une session authentifiee detenant la permission requise. |
|
||||
|
||||
---
|
||||
|
||||
## 6. Incoherences remontees vers les autres livrables
|
||||
## 6. Points resolus par rapport au v0.1
|
||||
|
||||
Ces ecarts entre les sources sont signales pour arbitrage de l'auteur (la
|
||||
modelisation finale releve de sa decision, mantra de validation humaine).
|
||||
Les incoherences que le v0.1 remontait pour arbitrage sont desormais tranchees
|
||||
par le modele v0.2 (`dictionary.md`, `mct.md`).
|
||||
|
||||
1. **ENUM `statut` et phase de paiement (tranche)**
|
||||
Le dictionnaire (`dictionary.md` 3.5) definit
|
||||
`statut ENUM('pending_payment','paid','preparing','ready','delivered','cancelled')`
|
||||
avec un paiement explicite. La regle metier confirmee fixe deux phases
|
||||
successives, la composition de la commande puis son paiement. Le cas
|
||||
"Payer la commande" est donc retenu cote Client et materialise la transition
|
||||
`pending_payment -> paid`. Cet ecart est tranche : la machine canonique de
|
||||
`state-commande.md` fait foi.
|
||||
|
||||
2. **Acteur "Caisse" absent du RBAC**
|
||||
Aucun role `caisse` n'existe (`PROJECT_CONTEXT.md` section 7 : `admin`,
|
||||
`preparation`, `accueil`). La fonction d'encaissement de la consigne a ete
|
||||
rattachee a l'acteur **Accueil**. A confirmer.
|
||||
|
||||
3. **"Manager" vs "Admin"**
|
||||
La consigne parle de "Manager/Admin" ; le brief ne connait que `admin`. Les
|
||||
deux ont ete fusionnes en un acteur **Administration**. A confirmer si un
|
||||
role manager intermediaire est souhaite (le dictionnaire 3.8 mentionne un
|
||||
role `manager` extensible, non present dans le scope section 7).
|
||||
1. **Acteur "Caisse"** : ecarte. L'encaissement est atomique a la creation
|
||||
(saisie du numero = substitut de paiement, `mct.md` section 13) et realise
|
||||
par le Customer (kiosk) ou par `counter`/`drive` (back-office). Aucun role
|
||||
`caisse` n'est necessaire.
|
||||
2. **"Manager" vs "Admin"** : scindes en deux roles distincts. `manager` gere le
|
||||
catalogue (create/update), le stock/reappro et les stats ; `admin` ajoute les
|
||||
suppressions catalogue, la gestion des utilisateurs et le RBAC.
|
||||
3. **"Accueil" unique** : scinde en `counter` et `drive`, car le tag `source` et
|
||||
le filtre `role_visible_source` different selon le canal.
|
||||
4. **Machine a etats** : alignee sur les 4 etats du `dictionary.md` 3.10
|
||||
(`pending_payment -> paid -> delivered` + `cancelled`). Plus de `preparing` /
|
||||
`ready` : la cuisine (`kitchen`) est en lecture seule, la remise est un geste
|
||||
unique (`counter`/`drive`).
|
||||
5. **Modele permission-driven** : chaque cas back-office est rattache a sa
|
||||
permission (catalogue de 23 codes fige, `dictionary.md` 3.17). Le diagramme
|
||||
reflete la matrice seed ; le gardien effectif reste la permission.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue