Skip to content

Phase 2 — Plan

What we build after the Phase 1 MVP reaches UAT. Phase 2 widens scale to household-business revenue 1–3B VND (Personal Income Tax on % of revenue, accounting book S2a) and adds multi-channel F&B, general retail, and grocery. Target window: Jun → Sep 2026.

7Epics
3Core reasons P2 exists
Jul–SepReal build window
1–3BRevenue band (VND)

Read this first — the board is behind the code

A 2026-05-31 code audit found the dev team has already built much of what the PO feature-sheet marks "Phase 2 / not confirmed" (KDS, BOM/recipe, lot+expiry, barcode infra, COGS posting, X/Z report schema, single-user shift, split/merge). So most of Phase 2 is finish + wire-up + activate, not build from scratch. This plan tags every item:

  • Done — already in code & working (verify, don't rebuild)
  • Finish — schema/service exists, needs state-machine / UI / wiring
  • Build-new — genuinely absent, must be built

Before sprint planning, reconcile the PO sheet against code so we don't pay twice for built features.

The three reasons Phase 2 exists

Everything else is finishing work. These are the genuinely-new capabilities that define Phase 2 — none can be cut:

  1. E1 — Tax for the 1–3B band (S2a book + form 01/CNKD + T-VAN submit). The S2a fetcher today is a stub returning fake data; this is the headline net-new work.
  2. E2 — Business Type: retail + grocery. Code defaults to and hardcodes F&B in ~40–60% of commerce; the new industries need real branches.
  3. E4 — business customers with a tax code. Customers can't store a tax code (MST) today, so we can't issue VAT invoices to companies — a hard requirement that gates B2B.

Epic dependency map

Decisions locked (2026-05-31)

  • Shifts must be multi-employee → Phase 2 lands the feat/shift-variant-2 refactor (multi-employee shift / shift-assignment / shift-device / shift-report), not the current single-user PosSession.
  • QR self-order · Offline mode · Loyalty/voucher · Webshop → Phase 3. They are genuinely absent (build-from-scratch) and not required for the 1–3B + retail/grocery goal.

Priority tiers

TierMeaningEpics
P2-coreThe reason Phase 2 exists; cannot be cutE1 Tax · E2 Business Type · E4 CRM
P2-finishHigh value, mostly wiring already-built codeE3 POS · E5 Reports · E6 Cash
P2-importantReal value, small once E4 landsE7 Pricing

E1 · Tax for the 1–3B band Build-new · P2-core

Goal: Serve household businesses taxed on % of revenue — book S2a + tax declaration form 01/CNKD, submittable to the tax authority. This is the single biggest net-new chunk of Phase 2.

ItemTagEvidence / what to do
S2a PIT calculatorBuild-news2x-hkd.data-fetcher.service.ts is a stub with fake data — replace with real fetcher: revenue × industry tax-rate
Tax-rate % by industryBuild-newGeneric pricing/tax entity exists, but no merchant-industry → rate mapping; add schema + seed VN rates
Form 01/CNKDBuild-newAbsent — design form schema + XML builder (TaxDeclarationLevel TIRE_0–3 exists as a hook)
T-VAN submissionFinisht-van today is query-only (queryInvoiceMessages, queryTaxInformation); add submit* POST + audit
Reuse: book engineDoneLedgerDataFetcherService is book-type parameterized; S1a works, S2a template (s2a-hkd.typ) already exists
Reuse: e-invoice POSDonePOS_VAT/POS_SALE + REAL_TIME mode + BullMQ issuance production-ready

Depends on: E4 (business-customer tax code needed for company VAT invoices). Feeds: E5 (tax/compliance reports).

E2 · Business Type — retail + grocery Build-new · P2-core

Goal: Make the platform genuinely multi-industry. The enum exists but the behaviour is F&B-shaped.

ItemTagEvidence / what to do
Industry enumDoneMerchantIndustry = RETAIL/FNB/TICKET/OTHER already defined
De-hardcode F&BBuild-newmerchant.industry defaults to FNB; invoice templates + ~40–60% of commerce assume F&B — add retail/grocery branches
Retail catalog/inventoryFinishVariants exist; add retail framing (size/color, "catalog" vs "menu"), wire barcode flow (infra InventoryIdentifier done)
Grocery: lot/expiry surfacingDonelotNumber/expiryDate + Typesense isExpired/isExpiringSoon already there — surface in grocery UI
Industry-driven invoice/taxFinishMerchantInvoiceProfile.businessType (HOUSEHOLD/BUSINESS) drives tax method; extend mapping for retail/grocery

Depends on: E1 (tax method per industry). Feeds: E5 (industry-specific KPIs).

E3 · POS — multi-employee shift + KDS + X/Z Finish · P2-finish

Goal: Complete the F&B/retail floor. Mostly wiring already-built code — except the multi-employee shift refactor.

ItemTagEvidence / what to do
Multi-employee shiftFinishDECISION: land feat/shift-variant-2 (shift/shift-assignment/shift-device/shift-report, commit cc9baf892, currently need-review). Stabilize + merge, replacing single-user PosSession
KDS / send-to-kitchenDonekitchen-ticket schema + KitchenTicketService.sendToKitchen + Kitchen.screen.tsx + WS + Kafka→inventory all built
KDS ticket printingFinishWire sendToKitchenPrinterService (tauri-tcp-printer.helper.ts); define ticket format (2-ply)
X/Z reportFinishPosSessionReport (X/Z, full fields) exists; build print template + auto-generate Z on shift close
Split / move tableDonesale-check split + order-split/order-merge; add floor-plan context-menu buttons
Merge tableFinishorder-merge works on DRAFT only; confirm policy for PROCESSING orders
Manual order statusFinishAdd PATCH /sale-orders/:id/status if mid-order updates needed (today: checkout/cancel + webhook only)

Depends on: shift refactor stabilizing. Feeds: E5 (X/Z), E6 (shift cash reconciliation).

E4 · CRM — business customers + tax code + groups + payables Build-new · P2-core

Goal: Turn the thin Phase-1 contact record into a real CRM, and enable B2B invoicing. Largest absent cluster.

ItemTagEvidence / what to do
Business customer (with tax code)Build-newuser-profile has no tax_code/company → can't issue company VAT invoices; add fields + tax-code validation + invoice link
Customer groupsBuild-newAbsent — add CustomerGroup + member bridge; foundation for E7 segment pricing
Customer payablesBuild-newAbsent — add customer ledger/balance (FinanceVoucher has partyType=CUSTOMER to build on)
Supplier payablesFinishVendor master done; FinanceVoucher PAYMENT already auto-posts on PO-received — add the payables ledger/aggregation + UI
Individual customerDonename+phone+email works (customer.service.ts); add address

Depends on: —. Feeds: E1 (company VAT invoices), E7 (segment pricing).

E5 · Reports — P&L + inventory Finish · P2-finish

Goal: Give owners the numbers the 1–3B tier needs.

ItemTagEvidence / what to do
Revenue reportsDoneSalesReportService (daily/product/category) + UI built
All-system revenue dashboardFinishIn-progress; finish the total dashboard
P&L (lãi/lỗ)Build-newCOGS posts to finance (handleInventoryIssuedForSale) but no P&L service — build Revenue − COGS − OpEx
Inventory & best-sellerFinishUI is ComingSoon; rank from existing getProductSales; add stock/turnover report

Depends on: E2 (industry KPIs), E3 (shift data), E6 (expense data), E1 (tax). Schedule late.

E6 · Cash & expense depth Finish · P2-finish

Goal: Complete the cash side — manual payment vouchers + shift reconciliation.

ItemTagEvidence / what to do
Receipt voucherDoneFinanceVoucherTypes.RECEIPT auto-created on payment success
Payment voucherFinishPAYMENT type + auto-post on PO-received exist; build manual create/issue/void form (non-PO expenses)
Shift cash reconciliationFinishcashDiscrepancy computed in closeSession; auto-trigger ADJUSTMENT voucher (reason CASH_COUNT) + dashboard

Depends on: E3 (multi-shift). Feeds: E5 (P&L OpEx).

E7 · Pricing — campaign + segment Finish · P2-important

Goal: Move from flat pricing to campaign and customer-segment pricing. The rule engine is already powerful; it just lacks context fields.

ItemTagEvidence / what to do
Rule engineDoneOperators EQ/NE/GT/IN/CONTAINS… + promotion types STANDARD/BUY_GET + effectiveFrom/To
Time / day pricingDonedayOfWeek, calculatingAt already in PricingContext
Campaign pricingFinishAdd campaignId to promotion + context (time fields already usable)
Customer-segment (VIP/member)FinishAdd customerGroupId/customerType to PricingContext + sample rules

Depends on: E4 (customer groups). Feeds: —.

Deferred to Phase 3 (decided 2026-05-31)

Genuinely absent (build-from-scratch) and not required for the 1–3B + retail/grocery goal:

CapabilityWhy Phase 3Code state
QR self-orderNew guest-facing surface + table-QR mappingAbsent
Offline modeNeeds local store + sync queue + conflict resolution in TauriUI banner only
Loyalty / voucher / pointsPoints have EARN only (no REDEEM); no voucher modelPartial/absent
WebshopSeparate app, large scopeAbsent (planned)
Device hubCentral device control beyond connection infoAbsent

Proposed sequence (Jun → Sep 2026)

June is mostly Phase 1, not Phase 2

T6 = Phase 1 UAT + carry-over cleanup (the MVP gate). Real Phase 2 build capacity is ~Jul–Sep (≈10–11 weeks). Don't double-count Phase 1 debt as Phase 2.

BlockFocusWork
T6 (parallel)Spec + harvestWrite E1 tax + E2 Business-Type specs · "harvest sprint": activate already-built low-risk items (KDS print, X/Z template, InventoryTicket state machine) while UAT runs
T7 — foundationsThe 3 core reasonsE1 S2a calculator + industry tax-rate · E2 retail/grocery branches · E4 business-customer tax code
T8 — depthBuild on foundationsE1 form 01/CNKD + T-VAN submit · E3 land multi-shift refactor · E4 payables · E6 payment voucher + reconciliation · E7 pricing context
T9 — insight + hardenDownstream + stabilizeE5 P&L + inventory reports · integration + UAT for 1–3B & retail/grocery

Sizing guardrail

The WK22 review showed completion collapses when a cycle commits ~100 items vs the sustainable ~32 (16 members × 2). Size each Phase 2 sprint to that ceiling and keep Phase 1 carry-over out of the Phase 2 count.

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.