← FTEG Platform Plan · Architecture · Yuzu Platform · Business OS
paused — ERP first 3 production systems target: fteg-commerce
Ecommerce 2.0 — Unify 9981 · Infinity · GDF
Three live shops run on two different table structures. This page explains exactly how each
system works today, why they look confusing side by side, how Infinity supplies GDF, and the plan to replace
all of them with one ERP + ecommerce platform (fteg-commerce, "Ecommerce 2.0").
Not the current build track. YMSB already has a live shop (9981). Keep using it.
Build
Business OS / ERP first (price book, purchasing, B2B quote → invoice).
Ecommerce 2.0 stays a written target — do not grow
fteg-commerce until ERP purchasing is usable.
1. Current situation — who runs what
| System | Path | Stack | Role |
| 9981 Yuzu (beelongz) |
/srv/www/9981beelongz |
Laravel 10 · Mix/Blade · laravel-admin BO · ~350 migrations |
B2C wine shop + events for YMSB. Single brand, but heavy ops: Loyverse POS, event tickets, MyInvois e-invoice, Google Sheets finance, Arriival courier. |
| Infinity |
/srv/www/infinity-bo-dev |
Laravel 9 · Vite · laravel-admin BO · ~164 migrations |
Inventory master — warehouse, purchasing (supplier invoices), B2B tiers, agent/referral wallet, outlets/POS. |
| GDF (infinity-ecom) |
/srv/www/infinity-ecom |
Same repo as Infinity, 2nd deploy + own DB |
Inventory sub — B2C web shop. Sells Infinity's stock just-in-time (see §2). |
| fteg-commerce (2.0 seed) |
/srv/www/fteg-products/commerce |
Laravel · bo-starter · 3 tables only |
Scaffold already reserved on the platform map as the migration target for all three. Today: flat categories / products / orders — no variants, stock, payments. |
Key clarification: Infinity and GDF are NOT two codebases — one repo, two deployments with two
MySQL databases; behavior switches on .env (INVENTORY_MODE=master|sub, APP_NAME).
The "different table structure" confusion is between 9981beelongz and the
Infinity/GDF repo — they were built independently and share no schema.
2. How Infinity supplies GDF (the actual mechanism)
GDF shop (sub, gdfDB) Infinity BO (master, infinityDB)
───────────────────── ─────────────────────────────────
① cron: catalog delta pull ◄──────────── GET /api/inventory/catalog/delta
upsert products/SKUs + balance mirror (API-key auth)
② customer checkout
OrderService::generate()
ProcureFromMasterService ─────────────► POST /api/agent/orders
GDF = a B2B "agent" user
real order on master
accept → SkuOut (stock truth)
③ book SupplierInvoice
(supplier code MASTER) → SkuIn
④ customer order accepted → local SkuOut (local net stock ≈ 0, JIT)
⑤ cancel → cancel master agent order + reverse local SkuIn/SkuOut
- Stock truth lives in Infinity (
sku_ins/sku_outs/sku_balances). GDF shows availability from inventory_balance_mirror, not its own near-zero balance.
- Idempotency: master
orders.agent_order_ref = sub order code. Fail-closed: if procurement fails, the GDF order is cancelled.
- Catalog identity across sides = stable
code on product / SKU / product-SKU; GDF may override price, rack, images via local_overrides.
- Docs:
infinity-bo-dev/docs/inventory-master/ (rollout, agent-b2b-order-design, runbook).
Superseded doc: docs/GDF-INFINITY-SYNC.md (the gdf_sync_orders /
gdf_sync_order_items design) was never migrated — those tables don't exist. Do not plan against it.
Production path is the master/sub + agent-order model above.
3. Schema comparison — why the tables "don't match"
| Domain | 9981beelongz | Infinity / GDF | 2.0 direction |
| Catalog |
products → product_skus; variants via option pivots + variants JSON; types single/bundle/service/ticket |
products → product_sku → separate inventory skus + sku_uoms (UOM conversion); typed extensions (sku_wine, sku_nihonshu) |
Adopt Infinity's split: sellable SKU ≠ inventory SKU + UOM. Variants + ticket/bundle types from 9981. |
| Stock |
stocks ledger rows (morph stockable) + parallel truth in Google Sheets gg_* + Loyverse |
Lot-based sku_ins / sku_outs (FIFO, morph in/out refs) + sku_balances + monthly closings + warehouse type ready/preorder |
Infinity's lot ledger wins — cleaner costing + audit. POS/Sheets become adapters feeding the ledger. |
| Orders |
orders + order_details; status Pending→Partially Paid→Paid→Shipped→Completed; source: online-ticket / loyverse / gg_orders / manual |
orders + polymorphic order_items; status pending→accepted→shipped→completed with separate payment_status; channel/outlet/agent fields |
One order doc: separate fulfilment status vs payment status (Infinity style) + channel/source (9981 style). |
| Customers |
users + tiers + loyalty points (loyalties/point_trxes) + referral |
users + user_tier_settings (B2B wholesale discount/min-qty) + agents + commission wallet (credit_ledgers, settlements, cashout) |
Identity in commerce; sell price from ERP tiers (not a shop price book). 9981 loyalty points stay a module. Infinity user_tier_settings is superseded by ERP erp_price_tiers. |
| Payments |
payments + channels; BillPlz / bank-transfer slip review via fteg/payment-gateway; morph billable |
payments + providers/methods + payment_allocations (partial payments across docs) |
fteg/payment-gateway as the gateway layer + Infinity's allocation model for B2B terms. |
| Fulfilment |
shippings + Arriival courier waybills |
delivery_orders docs + shipping zones/postcodes |
Delivery-order documents + provider adapters (Arriival first). |
| Purchasing |
vendors, vendor_orders/delivers/consignments |
suppliers, supplier_invoices → SkuIn, credit_notes, doc numbering |
Infinity's supplier-invoice → ledger flow; consignment from 9981 as a mode. |
| Promotions |
Promotions/PWP groups, vouchers, campaigns, spins, lucky draw |
Dual-era promo tables, bulk-purchase discount groups, rewards |
One promo engine: cart rules + tier rules; gamification (spins etc.) = 9981-only plugin. |
| Multi-entity |
Single deploy; companies + warehouses inside (legal entities, MyInvois certs) |
Two deploys, two DBs; master/sub via env flags |
One platform, multi-company + multi-warehouse rows; master/sub becomes an in-DB inter-company supply module. |
| Special modules |
Event tickets (first-class), Loyverse POS sync, MyInvois, Google Sheets finance, CandyForce, WhatsApp order |
Referral/commission wallet, outlets/cashiers POS, catalog master-sub sync, auditing (Telescope/owen-it) |
Keep as optional modules per tenant — this is the hard 20% of the migration. |
4. Options considered
| Option | What | Assessment |
| A. Big-bang rewrite |
Build 2.0 fully, migrate all three at once |
rejected 3 live production systems (map policy: "handle with care"); events + Loyverse + master/sub too much surface to cut over at once. |
| B. Merge into one legacy repo |
Port 9981 into Infinity repo (or reverse) |
rejected Inherits Laravel 9/10 + laravel-admin debt; schemas irreconcilable in place; no tenancy. |
C. Strangler onto fteg-commerce |
Grow the reserved 2.0 scaffold domain-by-domain; cut brands over one at a time; ERP finance stays on Business OS |
chosen Matches the platform map (fteg-commerce already marked "replaces 9981 / infinity-bo / gdf"); each cutover is reversible. |
Verdict: Ecommerce 2.0 =
fteg-commerce as a
multi-company commerce core
(catalog, lot-ledger inventory, orders, payments, fulfilment, promotions) with per-tenant modules
(events/Loyverse for 9981; tiers/referral/master-sub supply for Infinity+GDF).
Do not rebuild ERP inside it — accounting, e-invoice, CRM, purchasing approvals ride on
Business OS (sme-erp), same pattern as YMSB today.
5. Target architecture
fteg-store (billing / portal)
│
├── Business OS (sme-erp) ← ERP layer: CRM, quotes, invoices, e-Invoice, finance
│ ▲ read/summary sync (GMV, AR, stock valuation)
│ │
└── fteg-commerce (Ecommerce 2.0) ── one DB, multi-company
├── company: YMSB → brand 9981 (B2C + events + Loyverse channel)
├── company: Infinity → warehouse master (B2B tiers, purchasing)
└── company: GDF → B2C shop, supplied by Infinity
└── inter-company supply = internal module
(replaces API procure: same lot ledger, two companies)
- Inventory: single lot ledger (
sku_ins/sku_outs pattern) scoped by company + warehouse. Infinity→GDF becomes an internal transfer/sale document instead of cross-DB API calls — the mirror table and fail-closed procure disappear.
- Catalog: master data per company with share/subscribe (GDF subscribes to Infinity's catalog, keeps
local_overrides-style fields).
- Channels: storefront web, POS (Loyverse import), events, B2B trade login — all write the same
orders with channel + source.
- Packages: reuse
fteg/payment-gateway, pkg-myinvois, package-cms, package-seo, bo-starter shell.
5b. Pricing ownership (decided)
ERP is the only price book. Ecommerce does not store a second list.
Staff see every sell price in one glance: Business OS → Procurement → SKU prices
(SKU × B2C tiers × B2B tiers). The shop only asks: who is buying → which tier → that cell.
| Decision | Rule |
| Master | Business OS erp_price_tiers + erp_sku_prices + client price_tier_id |
| Shop | Resolves the tier and charges it. Guest = B2C retail. Member = B2C member (or assigned). B2B login = that client’s B2B tier. |
| One shop, two channels | Do not build a second public ecommerce for B2B. Public cart = B2C. Logged-in /trade = B2B self-order on the same catalog/stock. |
| Yuzu Marketing site | CMS / enquiry only (ymsbcorporate.fteg.dev). No cart. Partner apply → Inbox → convert to client + tier. |
| 9981 | Frozen legacy. Keep product_skus.price as a copy of ERP retail until E6. Do not add more price columns there. |
| Promos | Discount the tier price. Not a second book. |
| Shopee / Loyverse | Those channels keep their own prices. They are not the web book. |
YMSB detail: Yuzu Platform Plan § Pricing.
6. Roadmap (E-series)
| Phase | Status | Deliverable |
| E0 | done | Study both systems + this plan (schema reports, master/sub mechanism confirmed) |
| E1 | done | fteg-commerce scaffold live (catalog CRUD + order list, BO + public hosts) |
| E2 | paused | Core schema — deferred. ERP-first: do not start this while YMSB is still deepening Business OS. When resumed: companies/warehouses, sellable SKU → inventory SKU + UOM, lot ledger, doc numbering; seed from Infinity + 9981 exports (read-only). |
| E3 | planned | Orders + payments + fulfilment docs; checkout reads ERP tiers (no shop price book); promo engine v1 (off the tier); storefront checkout on one pilot brand (suggest GDF — smallest surface, no events/POS) |
| E4 | planned | GDF cutover: GDF storefront on 2.0; inter-company supply module replaces API procure (Infinity still legacy master via adapter until E5) |
| E5 | planned | Infinity cutover: purchasing, supplier invoices, B2B agents/referral wallet, outlets; retire master/sub env flags |
| E6 | deferred | 9981 cutover (last — most custom): storefront + orders first; event tickets, Loyverse sync, MyInvois, Sheets finance ported as modules; per Yuzu plan, 9981 commerce untouched until B2B on Business OS is proven |
7. Data mapping cheat-sheet (legacy → 2.0)
| 2.0 concept | From 9981 | From Infinity/GDF |
companies / warehouses | companies, warehouses | 1 company per deploy + warehouses (ready/preorder type) |
products / sellable_skus | products + product_skus (variants, ticket/bundle types) | products + product_sku (price_group, pre_order, discounts) |
inventory_skus + UOM | implicit (1:1 with product_skus) | skus, sku_uoms, unit_of_measurements |
| Lot ledger in/out | stocks rows (re-derive lots at migration) | sku_ins / sku_outs / sku_balances (near-direct copy) |
orders + items | orders + order_details (+ source/event meta) | orders + order_items (+ payment_status, agent_order_ref) |
| Payments + allocations | payments + billable morphs (BillPlz/slips) | payments + payment_allocations |
| Purchasing | vendor_orders/delivers/consignments | supplier_invoices/credit_notes |
| Sell price | Do not migrate product_skus.price as master — map to ERP B2C retail | Do not migrate Infinity price groups as master — map to ERP erp_price_tiers |
| Loyalty / wallet | tiers/user_tiers + points (not sell price) | agent wallet / referral (not sell price) |
| Tenant modules | event tickets, Loyverse, MyInvois, Sheets, campaigns | referral wallet, outlets/cashiers, catalog subscribe |
8. Risks & guardrails
- critical All three are production — map policy: no restructure/reseed/redeploy without explicit sign-off. GDF→Infinity procure API must keep working until E4.
- critical 9981 has three stock truths (app
stocks, Google Sheets gg_*, Loyverse). Migration needs a reconciliation freeze + opening-balance take-on, not a row copy.
- watch Order status semantics differ (9981 folds payment into status; Infinity splits it). Cutover mapping must be explicit per status.
- watch Event-ticket capacity holds (unpaid orders hold seats) and Loyverse bindings are 9981-unique — schedule them as their own module ports in E6, never "quick wins".
- note Infinity repo is Laravel 9 / PHP 8.1 — don't invest in upgrading it; effort goes to 2.0.
9. Code paths & docs
/srv/www/fteg-products/commerce — Ecommerce 2.0 home (public · BO)
/srv/www/9981beelongz — 9981 (docs: MODULES_LIST.md, ORDER_LIFECYCLE.md, CHECKOUT_FLOWS.md)
/srv/www/infinity-bo-dev — Infinity master (docs: docs/inventory-master/*, docs/README-referral.md)
/srv/www/infinity-ecom — GDF sub (same repo, own DB)
/srv/www/hubs/sme-erp — Business OS (ERP layer)
- Related plans: Architecture · Yuzu Platform · Yuzu sales channels · Business OS
Ecommerce 2.0 · Loading version…