Files
orion/app/modules/catalog/docs/data-model.md
Samir Boulahtit f141cc4e6a docs: migrate module documentation to single source of truth
Move 39 documentation files from top-level docs/ into each module's
docs/ folder, accessible via symlinks from docs/modules/. Create
data-model.md files for 10 modules with full schema documentation.
Replace originals with redirect stubs. Remove empty guide stubs.

Modules migrated: tenancy, billing, loyalty, marketplace, orders,
messaging, cms, catalog, inventory, hosting, prospecting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 23:38:37 +01:00

5.1 KiB
Raw Blame History

Catalog Data Model

Entity relationships and database schema for the catalog module.

Entity Relationship Overview

Store 1──* Product 1──* ProductTranslation
                   │
                   ├──* ProductMedia *──1 MediaFile
                   │
                   ├──? MarketplaceProduct (source)
                   │
                   └──* Inventory (from inventory module)

Models

Product

Store-specific product with independent copy pattern from marketplace imports. All monetary values stored as integer cents.

Field Type Constraints Description
id Integer PK Primary key
store_id Integer FK, not null Store ownership
marketplace_product_id Integer FK, nullable Optional marketplace source
store_sku String indexed Store's internal SKU
gtin String(50) indexed EAN/UPC barcode
gtin_type String(20) nullable gtin13, gtin14, gtin12, gtin8, isbn13, isbn10
price_cents Integer nullable Gross price in cents
sale_price_cents Integer nullable Sale price in cents
currency String(3) default "EUR" Currency code
brand String nullable Product brand
condition String nullable Product condition
availability String nullable Availability status
primary_image_url String nullable Main product image URL
additional_images JSON nullable Array of additional image URLs
download_url String nullable Digital product download URL
license_type String(50) nullable Digital product license
tax_rate_percent Integer not null, default 17 VAT rate (LU: 0, 3, 8, 14, 17)
supplier String(50) nullable codeswholesale, internal, etc.
supplier_product_id String nullable Supplier's product reference
cost_cents Integer nullable Cost to acquire in cents
margin_percent_x100 Integer nullable Markup × 100 (2550 = 25.5%)
is_digital Boolean default False, indexed Digital vs physical
product_type String(20) default "physical" physical, digital, service, subscription
is_featured Boolean default False Featured flag
is_active Boolean default True Active flag
display_order Integer default 0 Sort order
min_quantity Integer default 1 Min purchase quantity
max_quantity Integer nullable Max purchase quantity
fulfillment_email_template String nullable Template for digital delivery
created_at DateTime tz-aware Record creation time
updated_at DateTime tz-aware Record update time

Unique Constraint: (store_id, marketplace_product_id) Composite Indexes: (store_id, is_active), (store_id, is_featured), (store_id, store_sku), (supplier, supplier_product_id)

Key Properties: price, sale_price, cost (euro converters), net_price_cents (gross minus VAT), vat_amount_cents, profit_cents, profit_margin_percent, total_inventory, available_inventory

ProductTranslation

Store-specific multilingual content with SEO fields. Independent copy from marketplace translations.

Field Type Constraints Description
id Integer PK Primary key
product_id Integer FK, not null, cascade Parent product
language String(5) not null en, fr, de, lb
title String nullable Product title
description Text nullable Full description
short_description String(500) nullable Abbreviated description
meta_title String(70) nullable SEO title
meta_description String(160) nullable SEO description
url_slug String(255) nullable URL-friendly slug
created_at DateTime tz-aware Record creation time
updated_at DateTime tz-aware Record update time

Unique Constraint: (product_id, language)

ProductMedia

Association between products and media files with usage tracking.

Field Type Constraints Description
id Integer PK Primary key
product_id Integer FK, not null, cascade Product reference
media_id Integer FK, not null, cascade Media file reference
usage_type String(50) default "gallery" main_image, gallery, variant, thumbnail, swatch
display_order Integer default 0 Sort order
variant_id Integer nullable Variant reference
created_at DateTime tz-aware Record creation time
updated_at DateTime tz-aware Record update time

Unique Constraint: (product_id, media_id, usage_type)

Design Patterns

  • Independent copy pattern: Products are copied from marketplace sources, not linked. Store-specific data diverges independently.
  • Money as cents: All prices, costs, margins stored as integer cents
  • Luxembourg VAT: Supports all LU rates (0%, 3%, 8%, 14%, 17%)
  • Multi-type products: Physical, digital, service, subscription with type-specific fields
  • SEO per language: Meta title and description in each translation