Model of Conceptual Treatments (MCT) — Wakdo
Merise phase : P1 - Conception, step 3 (after MCD)
Version : v0.2 — prod-like, 4-state machine
Date : 2026-06-04
Branch : feat/p1-conception
Status : prod-like — all D1-D8 + stock decisions applied (see docs/notes/revue-alignement-p1.md §7)
Author : BYAN (methodology layer)
1. Purpose
The MCT (Model of Conceptual Treatments) describes the business operations of the Wakdo
domain in the canonical Merise form: triggering event -> operation -> emitted result.
It answers the question: what happens in the domain, and when?
It does not answer: who does what, on which workstation, in which organisational order
(the MOT level is intentionally skipped — agile shortcut, consistent with the solo RNCP
framework).
The MCT covers:
- The order lifecycle end-to-end (kiosk, counter, drive)
- Catalogue management (manager / admin)
- User and role management (admin)
- Back-office authentication (all back-office actors)
Identified actors:
| Actor |
Code |
Interface |
| Customer (kiosk) |
CUSTOMER |
Touch kiosk (public, unauthenticated) |
| Counter staff |
COUNTER |
Back-office, role counter |
| Drive staff |
DRIVE |
Back-office, role drive |
| Kitchen staff |
KITCHEN |
Back-office, role kitchen (read-only on orders) |
| Manager |
MANAGER |
Back-office, role manager |
| Administrator |
ADMIN |
Back-office, role admin |
| System |
SYS |
Internal API / PHP logic |
MCD cross-reference: each operation references entities from the MCD (section 14).
The MCT is consistent with the customer_order.status state machine:
pending_payment -> paid -> delivered
| |
+--------------+-----------> cancelled (from any non-terminal state)
Dropped states (compared to v0.1): preparing and ready are removed.
Rationale: in a fast-food context the kitchen display (KDS) is a visual system; staff read
the ticket and act. The single staff gesture is "deliver". KPI is total time
delivered_at - paid_at (SLA approx. 10 min). KDS colour coding is computed from
now - paid_at; no additional stored state is required.
Dropped operations (compared to v0.1): MARK_IN_PREPARATION (MARQUER_EN_PREPARATION)
and MARK_READY (MARQUER_PRETE) are removed because their intermediate states no longer
exist. DELIVER_ORDER becomes the sole status-advancing action for counter/drive staff.
2. Representation conventions
Operation format
[TRIGGERING EVENT(S)]
|
| [SYNCHRONISATION RULE / CONDITION]
v
( OPERATION )
|
v
[EMITTED RESULT(S)]
Synchronisations:
AND: all events must be present simultaneously to trigger the operation.
OR: any one of the events is sufficient.
Conditions: expressed in square brackets [condition] on the incoming arc.
Textual notation
For each operation the document provides:
- Triggering event(s): what occurs and causes the operation.
- Actor(s): who initiates (or validates).
- Synchronisation:
AND / OR if multiple events, plus condition.
- Operation: name and description of what it does.
- MCD entities touched: read (R) or write (W).
- Result(s): what is emitted or produced.
3. Domain 1 — Order lifecycle (kiosk)
3.1 LOAD_CATALOGUE
| Field |
Value |
| Triggering event |
Customer opens the kiosk (connection to the kiosk endpoint) |
| Actor |
CUSTOMER |
| Synchronisation |
None (single event) |
| Condition |
The kiosk is in service (within business hours 10:00-01:00) |
| Operation |
LOAD_CATALOGUE |
| Description |
Retrieval of active categories, available products, and available menus (with their slots and eligible options) for display on the kiosk screen. |
| MCD entities |
R: category (is_active=1), product (is_available=1), menu (is_available=1), menu_slot, menu_slot_option, ingredient (is_active=1), allergen, ingredient_allergen |
| Result |
Catalogue loaded; kiosk displays the home screen |
3.2 COMPOSE_CART
| Field |
Value |
| Triggering event |
Customer selects a product or a menu on the kiosk |
| Actor |
CUSTOMER |
| Synchronisation |
Repeatable event (OR: add product, add menu, change quantity, remove item, choose menu slot, choose format Normal/Maxi, add/remove ingredient modifier) |
| Condition |
The selected product or menu has is_available=1 |
| Operation |
COMPOSE_CART |
| Description |
In-memory cart construction: add an item (standalone product or menu), select slot products (order_item_selection), optionally modify ingredients (order_item_modifier), choose Normal or Maxi format for menus, recalculate TTC total. The cart is a volatile client-side structure; no database write at this stage. |
| MCD entities |
R: product, menu, menu_slot, menu_slot_option, ingredient, product_ingredient — W: none (volatile front-end state) |
| Result |
Cart updated, total recalculated, summary displayed |
3.3 CREATE_ORDER
| Field |
Value |
| Triggering events |
1. Customer confirms cart (presses "Validate") AND 2. Customer enters their order number (RNCP payment substitute) |
| Actor |
CUSTOMER |
| Synchronisation |
AND (both actions required) |
| Condition |
Cart contains at least 1 item. The order number entered is non-empty. |
| Operation |
CREATE_ORDER |
| Description |
Atomic order creation: INSERT customer_order with status pending_payment, source kiosk, snapshot of HT/VAT/TTC totals (computed line by line using vat_rate snapshotted per item). INSERT order_item lines with label_snapshot, unit_price_cents_snapshot, vat_rate_snapshot. INSERT order_item_selection for each slot filled in a menu item. INSERT order_item_modifier for each ingredient modification. Decrement ingredient.stock_quantity for each ingredient consumed (adjusted by modifiers: remove => no decrement; add => extra decrement); INSERT one stock_movement row of type sale per affected ingredient unit. Stock decrements and order insert are within the same transaction. After the customer enters their order number, the status transitions pending_payment -> paid within the same transaction; paid_at is set. The system generates the order number in format K-YYYY-MM-DD-NNN. |
| MCD entities |
R: product, menu, ingredient, product_ingredient (snapshot) — W: customer_order (INSERT status pending_payment then UPDATE status paid, paid_at), order_item (INSERT N lines), order_item_selection (INSERT per menu slot chosen), order_item_modifier (INSERT per modification), ingredient (UPDATE stock_quantity), stock_movement (INSERT type sale per unit) |
| Result |
Order created (status paid at end of operation), order number displayed to customer, logical event ORDER_CREATED emitted toward the preparation domain |
3.4 DISPLAY_CONFIRMATION
| Field |
Value |
| Triggering event |
ORDER_CREATED (API response 201 after CREATE_ORDER) |
| Actor |
SYS |
| Synchronisation |
None |
| Condition |
API response contains an id, an order_number and status paid |
| Operation |
DISPLAY_CONFIRMATION |
| Description |
Display of the confirmation screen on the kiosk with the order number. The kiosk then resets for the next customer. |
| MCD entities |
R: none (data is in the API response) |
| Result |
Confirmation screen displayed; kiosk available for next order |
4. Domain 2 — Order lifecycle (counter and drive)
4.1 CREATE_COUNTER_ORDER
| Field |
Value |
| Triggering event |
A counter or drive staff member initiates a new order from the back-office |
| Actor |
COUNTER or DRIVE |
| Synchronisation |
None |
| Condition |
The actor is authenticated and holds permission order.create. The source is counter or drive (auto-tagged from role.order_source). |
| Operation |
CREATE_COUNTER_ORDER |
| Description |
Manual order composition via the back-office: select products and menus, choose service mode (dine_in/takeaway/drive), fill menu slots, add ingredient modifiers. Identical creation logic to CREATE_ORDER (snapshot, stock decrement in same transaction, atomic pending_payment -> paid transition). The source is auto-tagged from role.order_source (counter -> counter, drive -> drive). Order number format: C-YYYY-MM-DD-NNN (counter) or D-YYYY-MM-DD-NNN (drive). Cross-constraint: if source = 'drive' then service_mode = 'drive' (verified at creation). |
| MCD entities |
R: product, menu, menu_slot, menu_slot_option, ingredient, product_ingredient — W: customer_order (INSERT status pending_payment then UPDATE status paid, paid_at), order_item, order_item_selection, order_item_modifier, ingredient (stock decrement), stock_movement (INSERT type sale) |
| Result |
Order created (status paid), order number communicated to customer |
5. Domain 3 — Preparation display (kitchen)
5.1 LIST_ORDERS_DISPLAY
| Field |
Value |
| Triggering event |
Kitchen staff accesses or refreshes the preparation display |
| Actor |
KITCHEN (or COUNTER, DRIVE, ADMIN) |
| Synchronisation |
None |
| Condition |
The actor is authenticated and holds permission order.read. |
| Operation |
LIST_ORDERS_DISPLAY |
| Description |
Read customer_order rows with status paid, filtered by sources visible to the actor's role (from role_visible_source): kitchen sees all sources; counter sees kiosk+counter; drive sees drive. Orders are sorted by paid_at ascending (oldest first). For each order, display: order number, source, content (order_item with label_snapshot, quantity, format, slot selections, ingredient modifiers). KDS colour is computed from now - paid_at against the SLA threshold (approx. 10 min), not stored. Kitchen staff performs no status transition — this is a read-only operation. |
| MCD entities |
R: customer_order (status=paid), order_item, order_item_selection, order_item_modifier, role_visible_source |
| Result |
Preparation display list shown, sorted by payment time ascending |
6. Domain 4 — Delivery to customer
6.1 DELIVER_ORDER
| Field |
Value |
| Triggering events |
1. The order is at status paid AND 2. Counter or drive staff clicks "Delivered" |
| Actor |
COUNTER or DRIVE |
| Synchronisation |
AND |
| Condition |
The order has status paid. The actor holds permission order.deliver. The actor's role is consistent with the order source (counter staff handles kiosk+counter orders; drive staff handles drive orders — filtered by role_visible_source). |
| Operation |
DELIVER_ORDER |
| Description |
Single-gesture transition paid -> delivered. Sets delivered_at = NOW(). The order moves to history. This operation replaces the v0.1 two-step sequence (mark-ready then deliver); the kitchen's visual confirmation (KDS) is sufficient before this action. |
| MCD entities |
W: customer_order (UPDATE status paid -> delivered, delivered_at = NOW()) |
| Result |
Order at status delivered, lifecycle complete |
7. Domain 5 — Cancellation
7.1 CANCEL_ORDER
| Field |
Value |
| Triggering event |
An authorised actor requests cancellation of an order |
| Actor |
COUNTER, DRIVE, or ADMIN |
| Synchronisation |
None |
| Condition |
The order exists. customer_order.status is in ['pending_payment', 'paid']. Terminal statuses delivered and cancelled cannot transition to cancelled. The actor holds permission order.cancel. |
| Operation |
CANCEL_ORDER |
| Description |
Transition from current status to cancelled. Sets cancelled_at = NOW(). The order is retained in the database for history and stats (no physical deletion). If the current status is paid, stock is re-credited: for each ingredient consumed by the order (accounting for modifiers), ingredient.stock_quantity is incremented; one stock_movement row of type cancellation is inserted per affected ingredient unit. Stock re-credit and status update are within the same transaction. |
| MCD entities |
R: order_item, order_item_modifier, ingredient, product_ingredient — W: customer_order (UPDATE status -> cancelled, cancelled_at = NOW()), ingredient (UPDATE stock_quantity, conditional on status paid), stock_movement (INSERT type cancellation, conditional on status paid) |
| Result |
Order at status cancelled, visible in admin history |
8. Domain 6 — Catalogue management
8.1 CREATE_PRODUCT
| Field |
Value |
| Triggering event |
Admin or manager submits the product creation form |
| Actor |
ADMIN or MANAGER |
| Synchronisation |
None |
| Condition |
Actor holds permission product.create. Target category exists and is_active=1. name is non-empty. price_cents > 0. |
| Operation |
CREATE_PRODUCT |
| Description |
INSERT a new product with its category, name, price in cents, VAT rate in per-mille (vat_rate: 100=10%, 55=5.5%, default 100), optional image path. is_available=1 by default. |
| MCD entities |
R: category (FK validation) — W: product (INSERT) |
| Result |
Product created, redirect to product list |
8.2 UPDATE_PRODUCT
| Field |
Value |
| Triggering event |
Admin or manager submits the product update form |
| Actor |
ADMIN or MANAGER |
| Synchronisation |
None |
| Condition |
Actor holds permission product.update. Product exists. New values respect constraints (price_cents > 0, non-empty name). |
| Operation |
UPDATE_PRODUCT |
| Description |
UPDATE modifiable columns (name, description, price_cents, vat_rate, image_path, is_available, display_order, category_id). Snapshots already stored in order_item are not affected (historical integrity guaranteed by design). |
| MCD entities |
W: product (UPDATE) |
| Result |
Product updated, product list refreshed |
8.3 DELETE_PRODUCT
| Field |
Value |
| Triggering event |
Admin confirms deletion of a product |
| Actor |
ADMIN |
| Synchronisation |
None |
| Condition |
Actor holds permission product.delete. Product is not a slot option in any menu_slot_option (FK ON DELETE RESTRICT). Product is not referenced in any order_item historical line (FK ON DELETE RESTRICT). Preliminary check required. |
| Operation |
DELETE_PRODUCT |
| Description |
Physical deletion of the product if no FK constraint blocks. If the product is referenced in a menu slot or historical order line, deletion is blocked. The recommended alternative is to deactivate (is_available=0). Also blocks if the product is the burger_product_id of any menu. |
| MCD entities |
W: product (DELETE — blocked if referenced in menu_slot_option, order_item, or menu.burger_product_id) |
| Result |
Product deleted OR error "product in use" |
| Field |
Value |
| Triggering event |
Admin or manager submits the menu creation form with its slot configuration |
| Actor |
ADMIN or MANAGER |
| Synchronisation |
None |
| Condition |
Actor holds permission menu.create. name is non-empty. price_normal_cents > 0, price_maxi_cents > 0. burger_product_id references an existing product. At least one slot is defined with at least one option. |
| Operation |
CREATE_MENU |
| Description |
Transaction: INSERT menu (with burger_product_id, price_normal_cents, price_maxi_cents), then INSERT menu_slot rows (one per slot: drink, side, sauce...), then INSERT menu_slot_option rows (eligible products per slot). |
| MCD entities |
R: product (burger FK validation, slot options validation), category — W: menu (INSERT), menu_slot (INSERT), menu_slot_option (INSERT) |
| Result |
Menu created with its slot configuration, visible on the kiosk |
| Field |
Value |
| Triggering event |
Admin or manager submits the menu update form |
| Actor |
ADMIN or MANAGER |
| Synchronisation |
None |
| Condition |
Actor holds permission menu.update. Menu exists. Updated configuration preserves at least one slot with at least one option. |
| Operation |
UPDATE_MENU |
| Description |
UPDATE menu columns. If slot configuration is modified: DELETE all menu_slot_option rows for this menu's slots, DELETE menu_slot rows, then re-INSERT (delete-and-reinsert pattern, atomic in transaction). Snapshots in order_item are not affected. |
| MCD entities |
W: menu (UPDATE), menu_slot (DELETE + INSERT), menu_slot_option (DELETE + INSERT) |
| Result |
Menu updated |
| Field |
Value |
| Triggering event |
Admin confirms deletion of a menu |
| Actor |
ADMIN |
| Synchronisation |
None |
| Condition |
Actor holds permission menu.delete. Menu is not referenced in any order_item historical line (FK ON DELETE RESTRICT). Preliminary check required. |
| Operation |
DELETE_MENU |
| Description |
If no order_item references this menu: DELETE menu_slot_option (CASCADE from menu_slot), DELETE menu_slot (CASCADE from menu), DELETE menu. If historical references exist, propose deactivation (is_available=0) instead. |
| MCD entities |
W: menu_slot_option (DELETE CASCADE), menu_slot (DELETE CASCADE), menu (DELETE — blocked if referenced in order_item) |
| Result |
Menu deleted OR error "menu present in historical orders" |
8.7 MANAGE_CATEGORY
| Field |
Value |
| Triggering event |
Admin or manager creates, updates, or deactivates a category |
| Actor |
ADMIN or MANAGER |
| Synchronisation |
OR (create, update, deactivation) |
| Condition |
Actor holds permission category.manage. For deactivation: products and menus in the category are not auto-deactivated in DB (no CASCADE on is_active); the application layer proposes deactivating child products/menus. |
| Operation |
MANAGE_CATEGORY |
| Description |
CRUD on category. Deactivation (is_active=0) hides the category and its products from the kiosk without physical deletion. Physical deletion is blocked if products or menus reference this category (FK ON DELETE RESTRICT). |
| MCD entities |
W: category (INSERT / UPDATE / conditional DELETE) |
| Result |
Category created / updated / deactivated |
8.8 MANAGE_INGREDIENT
| Field |
Value |
| Triggering event |
Admin or manager creates, updates, or deactivates an ingredient; or manages product composition (product_ingredient) or allergen mapping (ingredient_allergen) |
| Actor |
ADMIN or MANAGER |
| Synchronisation |
OR (create ingredient, update ingredient, update composition, update allergen mapping) |
| Condition |
Actor holds permission ingredient.manage. |
| Operation |
MANAGE_INGREDIENT |
| Description |
CRUD on ingredient (name, unit, pack_size, pack_label, low_stock_threshold, is_active). Manage product_ingredient composition (quantity_normal, quantity_maxi, is_removable, is_addable, extra_price_cents) for any product. Manage ingredient_allergen mapping (14 EU regulated allergens). Deactivating an ingredient (is_active=0) hides it from the configurator without deletion. Physical deletion of ingredient is blocked if referenced in product_ingredient (FK ON DELETE RESTRICT) or stock_movement (FK ON DELETE RESTRICT). |
| MCD entities |
R: product (FK validation), allergen (FK validation) — W: ingredient (INSERT/UPDATE/DELETE conditional), product_ingredient (INSERT/UPDATE/DELETE), ingredient_allergen (INSERT/DELETE) |
| Result |
Ingredient / composition / allergen mapping updated |
9. Domain 7 — Stock management
9.1 RESTOCK
| Field |
Value |
| Triggering event |
Manager or admin records a delivery of ingredient packs |
| Actor |
MANAGER or ADMIN |
| Synchronisation |
None |
| Condition |
Actor holds permission stock.manage. Ingredient exists and is_active=1. Number of packs N >= 1. |
| Operation |
RESTOCK |
| Description |
UPDATE ingredient.stock_quantity += N * pack_size. INSERT one stock_movement row: type restock, delta += N * pack_size, user_id of the actor, optional note (e.g. delivery reference). Both writes are in the same transaction. |
| MCD entities |
R: ingredient — W: ingredient (UPDATE stock_quantity), stock_movement (INSERT type restock) |
| Result |
Stock incremented, movement logged |
9.2 INVENTORY_COUNT
| Field |
Value |
| Triggering event |
A staff member or manager records the result of a physical inventory count |
| Actor |
KITCHEN, COUNTER, DRIVE, MANAGER, or ADMIN |
| Synchronisation |
None |
| Condition |
Actor holds permission stock.count. Ingredient exists. Physical count actual_quantity >= 0. |
| Operation |
INVENTORY_COUNT |
| Description |
Compute delta = actual_quantity - ingredient.stock_quantity (may be negative or positive). UPDATE ingredient.stock_quantity = actual_quantity. INSERT one stock_movement row: type inventory_correction, delta = computed discrepancy, user_id of the actor, optional note. Both writes in the same transaction. |
| MCD entities |
R: ingredient (read current stock_quantity) — W: ingredient (UPDATE stock_quantity), stock_movement (INSERT type inventory_correction) |
| Result |
Stock reconciled to physical count, discrepancy logged |
9.3 READ_STOCK
| Field |
Value |
| Triggering event |
An authorised actor accesses the stock view |
| Actor |
KITCHEN, COUNTER, DRIVE, MANAGER, or ADMIN |
| Synchronisation |
None |
| Condition |
Actor holds permission stock.read. |
| Operation |
READ_STOCK |
| Description |
Read ingredient list with current stock_quantity, low_stock_threshold, pack_size, pack_label. Low-stock alert computed at display time: stock_quantity <= low_stock_threshold. Optional: read stock_movement history for a given ingredient, filtered by date range. |
| MCD entities |
R: ingredient, stock_movement (optional history) |
| Result |
Stock list displayed with low-stock indicators |
10. Domain 8 — User and role management (admin)
10.1 CREATE_USER
| Field |
Value |
| Triggering event |
Admin submits the user creation form |
| Actor |
ADMIN |
| Synchronisation |
None |
| Condition |
Actor holds permission user.create. Email does not already exist in user.email (UNIQUE constraint). A valid and active role_id is selected. |
| Operation |
CREATE_USER |
| Description |
INSERT user with argon2id password hash. Email is unique. role_id is mandatory (FK NOT NULL). is_active=1 by default. last_login_at=NULL at creation. |
| MCD entities |
R: role (FK validation) — W: user (INSERT) |
| Result |
User created, can log into the back-office |
10.2 UPDATE_USER
| Field |
Value |
| Triggering event |
Admin submits the user update form |
| Actor |
ADMIN |
| Synchronisation |
None |
| Condition |
Actor holds permission user.update. User exists. If a new password is provided, it is re-hashed. |
| Operation |
UPDATE_USER |
| Description |
UPDATE modifiable fields (first_name, last_name, email, role_id, is_active). If a new password is supplied, it replaces the existing hash (argon2id rehash). |
| MCD entities |
W: user (UPDATE) |
| Result |
User updated |
10.3 DEACTIVATE_USER
| Field |
Value |
| Triggering event |
Admin clicks "Deactivate" for a user |
| Actor |
ADMIN |
| Synchronisation |
None |
| Condition |
Actor holds permission user.deactivate. Admin cannot deactivate their own account (application-level protection). |
| Operation |
DEACTIVATE_USER |
| Description |
UPDATE is_active=0. The user's active session is invalidated on next access (middleware checks is_active=1 on each authenticated request). User is not deleted; history remains traceable. |
| MCD entities |
W: user (UPDATE is_active=0) |
| Result |
User deactivated, back-office access blocked |
10.4 MANAGE_RBAC
| Field |
Value |
| Triggering event |
Admin modifies permission assignments for a role, or creates / updates a custom role |
| Actor |
ADMIN |
| Synchronisation |
OR (update role permissions, create custom role, update role attributes) |
| Condition |
Actor holds permission role.manage. Selected permissions exist in the permission catalogue. |
| Operation |
MANAGE_RBAC |
| Description |
Update role_permission for a given role: DELETE existing assignments, INSERT new ones (delete-and-reinsert, atomic in transaction). Permissions themselves are static (declared in migration, not modifiable via UI). Also covers: CREATE/UPDATE custom role (code, label, description, default_route, order_source), UPDATE role_visible_source (visible dashboard sources for the role). RBAC architecture rule: application code tests permissions, not role names — adding a new role with correct permissions requires no code change. |
| MCD entities |
R: role, permission — W: role_permission (DELETE + INSERT), role (INSERT/UPDATE for custom roles), role_visible_source (INSERT/DELETE) |
| Result |
RBAC matrix updated, effective immediately for new requests of users bearing this role |
11. Domain 9 — Stats and KPI
11.1 READ_STATS
| Field |
Value |
| Triggering event |
Manager or admin accesses the stats dashboard |
| Actor |
MANAGER or ADMIN |
| Synchronisation |
None |
| Condition |
Actor holds permission stats.read. |
| Operation |
READ_STATS |
| Description |
Aggregate queries on customer_order and order_item. Key aggregations: order count and revenue (TTC) by service_day (computed with CASE WHEN HOUR(created_at) < 10 THEN DATE(created_at) - INTERVAL 1 DAY ELSE DATE(created_at) END; cutoff at 10:00); top products by label_snapshot COUNT in order_item; cancellation rate; average delivery time delivered_at - paid_at; breakdown by source and service_mode. Queries exclude cancelled orders from revenue sums but include them in volume counts. No additional stored column for service_day; computation at query time. |
| MCD entities |
R: customer_order, order_item |
| Result |
Stats dashboard displayed |
12. Domain 10 — Back-office authentication
12.1 AUTHENTICATE_USER
| Field |
Value |
| Triggering event |
An actor submits the login form |
| Actor |
COUNTER / DRIVE / KITCHEN / MANAGER / ADMIN |
| Synchronisation |
None |
| Condition |
Email exists in database. Password matches argon2id hash. User is_active=1. |
| Operation |
AUTHENTICATE_USER |
| Description |
Credential verification. If valid: session ID regeneration (protection against session fixation), storage of user_id and role_id in session, UPDATE last_login_at. Idle timeout: 4h. Absolute timeout: 10h. Redirect to role.default_route. |
| MCD entities |
R: user (verification), role (load permissions, default_route), role_permission — W: user (UPDATE last_login_at) |
| Result |
Session opened, redirect to role-specific default view |
12.2 LOGOUT_USER
| Field |
Value |
| Triggering event |
Actor clicks "Logout" OR session expires |
| Actor |
COUNTER / DRIVE / KITCHEN / MANAGER / ADMIN / SYS (expiry) |
| Synchronisation |
OR |
| Condition |
A valid session is open |
| Operation |
LOGOUT_USER |
| Description |
PHP session destruction (session_destroy()). Session deleted server-side. Session cookie invalidated. |
| MCD entities |
No database write (session management is in PHP native, outside DB for this project) |
| Result |
Session destroyed, redirect to login page |
13. State machine — customer_order.status
Summary of transitions covered by MCT operations.
[CUSTOMER / COUNTER / DRIVE]
CREATE_ORDER
CREATE_COUNTER_ORDER
|
v
[ pending_payment ] (order composed, payment pending)
|
[CUSTOMER / COUNTER / DRIVE] payment confirmed
(atomic within CREATE_ORDER / CREATE_COUNTER_ORDER)
|
v
[ paid ]
|
[COUNTER / DRIVE] DELIVER_ORDER
|
v
[ delivered ] (terminal, cannot be cancelled)
From pending_payment / paid:
[COUNTER, DRIVE, or ADMIN] CANCEL_ORDER
|
v
[ cancelled ] (terminal)
Note on the pending_payment -> paid transition: in the RNCP context, payment is
replaced by the customer entering their order number (kiosk) or by staff validation
(counter/drive). The transition is atomic within CREATE_ORDER and CREATE_COUNTER_ORDER.
The pending_payment status is not observable outside the transaction.
Dropped from v0.1: preparing and ready states; MARK_IN_PREPARATION and MARK_READY
operations. Kitchen staff have a read-only view of paid orders (LIST_ORDERS_DISPLAY). The
single delivery action (DELIVER_ORDER) collapses the v0.1 three-step sequence into one gesture.
14. Operations summary table
| # |
Operation |
Domain |
Actor |
W Entities |
R Entities |
| 1 |
LOAD_CATALOGUE |
Order kiosk |
CUSTOMER |
— |
category, product, menu, menu_slot, menu_slot_option, ingredient, allergen, ingredient_allergen |
| 2 |
COMPOSE_CART |
Order kiosk |
CUSTOMER |
— (volatile) |
product, menu, menu_slot, menu_slot_option, ingredient, product_ingredient |
| 3 |
CREATE_ORDER |
Order kiosk |
CUSTOMER |
customer_order, order_item, order_item_selection, order_item_modifier, ingredient, stock_movement |
product, menu, ingredient, product_ingredient |
| 4 |
DISPLAY_CONFIRMATION |
Order kiosk |
SYS |
— |
— |
| 5 |
CREATE_COUNTER_ORDER |
Order counter/drive |
COUNTER/DRIVE |
customer_order, order_item, order_item_selection, order_item_modifier, ingredient, stock_movement |
product, menu, menu_slot, menu_slot_option, ingredient, product_ingredient |
| 6 |
LIST_ORDERS_DISPLAY |
Preparation |
KITCHEN/COUNTER/DRIVE/ADMIN |
— |
customer_order, order_item, order_item_selection, order_item_modifier, role_visible_source |
| 7 |
DELIVER_ORDER |
Delivery |
COUNTER/DRIVE |
customer_order |
— |
| 8 |
CANCEL_ORDER |
Cancellation |
COUNTER/DRIVE/ADMIN |
customer_order, ingredient, stock_movement |
order_item, order_item_modifier, ingredient, product_ingredient |
| 9 |
CREATE_PRODUCT |
Catalogue |
ADMIN/MANAGER |
product |
category |
| 10 |
UPDATE_PRODUCT |
Catalogue |
ADMIN/MANAGER |
product |
— |
| 11 |
DELETE_PRODUCT |
Catalogue |
ADMIN |
product |
menu_slot_option, order_item, menu |
| 12 |
CREATE_MENU |
Catalogue |
ADMIN/MANAGER |
menu, menu_slot, menu_slot_option |
product, category |
| 13 |
UPDATE_MENU |
Catalogue |
ADMIN/MANAGER |
menu, menu_slot, menu_slot_option |
— |
| 14 |
DELETE_MENU |
Catalogue |
ADMIN |
menu_slot_option, menu_slot, menu |
order_item |
| 15 |
MANAGE_CATEGORY |
Catalogue |
ADMIN/MANAGER |
category |
product, menu |
| 16 |
MANAGE_INGREDIENT |
Catalogue |
ADMIN/MANAGER |
ingredient, product_ingredient, ingredient_allergen |
product, allergen |
| 17 |
RESTOCK |
Stock |
MANAGER/ADMIN |
ingredient, stock_movement |
ingredient |
| 18 |
INVENTORY_COUNT |
Stock |
KITCHEN/COUNTER/DRIVE/MANAGER/ADMIN |
ingredient, stock_movement |
ingredient |
| 19 |
READ_STOCK |
Stock |
KITCHEN/COUNTER/DRIVE/MANAGER/ADMIN |
— |
ingredient, stock_movement |
| 20 |
CREATE_USER |
RBAC |
ADMIN |
user |
role |
| 21 |
UPDATE_USER |
RBAC |
ADMIN |
user |
— |
| 22 |
DEACTIVATE_USER |
RBAC |
ADMIN |
user |
— |
| 23 |
MANAGE_RBAC |
RBAC |
ADMIN |
role_permission, role, role_visible_source |
role, permission |
| 24 |
READ_STATS |
Stats |
MANAGER/ADMIN |
— |
customer_order, order_item |
| 25 |
AUTHENTICATE_USER |
Auth |
ALL BACK |
user |
user, role, role_permission |
| 26 |
LOGOUT_USER |
Auth |
ALL BACK |
— |
— |
Total: 26 operations covering the complete Wakdo business lifecycle.
15. MCT -> MCD cross-validation (mantra #34)
Verification that each MCD entity participates in at least one MCT operation.
| MCD entity |
Operations that read |
Operations that write |
Coverage |
category |
1, 9, 12, 15 |
15 |
OK |
product |
1, 2, 3, 5, 9, 11, 12 |
9, 10, 11 |
OK |
menu |
1, 2, 3, 5, 12, 14 |
12, 13, 14 |
OK |
menu_slot |
1, 2, 5 |
12, 13, 14 |
OK |
menu_slot_option |
1, 2, 5, 11 |
12, 13, 14 |
OK |
ingredient |
1, 2, 3, 5, 8, 16, 17, 18, 19 |
3, 5, 8, 16, 17, 18 |
OK |
product_ingredient |
2, 3, 5, 8 |
16 |
OK |
allergen |
1 |
— (static seed) |
OK (*) |
ingredient_allergen |
1 |
16 |
OK |
customer_order |
6, 8, 24 |
3, 5, 7, 8 |
OK |
order_item |
6, 8, 14, 24 |
3, 5 |
OK |
order_item_selection |
6 |
3, 5 |
OK |
order_item_modifier |
6, 8 |
3, 5 |
OK |
user |
25 |
20, 21, 22, 25 |
OK |
role |
20, 23, 25 |
23 |
OK |
role_visible_source |
6 |
23 |
OK |
permission |
23 |
— (static seed) |
OK (*) |
role_permission |
25 |
23 |
OK |
stock_movement |
19 |
3, 5, 8, 17, 18 |
OK |
(*) allergen and permission are read-only at the MCT level: their values are declared
in seed migrations and are not modifiable via the UI. allergen is managed indirectly
via ingredient_allergen in MANAGE_INGREDIENT.
Conclusion: 19/19 entities covered. MCT <-> MCD consistency validated.