Database model
Every shop owns a full Solidus schema; this page shows the lean core plus each shop's custom tables. Update this page in the same PR that adds a migration.
Solidus core (shared shape, one database per shop)
erDiagram
ORDER ||--o{ LINE_ITEM : contains
LINE_ITEM }o--|| VARIANT : of
VARIANT }o--|| PRODUCT : belongs_to
PRODUCT }o--o{ TAXON : classified
ORDER ||--o{ SHIPMENT : ships_as
SHIPMENT }o--|| STOCK_LOCATION : from
ORDER ||--o{ PAYMENT : paid_by
PAYMENT }o--|| PAYMENT_METHOD : via
ORDER }o--|| USER : placed_by
ORDER }o--o| PROMOTION : discounted_by
USER ||--o{ ADDRESS : has
Custom tables per shop
erDiagram
USER ||--o{ PET : "wagwhisker: profiles"
PET {
string name
date birthday "immutable, drives birthday baskets"
string species
jsonb feeding_data
}
PRODUCT ||--o{ PRICE_CHECK : "wagwhisker: best price crawls"
PRICE_CHECK {
string competitor
string country
datetime checked_at
}
USER ||--o{ ASSISTANT_CONVERSATION : "all shops: AI finder"
ASSISTANT_CONVERSATION {
text summary "feeds FAQ statistics"
}
NEWSLETTER_VOUCHER {
string code
datetime expires_at
}
DEMO_EVENT {
string kind "showcase analytics"
}
USER ||--o| PILOT_PROFILE : "flugschule"
PILOT_PROFILE {
string licence_level
date licence_since
int logged_hours
}
COURSE ||--o{ COURSE_DAY : "flugschule: weather gated"
COURSE_DAY ||--o{ PARTICIPATION : validated
PARTICIPATION }o--|| USER : by
PARTICIPATION {
bool validated "attendance drives progression"
}
USER ||--o{ FLIGHT_LOG : "IGC uploads"
FLIGHT_LOG {
string igc_file
float distance_km "B licence XC check"
}
LINE_ITEM {
int deposit_pence "flugschule instalments"
}
The flight school's licence engine derives progression from validated participations and flight logs (Uebungshang days unlock Hoehenfluege; 40 Hoehenfluege plus theory unlock the A licence test; the B licence checks a cross country flight of at least 10 km straight from the uploaded IGC file). State is always derived from evidence rows, never stored as a mutable flag.