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

SystemPathStackRole
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
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"

Domain9981beelongzInfinity / GDF2.0 direction
Catalog productsproduct_skus; variants via option pivots + variants JSON; types single/bundle/service/ticket productsproduct_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_invoicesSkuIn, 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

OptionWhatAssessment
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)

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.
DecisionRule
MasterBusiness OS erp_price_tiers + erp_sku_prices + client price_tier_id
ShopResolves the tier and charges it. Guest = B2C retail. Member = B2C member (or assigned). B2B login = that client’s B2B tier.
One shop, two channelsDo not build a second public ecommerce for B2B. Public cart = B2C. Logged-in /trade = B2B self-order on the same catalog/stock.
Yuzu Marketing siteCMS / enquiry only (ymsbcorporate.fteg.dev). No cart. Partner apply → Inbox → convert to client + tier.
9981Frozen legacy. Keep product_skus.price as a copy of ERP retail until E6. Do not add more price columns there.
PromosDiscount the tier price. Not a second book.
Shopee / LoyverseThose channels keep their own prices. They are not the web book.

YMSB detail: Yuzu Platform Plan § Pricing.

6. Roadmap (E-series)

PhaseStatusDeliverable
E0doneStudy both systems + this plan (schema reports, master/sub mechanism confirmed)
E1donefteg-commerce scaffold live (catalog CRUD + order list, BO + public hosts)
E2pausedCore 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).
E3plannedOrders + 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)
E4plannedGDF cutover: GDF storefront on 2.0; inter-company supply module replaces API procure (Infinity still legacy master via adapter until E5)
E5plannedInfinity cutover: purchasing, supplier invoices, B2B agents/referral wallet, outlets; retire master/sub env flags
E6deferred9981 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 conceptFrom 9981From Infinity/GDF
companies / warehousescompanies, warehouses1 company per deploy + warehouses (ready/preorder type)
products / sellable_skusproducts + product_skus (variants, ticket/bundle types)products + product_sku (price_group, pre_order, discounts)
inventory_skus + UOMimplicit (1:1 with product_skus)skus, sku_uoms, unit_of_measurements
Lot ledger in/outstocks rows (re-derive lots at migration)sku_ins / sku_outs / sku_balances (near-direct copy)
orders + itemsorders + order_details (+ source/event meta)orders + order_items (+ payment_status, agent_order_ref)
Payments + allocationspayments + billable morphs (BillPlz/slips)payments + payment_allocations
Purchasingvendor_orders/delivers/consignmentssupplier_invoices/credit_notes
Sell priceDo not migrate product_skus.price as master — map to ERP B2C retailDo not migrate Infinity price groups as master — map to ERP erp_price_tiers
Loyalty / wallettiers/user_tiers + points (not sell price)agent wallet / referral (not sell price)
Tenant modulesevent tickets, Loyverse, MyInvois, Sheets, campaignsreferral wallet, outlets/cashiers, catalog subscribe

8. Risks & guardrails

9. Code paths & docs

Ecommerce 2.0 · Loading version…