← Ventures — GCStore Constellation
ERP — Level-2 Deep Dive
The ERP is the operational control plane of the venture: one cockpit that runs the business end-to-end — purchasing → inventory → sales → COGS → KPIs → fiscal close — and owns product truth (the catalog of listings, their options/variants, and the media library). It is used by the owner and a small set of role-gated internal users (partner, accountant, auditor). It is also the admin surface for GCStore Core: GCStore Core has no UI of its own, so the ERP is where its catalog, entitlements and fleet offers are administered. The storefront is fed from here; the financials are closed from here.
Internal architecture
A FastAPI backend and an Angular admin SPA over a relational store, organised as cooperating domains rather than a monolith of endpoints.
- Two database access paths, selected by function. Reads go through a pool bound to a least-privilege reader; writes go through a separate pool that runs each request in a single transaction under a role that can only touch the business tables. The blast radius of a compromised read path is "can read"; the fiscal snapshots and reference catalogs are not writable at all. This split is the backbone of the whole service.
- Control-plane domain (purchasing / inventory / sales / COGS). Purchases divide into physical-inventory invoices (which explode into items → units → individually-tracked inventory units) and expense-anchor invoices (cost with no stock). Inventory is history-driven: an append-only status history is the source of truth, and the scalar "current status" is a derived convenience — so any past date (e.g. a fiscal cutoff) is reconstructable exactly. COGS is the single crossing between the otherwise-independent purchase and sale worlds: cost originates at the purchase, rides the inventory unit, and attaches to a sale only when that unit is consumed.
- Fiscal / KPI engine. A layer of database views derives the P&L, cost of goods, inventory valuation, per-unit ROI and period roll-ups from the same operational rows — no parallel bookkeeping to drift. Profit is distributed across the units of a sale by a gross-share pro-rata rule, with a documented fallback. Reporting is built to be faithful to the actual filed forms, line by line.
- Listing & media library — product truth. A listing is a template: structured attributes flagged spec (descriptive) or option (selectable); options generate the cartesian set of variants, and price + availability live on the variant, never on the listing. Prices are generated — a base price plus a signed delta per option value — so a machine with 150+ configurations is priced by a handful of numbers, then still editable per row. Media is a content-addressed store (SHA-256): every photo is pulled into the ERP's own domain (an external URL is downloaded, never hot-linked, so a third party can't break an ad), normalised to WebP with fixed resolution variants, deduplicated by hash, and staged in a temp area promoted to its final home only on save — an abandoned edit leaves nothing to garbage-collect.
- Catalog & sales contracts (the storefront boundary). The catalog is projected by notify-then-fetch: every listing change writes a monotonic version, a full frozen snapshot, and an event into an outbox — a background worker delivers the notification, so the storefront can be down and lose nothing. Sales come back as an order of N listings: one sale record holds the order-level money (absolute, never split on write — the ROI views derive each unit's share live), and one bundle per listing carries the reconciliation state. A reported sale binds to the snapshot version the buyer actually saw — a consummated sale is immutable even as the ad keeps evolving. The contract is idempotent and timing-agnostic.
- GCStore Core admin proxy & customer reconciliation. The ERP forwards administrative calls to GCStore Core server-to-server (GCStore Core's admin UI is the ERP). Two customer worlds are kept distinct and reconciled: the ERP's own registry (real buyers captured from external marketplaces) and GCStore Core's identity registry; email is the imperfect join key, and a storefront sale is itself a linking event.
- Cross-cutting operations. Background workers (catalog delivery, media temp purge) run inside the API lifecycle; an owner-only backup subsystem produces logical database dumps and, independently, media archives.
Rejected alternatives worth noting: per-sale money was not split across lines (the views derive it — one source of truth, no rounding drift); listing prices were not stored only per-variant (the base+delta generator makes bulk pricing tractable); the storefront integration is system-to-system, authenticated with a shared key rather than a user token — machine-to-machine contract exchange kept cleanly separate from the ERP's own operator sign-in.
Interfaces
- → Storefront (Shop) — system-to-system: provides a read-only catalog API (versioned listings, options/variants, resolved prices, media manifests), a change-notification webhook driven by the outbox, and by-resolution serving of media bytes; accepts sales reports (idempotent create/correct). Authenticated with a shared integration key — a server-to-server credential that never reaches fiscal data.
- ⇆ GCStore Core — system-to-system: the ERP is its admin UI — administrative calls proxied server-to-server with a server-side key; and it pushes marketplace customers into GCStore Core's registry for reconciliation.
- ⇆ Identity — user-to-system: internal operators sign in against the ERP's own dedicated realm (OIDC) — exclusive to internal staff, never mixed with the customer-facing realm — then role-gated (owner / partner / accountant / auditor).
- ← GCStocks (upcoming): intraday/daily valuation of open positions, feeding the fiscal view of investment income.
Tech stack
Backend: Python · FastAPI · SQLAlchemy Core (async driver) · Pydantic; Pillow (+ HEIF) for media processing; async HTTP client for the admin proxy and outbox delivery. Frontend: Angular — standalone components, signals, reactive forms, role route-guards. Data: MariaDB, kept as the ERP's own database (separate from the shared app-data plane); view-heavy for the fiscal/ROI layer; append-only history where auditability matters. Deploy: Docker Compose behind the host nginx that owns TLS; background workers in the API process lifecycle.
Status & upcoming features
Production, in daily use for the full control-plane loop. The storefront catalog and sales contracts are live and integrated; the media-into-domain pipeline is live; the fiscal/KPI layer is in use for real close work.
- Per-channel publish control — selecting exactly which listings project to a given storefront.
- Payout ↔ sale reconciliation across marketplaces and gateways, as an audit aid.
- Extended sales contract carrying base-price + per-option deltas to the storefront (reverse-compatible).
- Expanded fiscal-snapshot automation, and the GCStocks valuation edge feeding the fiscal view of investment income.