Product store — Data model
Migration 0178_product_store.
products
| Column | Notes |
|---|---|
organization_id | FK organizations. |
name | ≤120. |
description | Nullable. |
price_in_cents | VAT included. |
currency | The org’s currency at creation. |
image_asset_id | R2 key orgs/<org>/products/<product>/<asset>.webp. Served through GET /public/products/:token/image. |
public_token | Unique, 128-bit, the QR code handle. |
status | product_status: active, archived. |
sort_order, created_by, timestamps |
product_sales
One row per sale. The money is the linked payment_transactions row; the sale’s status is derived from it.
| Column | Notes |
|---|---|
product_id | FK products. |
product_name, unit_price_in_cents | Copied at sale time. |
quantity, amount_in_cents, currency | amount = unit × quantity. |
channel | product_sale_channel: link, desk. |
buyer_name, buyer_phone | Phone in E.164. |
membership_id, member_link | product_sale_member_link: session, phone, staff. |
payment_transaction_id | Unique. |
process_id | Cardcom LowProfileId; settlement key. |
receipt_token | Unique, 72-bit; the short receipt link. |
receipt_sent_at, receipt_channel, receipt_error | Receipt claim and outcome. |
recorded_by | Desk sales. |
organization_sms_settings
| Column | Notes |
|---|---|
organization_id | PK. |
enabled | Default false. |
sender_name | ≤11, Latin letters, digits, space, +, *. |
Ledger conventions
- Store charges:
metadata = { source: 'shop_order', orderId: <sale id>, productId }. - Card:
provider = 'cardcom',membership_idset only when a member was matched. - Desk:
provider = 'manual',methodas recorded,idempotency_key = product-desk:<org>:<client key>.