Skip to Content
Living documentation — last reviewed 2026-05-28
FeaturesProduct StoreProduct store — Data model

Product store — Data model

Migration 0178_product_store.

products

ColumnNotes
organization_idFK organizations.
name≤120.
descriptionNullable.
price_in_centsVAT included.
currencyThe org’s currency at creation.
image_asset_idR2 key orgs/<org>/products/<product>/<asset>.webp. Served through GET /public/products/:token/image.
public_tokenUnique, 128-bit, the QR code handle.
statusproduct_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.

ColumnNotes
product_idFK products.
product_name, unit_price_in_centsCopied at sale time.
quantity, amount_in_cents, currencyamount = unit × quantity.
channelproduct_sale_channel: link, desk.
buyer_name, buyer_phonePhone in E.164.
membership_id, member_linkproduct_sale_member_link: session, phone, staff.
payment_transaction_idUnique.
process_idCardcom LowProfileId; settlement key.
receipt_tokenUnique, 72-bit; the short receipt link.
receipt_sent_at, receipt_channel, receipt_errorReceipt claim and outcome.
recorded_byDesk sales.

organization_sms_settings

ColumnNotes
organization_idPK.
enabledDefault false.
sender_name≤11, Latin letters, digits, space, +, *.

Ledger conventions

  • Store charges: metadata = { source: 'shop_order', orderId: <sale id>, productId }.
  • Card: provider = 'cardcom', membership_id set only when a member was matched.
  • Desk: provider = 'manual', method as recorded, idempotency_key = product-desk:<org>:<client key>.