REFERENCE

Database

Database

MySQL/MariaDB via TypeORM. Entities are in src/entities/; the connection is configured in database.module.ts.

products ──< product_images       (one row per S3 slot: main, gallery-1, cart, …)
products ──< product_variants     (one row per combination; stock lives here)
cart_items >── product_variants
orders   ──< order_items >── products
orders   >── customers
categories  addresses  payment_cards  preferences  feed_posts  ugc_posts

A product's options — what it is sold in — are JSON on the product itself; the combinations they make are product_variants, each with its own SKU, optional price and stock. A product sold as one thing has a single variant with no values. product_stock, the old row-per-size table, is left in place on stores that predate this and read only by the migration that converted them.

Prices are stored as price_cents integers — never floats, to avoid rounding drift. What those units are called is store_settings.currency; the amount is the same number either way, so switching currency re-labels rather than converts. An order line keeps the price it charged and the variant's label as text, so a variant renamed or removed later cannot rewrite an old order. payment_cards holds display metadata only (brand + masked number); real cards belong in the processor's vault, keyed by a token.

Setup

CREATE DATABASE my_store CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'my_store'@'127.0.0.1' IDENTIFIED BY '<password>';
GRANT ALL PRIVILEGES ON my_store.* TO 'my_store'@'127.0.0.1';

Then set DB_* in apps/api/.env and run:

npm run seed --workspace=apps/api

DB_SYNCHRONIZE=true creates and updates tables from the entities on boot. That is convenient locally but rewrites schema and can drop columns, so the app refuses to start with it enabled when NODE_ENV=production — generate real migrations before deploying.

Database — Docs