Skip to main content

JikoXpress Financial System Architecture

Version 1.2.0 | April 2026 | QBIT SPARK CO LIMITED
FullRefined architecture,architecture databased flow,on userfull journeysdesign sessions — all scenarios, edge cases, and entitydecisions designcaptured.


Table of Contents

  1. Overview & Core Principles
  2. Platform Context
  3. Two Financial Worlds
  4. Treasury Design
  5. Wallet System Components
  6. Chart of Accounts
  7. EntityMoney DesignSplitting
  8. DataEscrow Flows
  9. User JourneysSystem
  10. Payment Channels
  11. EscrowFull SystemMoney Journey — All Scenarios
  12. MoneySubscription Splitting
  13. Platform OffersPayments
  14. Settlements & WithdrawalsPayouts
  15. P&LRefunds & Cancellations
  16. Admin Withdrawal
  17. PSP Reconciliation
  18. Reporting
  19. SecuritySafety Rules & RulesIntegrity Checks
  20. Decision Log

1. Overview & Core Principles

JikoXpress financial system is a unified internal accounting engine — a proper ledger that tracks every single money movement acrosson the platform —platform, regardless of amount (even TZS 0.00), channel, or purpose.

Core Principles

  • — cash,
  • — every
  • — internal
  • — splits
  • — any
    PrincipleDescription
    Every event is a transaction Cash, mobile money, wallet, kitchen wallet, TZS 0 promo orders — all recorded
    Double entry accounting Every debit has a credit,credit. booksBooks always balance
    Single source of truth Internal ledger is authoritative,authoritative — not the external providerPSP
    Dynamic money splitting Splits are configurable,passed as parameters, not hardcoded
    Escrow is a flag Any transaction can be held,held — decided at runtime notby hardcodedthe caller
    Everyone has one walletSame JikoXpress account can be customer, kitchen owner, and rider — one wallet
    Counter orders stay outsidePOS/cash/kitchen custom payments never enter the treasury pool
    Platform earns on online onlyService fee applies only to App and WhatsApp orders

    2. Platform Context

    JikoXpress Pro connects customers with local chefs and restaurants (like Toasty for East Africa). The platform has:

    • 7 sales channels: POS, Kiosk, Table QR, Mobile App, WhatsApp, Drive-Through, Direct Counter
    • Kitchen4 walletsubscription istiers: separateSTARTER, GROWING, PROFESSIONAL, ENTERPRISE
    • Multiple fulfillment types: Dine-in, platformPickup, recordsDelivery, usageDrive-Through
    • but
    • East doesAfrica notfirst: manageBuilt itfor M-Pesa, Tigo Pesa, Airtel Money via Selcom, Azampay

    Who Are the Actors?

    Every person on the platform has one account and one wallet — regardless of their role:

    Same JikoXpress account can be:
    ├── Customer       — orders food via App/WhatsApp
    ├── Kitchen owner  — runs a kitchen on the platform
    └── Rider          — delivers orders for kitchens
    

    One person. One wallet. All roles.


    3. Two Separate Financial Worlds

    Not all money flows through JikoXpress. There are two separate worlds:

    ┌──────────────────────────────────────────────────────┐
    │              WORLD 1 — JikoXpress Platform TreasuryPool                │
    │                                                        Commission,
    wallets,  settlements,App offersorders, WhatsApp orders                          │
    │  OneMoney internalflows ledgerthrough our PSP accounts                 │
    │  Treasury tracks everything                           │
    │  Platform earns service fee here                      │
    └──────────────────────────────────────────────────────┘
    
    ┌──────────────────────────────────────────────────────┐
    │         KitchenWORLD Customer2 Wallet— Kitchen's Own World                 │
    │                                                        Kitchen
    manages  independentlyPOS cash, card, kitchen custom payments              │
    │  Money goes directly to kitchen's physical till       │
    │  or kitchen's own mobile money account                │
    │  Treasury never sees this money                       │
    │  Platform onlyearns recordsZERO "usedhere as(covered payment"by subscription)  │
    └──────────────────────────────────────────────────────┘
    

    Which Channels Belong to Which World?

    ChannelWorldService FeeTreasury Involvement
    Mobile AppJikoXpress PoolYesFull
    WhatsAppJikoXpress PoolYesFull
    POS — CashKitchen's WorldNoNone
    POS — CardKitchen's WorldNoNone
    POS — Kitchen WalletKitchen's WorldNoNone
    POS — Kitchen Custom (Lipa Voda etc)Kitchen's WorldNoNone
    Kiosk — CashKitchen's WorldNoNone
    Table QR — CashKitchen's WorldNoNone
    Drive-Through — CashKitchen's WorldNoNone

    The rule: Platform only earns a service fee when it brings the customer. Counter/automation channels are covered by the kitchen's subscription fee — not per-order cuts.


    2. System Components

    2.1 Platform4. Treasury

     Design

    The treasury is the central bank of JikoXpress.JikoXpress. AllIt platformis a proper ledger using double entry accounting — every money flowsmovement throughhas here.two sides (debit and credit), books always balance.

    What Double Entry Means

    Responsibilities:

    Money
      never
    • Receiveappears commissionor disappears — it always moves from somewhere to somewhere.

      Example: Customer pays TZS 10,000 via Mpesa
      
      Money arrives at Selcom (we now have it):
      DEBIT  ASSET_PSP_SELCOM     10,000
      
      Money is split:
      CREDIT LIABILITY_WALLETS      9,000  (kitchen's cut — we owe them)
      CREDIT REVENUE_SERVICE_FEE    1,000  (we earned this)
      
      Total debits = Total credits = TZS 10,000 ✅
      

      Treasury Buckets — What the Money Is

      At any moment, every order

    • shilling
    • Receivein subscriptionthe treasury is tagged to a bucket:

      ASSET_PSP_SELCOM      — physical money sitting at Selcom
      ASSET_PSP_AZAMPAY     — physical money sitting at Azampay
      ASSET_ESCROW          — held money, belongs to nobody yet
      
      LIABILITY_WALLETS     — belongs to ALL users (customers, kitchen owners, riders)
                              this is their money — we owe it back on demand
      LIABILITY_SETTLEMENTS — payout requests being processed, on the way out
      
      REVENUE_SERVICE_FEE      — platform's cut from online orders (OURS)
      REVENUE_SUBSCRIPTION     — monthly/yearly kitchen fees from(OURS)
      
      kitchens
    • EXPENSE_REFUNDS
    • Hold escrowmoney forreturned remoteto orders
    • customers
    • Pay delivery partners
    • Subsidize platform offers
    • Process refunds
    • Settle kitchen earnings
    • Record admin profit withdrawals

    2.2The Golden Safety Rule

    ASSET_PSP_SELCOM + ASSET_PSP_AZAMPAY + ASSET_ESCROW
    >=
    LIABILITY_WALLETS + LIABILITY_SETTLEMENTS
    

    If this breaks → crisis alert immediately. Platform is spending money it doesn't own.


    5. Wallet System

    User Wallet (Personal)

    Every registered JikoXpress app user wallet.gets Customerone canwallet topup,automatically payon orders,account withdraw.creation.

    • One wallet per registeredperson, appregardless userof role
    • CreatedUsed automaticallyto: ontop registrationup, pay orders, receive earnings (kitchen revenue, delivery fees), withdraw to Mpesa
    • HasLives itsunder ownLIABILITY_WALLETS transaction ledger
    • Linked toin treasury LIABILITY accountit's the user's money, not the platform's

    2.3 Kitchen EarningsWallet (Kitchen-Level)

    PlatformA holdscompletely kitchenseparate revenuesystem after ordersnot untilthe kitchenplatform owner requests payout.wallet.

    • PerIssued by the kitchen
    • Accumulates with every completed order
    • Depleted on settlement request
    • Linked to treasurytheir LIABILITY_SETTLEMENTS account

    2.4 Kitchen Customer Wallet

    Completely separate from platform. Kitchen manages independently.

    • Kitchen issues toown loyal customers
    • Kitchen handlesmanages it independently (deposits, deductions, withdrawalsbalance)
    • Has its own ledger — kitchen's booksbooks, not platform's
    • Platform only records "channel:paid via KITCHEN_WALLET" in the transaction — no treasury movement

    2.5Wallet Externalvs PaymentTreasury

    Providers
    LevelWhat It Sees
    TreasuryLIABILITY_WALLETS = TZS 5,000,000 (total of all wallets combined)
    Wallet levelKibuti = TZS 45,000 / Mama Lishe = TZS 230,000 / John rider = TZS 80,000

    Treasury sees the total obligation. Individual wallets explain the breakdown.

    Wallet Transaction Ledger

    PhysicalEvery moneywallet handlersmovement creates Selcom,a Azampay,record etc.with:

    • Physicaltype money sitsTOPUP, hereORDER_PAYMENT, ORDER_EARNING, DELIVERY_EARNING, WITHDRAWAL, SUBSCRIPTION_PAYMENT
    • Platformdirection calls theirCREDIT API(in) foror collectionsDEBIT (out)
    • amount
    • balanceBefore and disbursementsbalanceAfter — full audit trail, history reconstructable at any point
    • EveryreferenceId interaction recordedorder inID, platformpayout ledger
    • ID
    • Provider can be swapped without changing internal accounting

    2.6 Escrow

    Temporary holding account for remote orders.

    • Lives in ASSET_ESCROW account in treasury
    • Holds money between payment and delivery/confirmation
    • Released when release condition is met
    • Any transaction can be flagged for escrow at runtimeetc

    3.6. Chart of Accounts

    ASSETS  (what platform owns)has / controls)
    ├── ASSET_FLOATASSET_PSP_SELCOM          WorkingPhysical capitalmoney forat disbursementsSelcom
    ├── ASSET_ESCROWASSET_PSP_AZAMPAY         MoneyPhysical heldmoney pendingat releaseAzampay
    └── ASSET_RECEIVABLESASSET_ESCROW              MoneyHeld owedmoney to— no owner yet
    
    LIABILITIES  (what platform REVENUEowes (money comingnever in)touch without permission)
    ├── REVENUE_COMMISSIONLIABILITY_WALLETS         %All takenuser wallets combined
    └── LIABILITY_SETTLEMENTS     Payout requests being processed
    
    REVENUE  (platform's own earnings)
    ├── REVENUE_SERVICE_FEE       Cut from everyApp/WhatsApp orderorders
    ── REVENUE_SUBSCRIPTION      Kitchen monthly/yearly fees
    
    ├──EXPENSE  REVENUE_SERVICE_FEE(money Platformplatform service chargesspent)
    └── REVENUE_DELIVERY_MARKUP  Markup on delivery price
    
    EXPENSE  (money going out)
    ├── EXPENSE_DELIVERY         Paying delivery partners
    ├── EXPENSE_OFFER_SUBSIDY    Platform offer costs
    ├── EXPENSE_REFUNDS           CustomerRefunds refundssent └──back EXPENSE_OPERATIONSto Platform operational costs
    
    LIABILITY  (what platform owes)
    ├── LIABILITY_SETTLEMENTS    Kitchen earnings awaiting payout
    ├── LIABILITY_PLATFORM_WALLETS  App user wallet balances
    └── LIABILITY_ESCROW_DUE     Escrow obligationscustomers
    
    EQUITY  (platform net worth)
    ├── EQUITY_CAPITAL            Admin deposits / investments into platform
    └── EQUITY_RETAINED_EARNINGS  Accumulated platform profits
    

    P&L Formula

    Total Revenue  = sum(REVENUE_*)
    Total Expenses = sum(EXPENSE_*)Platform Net Profit = TotalREVENUE_SERVICE_FEE Revenue+ REVENUE_SUBSCRIPTION - TotalEXPENSE_REFUNDS
    
    ExpensesAdmin Availablecan Cashonly =withdraw ASSET_FLOATfrom -Net LIABILITY_SETTLEMENTSProfit - LIABILITY_PLATFORM_WALLETSnever from ASSETS covering LIABILITIES
    

    4.7. EntityMoney DesignSplitting

    4.1

    When AccountEntity

    an

    Chartonline oforder accountsis paid, the total is split into buckets dynamically. The caller (checkout service) passes the split parametersonethe recordfinancial service just executes. No business logic in the financial service.

    Split Buckets per accountOnline type.

    Order

    Split
    Field Type DescriptionGoes ToNotes
    idMenu revenue UUIDKitchen owner's wallet Main food items
    codePackaging fee StringKitchen owner's wallet e.g.Kitchen ASSET_FLOAT,sells REVENUE_COMMISSIONpackaging too
    nameDelivery fee StringRider's wallet HumanOnly readableon delivery orders
    typeService fee EnumREVENUE_SERVICE_FEE ASSET,App/WhatsApp REVENUE, EXPENSE, LIABILITY, EQUITY
    balanceBigDecimalRunning balance
    createdAtLocalDateTimeonly

    Service Fee — Configurable Refundability

    Controlled by a flag in the platform config:

    service.fee.refundable = true   → service fee goes into escrow with the rest
                                      on cancel → full refund including service fee
    
    service.fee.refundable = false  → service fee goes to REVENUE immediately on confirmation
                                      on cancel → only kitchen/rider money refunded
                                      platform keeps its cut
    

    Early stage → set true to build customer trust. Mature stage → flip to false to protect platform revenue. No code change needed — one config change.


    8. Escrow System

    Escrow is a dynamic flag, not a hardcoded rule. The checkout service decides whether to hold money based on the order context, and passes this to the financial service.

    4.2How JournalEntryEntityIt Works

    Every singletransaction moneyhas:

    movement.
      Immutable
    • holdInEscrow: true/false
    • escrowReleaseCondition: DELIVERY_CONFIRMED | PICKUP_CODE_CONFIRMED | null

    Financial service does exactly what it's told. It doesn't know WHYneverthe updatedcheckout orlayer deleted.knows that.

    Default Business Rules (Set by Checkout, Not Financial Service)

    Fulfillment debitedcreditedpositivereadable note
    Field Type DescriptionPayment ChannelHold in Escrow?Release Condition
    idDelivery UUIDMobile Money YesDELIVERY_CONFIRMED
    debitAccountDelivery AccountEntityPlatform Wallet AccountYes DELIVERY_CONFIRMED
    creditAccountPickup AccountEntityMobile Money AccountYes PICKUP_CODE_CONFIRMED
    amountPickup BigDecimalPlatform Wallet AlwaysYes PICKUP_CODE_CONFIRMED
    descriptionDine-in StringAny online HumanNo Immediate
    referenceAny StringCash OrderNo ID,(cash settlementis ID, etc
    referenceTypephysical) EnumORDER, SETTLEMENT, TOPUP, WITHDRAWAL, REFUND
    createdAtLocalDateTimeImmediate

    Rules

    4.3can TransactionEntity

    change

    Everywithout paymenttouching eventthe financial serviceonejust perupdate paymentthe splitcheckout perlayer order.logic.


    9. Payment Channels

    order checkoutsessionCARD,etc0.00 online
    FieldChannel TypeHits Treasury? DescriptionExternal PSP API?Escrow Possible?Service Fee?
    idCASH UUIDNo NoNoNo
    orderIdKITCHEN_CUSTOM (Lipa Voda etc) UUIDNo LinkedNo NoNo
    sessionIdKITCHEN_WALLET UUIDNo LinkedNo No No
    channelMOBILE_MONEY (USSD) UniversalPaymentMethodYes CASH,Yes MOBILE_MONEY,(Selcom/Azampay) Yes If online channel
    amountPLATFORM_WALLET BigDecimalYes (internal) EvenNo YesIf online channel
    statusCARD EnumYes PENDING,Yes COMPLETED,(card FAILED, REFUNDED
    holdInEscrowgateway) BooleanDynamic flag
    escrowReleaseConditionEnumIMMEDIATE, DELIVERY_CONFIRMED, PICKUP_CONFIRMED
    referenceStringUSSD ref, card ref, etc
    kitchenPaymentMethodIdUUIDYes If KITCHEN_CHANNEL
    kitchenCustomerIdUUIDIf KITCHEN_WALLET
    paidByEnumCUSTOMER, PLATFORM
    offerRefUUIDIf platform offer covered this
    createdAtLocalDateTime
    completedAtLocalDateTime

    4.4 TransactionSplitEntity

    How transaction amount is distributed. Dynamic — not hardcoded.

    FieldTypeDescription
    idUUID
    transactionTransactionEntity
    splitTypeStringKITCHEN_REVENUE, DELIVERY_FEE, COMMISSION, TAX, PACKAGING, etc
    descriptionStringHuman readable
    amountBigDecimal
    destinationEnumKITCHEN, PLATFORM, DELIVERY_PARTNER, TAX_ACCOUNT
    destinationIdUUIDWhich kitchen, which partner, etc
    statusEnumPENDING, COMPLETED
    createdAtLocalDateTime

    4.5 EscrowEntity

    Tracks escrow holdings per transaction.

    FieldTypeDescription
    idUUID
    transactionTransactionEntity
    amountBigDecimalAmount held
    statusEnumHELD, RELEASED, REFUNDED
    releaseConditionEnumDELIVERY_CONFIRMED, PICKUP_CONFIRMED, ORDER_CONFIRMED
    heldAtLocalDateTime
    releasedAtLocalDateTime

    4.6 DisbursementEntity

    Every outgoing payment to external world.

    FieldTypeDescription
    idUUID
    amountBigDecimal
    purposeEnumKITCHEN_SETTLEMENT, DELIVERY_FEE, REFUND, OFFER_SUBSIDY, PROFIT_WITHDRAWAL
    providerStringSELCOM, AZAMPAY, etc
    referenceStringProvider transaction ref
    statusEnumPENDING, COMPLETED, FAILED
    recipientNameString
    recipientAccountStringPhone or bank account
    orderIdUUIDIf related to order
    kitchenIdUUIDIf kitchen settlement
    createdAtLocalDateTime
    completedAtLocalDateTime

    4.7 PlatformWalletEntity

    JikoXpress app user wallet.

    FieldTypeDescription
    idUUID
    accountAccountEntityLinked JikoXpress user
    balanceBigDecimalCurrent balance
    createdAtLocalDateTime
    updatedAtLocalDateTime

    4.8 PlatformWalletTransactionEntity

    Every platform wallet movement.

    FieldTypeDescription
    idUUID
    walletPlatformWalletEntity
    typeEnumTOPUP, ORDER_PAYMENT, WITHDRAWAL, REFUND
    directionEnumCREDIT, DEBIT
    amountBigDecimal
    balanceBeforeBigDecimal
    balanceAfterBigDecimal
    referenceString
    orderIdUUIDIf order payment
    createdAtLocalDateTime

    4.9 KitchenEarningsEntity

    Kitchen revenue held on platform.

    FieldTypeDescription
    idUUID
    kitchenKitchenEntity
    balanceBigDecimalAvailable for payout
    totalEarnedBigDecimalAll time earnings
    totalSettledBigDecimalAll time payouts
    updatedAtLocalDateTime

    4.10 SettlementEntity

    Kitchen payout records.

    FieldTypeDescription
    idUUID
    kitchenKitchenEntity
    amountBigDecimal
    statusEnumPENDING, PROCESSING, COMPLETED, FAILED
    requestedByAccountEntityKitchen owner
    disbursementDisbursementEntityLinked disbursement
    periodFromLocalDateSettlement period
    periodToLocalDate
    createdAtLocalDateTime
    completedAtLocalDateTime

    4.11 TreasuryTopupEntity

    Admin deposits to external provider.

    FieldTypeDescription
    idUUID
    amountBigDecimal
    providerStringSELCOM, AZAMPAY, etc
    referenceStringDeposit reference
    depositedByAccountEntityAdmin who deposited
    noteStringOptional note
    createdAtLocalDateTime

    4.12 WithdrawalEntity

    Admin profit withdrawals from treasury.

    FieldTypeDescription
    idUUID
    amountBigDecimal
    requestedByAccountEntitySuper admin
    approvedByAccountEntitySecond admin approval
    purposeStringProfit withdrawal note
    destinationAccountStringBank/mobile to receive
    statusEnumPENDING, APPROVED, COMPLETED, REJECTED
    disbursementDisbursementEntityLinked disbursement
    createdAtLocalDateTime
    completedAtLocalDateTime

    4.13 PlatformOfferEntity

    Platform offer definitions.

    FieldTypeDescription
    idUUID
    nameString
    typeEnumFREE_DELIVERY, FREE_ORDERS, DISCOUNT_PERCENT, FREE_ITEM
    valueBigDecimalDiscount amount or %
    conditionsJSONMin order, eligible users, max uses
    budgetBigDecimalTotal platform budget for this offer
    budgetUsedBigDecimalRunning total spent
    activeBooleanAuto-deactivates when budget exhausted
    validFromLocalDate
    validUntilLocalDate
    createdAtLocalDateTime

    4.14 PlatformOfferUsageEntity

    Who used which offer.

    FieldTypeDescription
    idUUID
    offerPlatformOfferEntity
    accountAccountEntityApp user who used it
    orderIdUUID
    amountCoveredBigDecimalHow much platform paid
    createdAtLocalDateTimechannel

    5.10. DataFull FlowsMoney Journey — All Scenarios

    5.Chapter 1 Payment CollectionCounter FlowOrders (World 2 — No Treasury Involvement)


    Scenario 1.1 — POS Cash, Any Fulfillment

    Customer initiatespays paymentTZS 10,000 cash CheckoutSessionat createdcounter
    
    → Order recorded ✅
    → Transaction logged (inventorychannel: held)CASH) 
     TransactionEntityReceipt createdgenerated -
    channel setMoney -physically holdInEscrowin flagkitchen settill -💰
    status Treasury: nothing moves ❌
    → Platform earns: TZS 0 (covered by subscription)
    
    Kitchen sales report shows: CASH += PENDINGTZS 10,000
    ├───
    Cash
    /

    Scenario 1.2 — POS Kitchen Custom Payment (Lipa Voda, HaloPesa)

    Customer pays TZS 15,000 via Lipa Voda at counter
    
    → Order recorded ✅
    → Transaction logged (channel: KITCHEN_CUSTOM) ✅
    → Money goes to kitchen's own Lipa Voda account 💰
    → Treasury: nothing moves ❌
    → Platform earns: TZS 0
    
    Kitchen sales report shows: KITCHEN_CUSTOM += TZS 15,000
    

    Scenario 1.3 — POS Kitchen Wallet ──────────────────────────────────►Payment

    Loyal Nocustomer externalhas APITZS call20,000 in kitchen Cashierwallet
    confirmsOrders manuallyfood TZS 8,000, pays ├───from kitchen wallet
    
    → Order recorded ✅
    → Transaction logged (channel: KITCHEN_WALLET) ✅
    → Kitchen wallet balance -= TZS 8,000 (kitchen manages independently)
    → Treasury: nothing moves ❌
    → Platform earns: TZS 0
    
    Kitchen sales report shows: KITCHEN_WALLET += TZS 8,000
    

    Scenario 1.4 — Kiosk, Table QR, Drive-Through (Cash)

    Same as above — counter level, no treasury, no service fee. Order recorded, money stays in kitchen's physical world.


    Chapter 2 — Online Orders (World 1 — Treasury Involved)


    Scenario 2.1 — App Order, Pickup, Mobile Money /(USSD)

    Card
    Total: ──────────────────────────────────►TZS 12,000
      Menu:         ExternalTZS provider10,500
      APIPackaging:    calledTZS   500
      Service fee:  TZS 1,000
    
    STEP 1 — Payment initiated:
      Checkout session created, inventory held
      USSD prompt /sent cardto terminalcustomer via Selcom WebhookAPI
      Customer confirms on phone
      Selcom webhook fires
    
    onSTEP confirmation2 │
            │                                                              │
            └─── Platform Wallet ───────────────────────────────────────► │
                 Internal debit only                                       │
                 No external API                                           │
                                                                           │
                                            Payment Confirmed ◄────────────┘
                                                    │
                                                    ▼
                                        TransactionEntity status = COMPLETED
                                                    │
                                        ┌───────────┴───────────┐
                                        │                       │
                                  holdInEscrow=false      holdInEscrow=true
                                        │                       │
                                        ▼                       ▼
                                  Split money            EscrowEntity created
                                  immediately Money arrives, held in toescrow destinations(pickup not yet confirmed):
      DEBIT  ASSET_PSP_SELCOM    12,000
      CREDIT ASSET_ESCROW        12,000
    
    STEP 3 Release conditionOrder metconfirmed, kitchen notified, kitchen prepares
    
    STEP 4 — Customer arrives, shows pickup code, confirmed:
      DEBIT  ASSET_ESCROW              12,000
      CREDIT LIABILITY_WALLETS          11,000  (kitchen owner)
      CREDIT REVENUE_SERVICE_FEE         1,000  (platform)
    
      Kitchen wallet += TZS 11,000 ✅
      Platform revenue += TZS 1,000 ✅
    

    Scenario 2.2 — App Order, Delivery, Mobile Money

    Total: TZS 18,000
      Menu:          TZS 12,000
      Packaging:     TZS  1,000
      Delivery fee:  TZS  4,000
      Service fee:   TZS  1,000
    
    STEP 1 — Money arrives, full amount held in escrow:
      DEBIT  ASSET_PSP_SELCOM    18,000
      CREDIT ASSET_ESCROW        18,000
    
    STEP 2 — Order confirmed, kitchen prepares, rider picks up
    
    STEP 3 — Delivery confirmed:
      DEBIT  ASSET_ESCROW              18,000
      CREDIT LIABILITY_WALLETS         12,000  (kitchen — menu + packaging)
      CREDIT LIABILITY_WALLETS          4,000  (rider — delivery fee)
      CREDIT REVENUE_SERVICE_FEE        1,000  (platform)
    
      Kitchen wallet += TZS 12,000 ✅
      Rider wallet   += TZS 4,000 ✅
      Platform       += TZS 1,000 ✅
    

    Scenario 2.3 — App Order, Delivery, JikoXpress Wallet Payment

    Customer has TZS 30,000 in JikoXpress wallet
    Pays TZS 18,000 from wallet — NO PSP API call, purely internal
    
    STEP 1 — Wallet debited, goes to escrow:
      DEBIT  LIABILITY_WALLETS     18,000  (customer wallet decreases)
      CREDIT ASSET_ESCROW          18,000  (held)
    
    STEP 2 — Delivery confirmed, escrow releases:
      DEBIT  ASSET_ESCROW              18,000
      CREDIT LIABILITY_WALLETS         12,000  (kitchen)
      CREDIT LIABILITY_WALLETS          4,000  (rider)
      CREDIT REVENUE_SERVICE_FEE        1,000  (platform)
    
      No money entered or left the pool — purely internal redistribution ✅
    

    Scenario 2.4 — App Order, Dine-in, Mobile Money

    Dine-in — no escrow needed (no delivery/pickup risk)
    
      DEBIT  ASSET_PSP_SELCOM     11,000
      CREDIT LIABILITY_WALLETS     10,000  (kitchen)
      CREDIT REVENUE_SERVICE_FEE    1,000  (platform)
    
    Immediate split. No escrow. ✅
    

    Scenario 2.5 — WhatsApp Order, Pickup, Mobile Money

    Same flow as Scenario 2.1. Channel recorded as WHATSAPP. Service fee applies. Escrow holds until pickup code confirmed.


    Scenario 2.6 — Split moneyPayment (Multiple Methods)

    Order total: TZS 20,000
      Customer pays TZS 10,000 from wallet
      Customer pays TZS 10,000 via USSD
    
    Two TransactionEntities — both linked to destinationssame order, both └───────────────────────┘held in escrow
    
      DEBIT  LIABILITY_WALLETS     10,000  (wallet portion)
      DEBIT  ASSET_PSP_SELCOM      10,000  (USSD portion)
      CREDIT ASSET_ESCROW          20,000  (total held)
    
    On release → same split logic, total amount split proportionally ✅
    

    Scenario 2.7 — Platform Offer / Promo Applied

    Customer orders TZS 10,000 via App
    Platform covers delivery fee TZS 2,000 (free delivery offer)
    Customer pays TZS 8,000
    
    Two TransactionEntities:
      1. Customer: TZS 8,000 via USSD → escrow
      2. Platform: TZS 2,000 subsidy (paidBy = PLATFORM) → escrow
    
    On delivery confirmed:
      DEBIT  ASSET_ESCROW              10,000
      CREDIT LIABILITY_WALLETS          8,000  (kitchen)
      CREDIT LIABILITY_WALLETS          2,000  (rider — full fee covered)
      CREDIT REVENUE_SERVICE_FEE          500  (platform still earns cut on food amount)
    
      PlatformOfferUsageEntity created — budget tracked
      If budgetUsed >= budget → offer auto-deactivated ✅
    

    Scenario 2.8 — TZS 0.00 Free Order Created(Full Promo)

    Platform gives customer completely free order
    
    TransactionEntity still created:
      amount: 0.00
      channel: PLATFORM
      holdInEscrow: false
    
    Still recorded. Kitchen Notifiednotified. Order flows normally.
    No money moves. Event is captured. ✅
    

    5.2Chapter Money3 Split FlowWallet Operations


    Scenario 3.1 — User Tops Up Wallet

    TotalKibuti Ordertops Amount:up TZS 10,50,000 via Mpesa
    
      SplitDEBIT  CalculatorASSET_PSP_SELCOM      50,000
      ├──CREDIT FoodLIABILITY_WALLETS     Items50,000  Total(belongs ──────────────►to KitchenEarningsKibuti)
    
    Kibuti wallet += XTZS 50,000 ├── Packaging Fee ────────────────► KitchenEarnings += X
            │
            ├── Delivery Fee ──────────────────► DisbursementEntity
            │                                    (pay delivery partner)
            │
            ├── Platform Commission ──────────► JournalEntry
            │                                    DEBIT ASSET_FLOAT
            │                                    CREDIT REVENUE_COMMISSION
            │
            └── Tax ────────────────────────────► JournalEntry
                                                 DEBIT ASSET_FLOAT
                                                 CREDIT TAX_ACCOUNT
    

    5.3

    Scenario Escrow3.2 Release Flow

    Anyone Requests Payout to Mpesa

    EscrowEntityKitchen status = HELD
            │
            ▼
    Release Condition Metowner (DELIVERY_CONFIRMEDor /rider, PICKUP_CONFIRMED)or customer) withdraws EscrowEntityTZS status30,000
    
    =STEP RELEASED1  Money JournalEntry:earmarked:
      DEBIT  ASSET_FLOATLIABILITY_WALLETS      30,000
      CREDIT ASSET_ESCROWLIABILITY_SETTLEMENTS  30,000  (being processed)
    
    STEP 2 — JikoXpress calls Selcom API, sends to Mpesa:
      DEBIT  LIABILITY_SETTLEMENTS  30,000
      CREDIT ASSET_PSP_SELCOM       30,000  (money leaves)
    
    Money Splitarrives Calculatoron runsMpesa 
    Same TransactionSplitEntityflow createdfor percustomers, splitkitchen owners, ▼
    Each split credited to destinationriders
    

    Scenario 3.3 — Payout Fails

    Selcom API returns failure (wrong number, system down etc)
    
      DEBIT  LIABILITY_SETTLEMENTS  30,000  (earmark reversed)
      CREDIT LIABILITY_WALLETS      30,000  (money back in wallet)
    
    User notified. They can retry. No money lost. ✅
    

    11. Subscription Payments

    Kitchen owners pay monthly or yearly. They choose how to pay.


    Scenario 11.1 — Subscription via Wallet

    Mama Lishe pays TZS 15,000/month from wallet
    
    Pure internal — no PSP:
      DEBIT  LIABILITY_WALLETS      15,000
      CREDIT REVENUE_SUBSCRIPTION   15,000
    
    Kitchen wallet -= TZS 15,000
    Platform revenue += TZS 15,000 ✅
    

    Scenario 11.2 — Subscription via Mobile Money

      DEBIT  ASSET_PSP_SELCOM       15,000
      CREDIT REVENUE_SUBSCRIPTION   15,000
    
    Platform revenue += TZS 15,000 ✅
    

    Renewal Logic

    On renewal date:
    1. Check if owner chose wallet AND has sufficient balance
    2. If yes → auto deduct (Scenario 11.1)
    3. If no balance OR chose mobile money → send payment prompt
    4. If payment fails → grace period (configurable, e.g. 3 days)
    5. If still unpaid after grace → kitchen suspended
    

    12. Settlements & Payouts

    Any user can request a payout at any time — customers, kitchen owners, riders. Same mechanism for all.

    5.Rules

    1. Amount cannot exceed available wallet balance
    2. Minimum payout amount configurable in platform settings
    3. Processing time depends on external PSP
    4. Failed payouts → money returns to wallet automatically
    5. Full audit trail — who requested, when, destination, result

    13. Refunds & Cancellations


    Scenario 13.1 — Order Cancelled, Money in Escrow, service.fee.refundable=true

    TZS 18,000 in escrow, full refund including service fee
    
      DEBIT  ASSET_ESCROW          18,000
      CREDIT ASSET_PSP_SELCOM      18,000
    
    Selcom API → refund to customer Mpesa
    Platform earns nothing ✅
    

    Scenario 13.2 — Order Cancelled, service.fee.refundable=false

    Platform keeps service fee
    
      DEBIT  ASSET_ESCROW           18,000
      CREDIT ASSET_PSP_SELCOM       17,000  (customer refund minus fee)
      CREDIT REVENUE_SERVICE_FEE     1,000  (platform keeps)
    

    Scenario 13.3 — Order Cancelled, Paid via Wallet

      DEBIT  ASSET_ESCROW          18,000
      CREDIT LIABILITY_WALLETS     18,000  (back to customer wallet)
    
    No PSP call. Pure internal. Instant refund to wallet ✅
    

    Scenario 13.4 — Post-Completion Refund Flow(Dispute)

    Order Cancelleddelivered, /escrow Refundalready Requestedreleased, kitchen already Checkpaid
    Rare — dispute/complaint scenario. Manual admin action required.
    
      DEBIT  LIABILITY_WALLETS      10,000  (kitchen wallet reduced)
      DEBIT  EXPENSE_REFUNDS        10,000
      CREDIT ASSET_PSP_SELCOM       10,000  (refund to customer)
    
    Full audit trail. SUPER_ADMIN approval required.
    

    14. Admin Withdrawal

    Platform accumulates profit from service fees and subscriptions. Admin can withdraw profit only.

    Rules

    1. Only SUPER_ADMIN can request
    2. Requires second SUPER_ADMIN approval
    3. Can only withdraw from net profit (REVENUE minus EXPENSE minus already withdrawn)
    4. Can never withdraw from escrow — belongs to customers
    5. Can never withdraw from LIABILITY_WALLETS — belongs to users
    6. System enforces hard limit — no override

    Withdrawal Calculation

    Available to withdraw =
      REVENUE_SERVICE_FEE
      + REVENUE_SUBSCRIPTION
      - EXPENSE_REFUNDS
      - previously_withdrawn
    
    If requested amount <= available → allow ✅
    If requested amount > available  → reject hard ❌
    

    Journal Entry

      DEBIT  EQUITY_RETAINED_EARNINGS  500,000
      CREDIT ASSET_PSP_SELCOM          500,000
    
    Selcom API → transfers to admin Mpesa ✅
    

    15. PSP Reconciliation

    The Rule

    Selcom actual balance >= ASSET_PSP_SELCOM  ✅ (normal — other money may be there too)
    Selcom actual balance <  ASSET_PSP_SELCOM  ❌ CRISIS — money is missing
    

    The Selcom account may receive money from other business activities unrelated to JikoXpress. That is expected and normal. The check only validates that JikoXpress-tracked money is fully covered.

    Daily Reconciliation Process

    1. Pull Selcom transaction log for the day
    2. Match each incoming payment to a TransactionEntity by ├──reference/amount
    3. Flag unmatched payments (other sources — expected, not a problem)
    4. Flag any JikoXpress transaction with no matching Selcom record (problem)
    5. Alert if ASSET_PSP_SELCOM > Selcom actual balance (crisis)
    

    16. Reporting

    Treasury Snapshot (Platform View)

    WHAT WE HAVE:
      At Selcom:              ASSET_PSP_SELCOM balance
      At Azampay:             ASSET_PSP_AZAMPAY balance
      In Escrowescrow:              ASSET_ESCROW balance
    
    WHAT WE OWE:
      To all users (wallets): LIABILITY_WALLETS balance
      Payouts in progress:    LIABILITY_SETTLEMENTS balance
    
    WHAT WE EARNED:
      Service fees:           REVENUE_SERVICE_FEE balance
      Subscriptions:          REVENUE_SUBSCRIPTION balance
      Net profit:             REVENUE_SERVICE_FEE + REVENUE_SUBSCRIPTION - EXPENSE_REFUNDS
    

    Kitchen Owner Sales Report

    Reads from orders + wallet transactions — NOT treasury directly:

    SALES REPORT — Mama Lishe Kitchen | April 2026
    ────────────────────────────────────────────►
            │   EscrowEntity status = REFUNDED                         │
            │   JournalEntry:                                          │
            │   DEBIT ASSET_FLOAT                                      │
            │   CREDIT ASSET_ESCROW                                    │
            │                                                          │
            └──
    AlreadyCHANNEL SettledBREAKDOWN:
      App orders         TZS 150,000    (in your JikoXpress wallet)
      WhatsApp orders    TZS  80,000    (in your JikoXpress wallet)
      Cash (POS)         TZS 200,000    (collected physically — in your till)
      Lipa Voda (POS)    TZS  50,000    (in your Lipa Voda account)
    
    TOTAL SALES:         TZS 480,000
    ───────────────────────────────────►  │
                KitchenEarnings debited                                │
                JournalEntry:                                          │
                DEBIT LIABILITY_SETTLEMENTS                            │
                CREDIT ASSET_FLOAT                                     │
                                                                       │
                                                Refund Processed ◄───────────
    JIKOXPRESS WALLET:
      DisbursementEntityAvailable createdbalance  TZS 230,000    (purpose: REFUND)
                                                        │
                                                        ▼
                                            External provider API
                                            (return moneyready to customer)
                                                        │
                                                        ▼
                                            JournalEntry:
                                            DEBIT EXPENSE_REFUNDS
                                            CREDIT ASSET_FLOATwithdraw)
    

    Individual

    5.5Wallet Kitchen Settlement FlowStatement

    KitchenMY Owner requests payout
            │
            ▼
    KitchenEarningsEntity checked
    (available balance)
            │
            ▼
    SettlementEntity created
    status = PENDING
            │
            ▼
    JournalEntry:
    DEBIT LIABILITY_SETTLEMENTS
    CREDIT ASSET_FLOAT
            │
            ▼
    DisbursementEntity created
    (purpose: KITCHEN_SETTLEMENT)
            │
            ▼
    External provider API called
    (transfer to owner mobile/bank)
            │
            ▼
    Provider webhook confirms
            │
            ▼
    DisbursementEntity status = COMPLETED
    SettlementEntity status = COMPLETED
    KitchenEarningsEntity balance -= amount
    

    5.6 Admin Profit Withdrawal Flow

    Super Admin requests withdrawal
            │
            ▼
    WithdrawalEntity created
    status = PENDING
            │
            ▼
    Second Admin approves
            │
            ▼
    WithdrawalEntity status = APPROVED
            │
            ▼
    JournalEntry:
    DEBIT EQUITY_RETAINED_EARNINGS
    CREDIT ASSET_FLOAT
            │
            ▼
    DisbursementEntity created
    (purpose: PROFIT_WITHDRAWAL)
            │
            ▼
    External provider transfer
            │
            ▼
    WithdrawalEntity status = COMPLETED
    

    5.7 Platform Offer Flow

    App customer applies offer at checkout
            │
            ▼
    PlatformOfferEntity validated
    - Is active?
    - Budget available?
    - User eligible?
    - Conditions met?
            │
            ▼
    Offer applied
    Customer pays reduced amount
            │
            ▼
    Two TransactionEntities created:
    1. Customer payment (reduced amount)
    2. Platform payment (offer subsidy amount)
       - paidBy = PLATFORM
       - offerRef = offer uuid
            │
            ▼
    PlatformOfferUsageEntity created
    PlatformOfferEntity.budgetUsed += subsidy amount
            │
            ▼
    If budgetUsed >= budget
    → offer auto-deactivated
            │
            ▼
    JournalEntry:
    DEBIT EXPENSE_OFFER_SUBSIDY
    CREDIT ASSET_FLOAT
            │
            ▼
    Both transactions confirmed
    → Order created
    → Kitchen gets full amount
    → Platform covered the difference
    

    6. User Journeys

    6.1 CustomerWALLETPayKibuti for Order (POS Cash)

    Customer at counter
            │
            ▼
    Staff adds items to checkout session
            │
            ▼
    Staff selects: Pay Now → Cash
            │
            ▼
    System calculates total
            │
            ▼
    Staff collects cash from customer
            │
            ▼
    Staff confirms payment in system
            │
            ▼
    Transaction recorded (CASH, no escrow)
    Money split immediately
            │
            ▼
    Order created → kitchen notified
            │
            ▼
    Receipt printed (frontend)
            │
            ▼
    Kitchen prepares → food ready
            │
            ▼
    Customer receives food
    

    6.2 Customer — App Delivery with Mobile Money

    App customer browses kitchens
            │
            ▼
    Adds items to cart
            │
            ▼
    Proceeds to checkout
    Enters delivery address
            │
            ▼
    Selects Mobile Money payment
            │
            ▼
    System creates checkout session
    Inventory held
            │
            ▼
    USSD prompt sent to customer phone
            │
            ▼
    Customer enters PIN on phone
            │
            ▼
    Provider confirms → webhook fires
            │
            ▼
    Transaction recorded
    holdInEscrow = true
    EscrowEntity created
            │
            ▼
    Order created → kitchen notified
            │
            ▼
    Kitchen prepares → packages food
            │
            ▼
    Delivery partner picks up
            │
            ▼
    Delivery partner confirms delivery
            │
            ▼
    Escrow released
    Money split:
      → Kitchen earnings
      → Delivery partner paid
      → Platform commission recorded
            │
            ▼
    Customer receives food
    

    6.3 Customer — Kiosk Cash Slip

    Customer at kiosk machine
            │
            ▼
    Customer selects items
            │
            ▼
    Customer selects: Pay Cash
            │
            ▼
    System creates SLIP session
    Inventory held
    Slip expires in 15 min
            │
            ▼
    Slip printed (frontend handles)
            │
            ▼
    Customer walks to cashier with slip
            │
            ▼
    Cashier scans slip barcode
    Finds session in queue
            │
            ▼
    Cashier collects cash
    Confirms payment in system
            │
            ▼
    Transaction recorded (CASH, no escrow)
    Money split immediately
            │
            ▼
    Order created → kitchen notified
            │
            ▼
    Kitchen prepares food
            │
            ▼
    Customer number called
    Customer collects food
    

    6.4 Customer — Dine In with Tab (Multiple Rounds)

    Customer sits at table
            │
            ▼
    Waiter takes order → Round 1
    Creates TAB session
    New KitchenBillsEntity opened
            │
            ▼
    Kitchen ticket printed for Round 1
    Kitchen prepares
            │
            ▼
    Customer orders more → Round 2
    Waiter adds new session to same bill
            │
            ▼
    Kitchen ticket printed for Round 2
    Kitchen prepares
            │
            ▼
    Customer asks for bill
    Waiter prints bill (all rounds)
            │
            ▼
    Customer pays
    Waiter selects payment method(s)
            │
            ▼
    Transaction(s) recorded
    Money split
            │
            ▼
    KitchenBillsEntity closed
    Receipt printed
    

    6.5 Kitchen Owner — Request Settlement

    Kitchen owner opens earnings screen
    Sees available balance
            │
            ▼
    Clicks "Request Payout"
    Enters amount and destination
            │
            ▼
    SettlementEntity created (PENDING)
            │
            ▼
    Platform processes
    DisbursementEntity created
    External transfer initiated
            │
            ▼
    Provider confirms
            │
            ▼
    SettlementEntity COMPLETED
    KitchenEarnings balance updated
            │
            ▼
    Kitchen owner receives money
    on mobile/bank account
    

    6.6 Admin — Treasury Topup

    Platform needs more float
    Admin deposits to Selcom
            │
            ▼
    Admin records topup in system
    TreasuryTopupEntity created
            │
            ▼
    JournalEntry:
    DEBIT ASSET_FLOAT
    CREDIT EQUITY_CAPITAL
            │
            ▼
    Platform float increases
    Ready for disbursements
    

    6.7 Admin — Profit Withdrawal

    Platform has accumulated profits
    Super admin requests withdrawal
            │
            ▼
    WithdrawalEntity created (PENDING)
    Second admin notified for approval
            │
            ▼
    Second admin approves
            │
            ▼
    JournalEntry recorded
    DisbursementEntity created
    External transfer initiated
            │
            ▼
    WithdrawalEntity COMPLETED
    Profits withdrawn
    

    7. Payment Channels

    ChannelExternal APIEscrow PossibleNotes
    CASHPhysical, always immediate
    MOBILE_MONEY✅ Selcom/AzampayUSSD webhook based
    CARD✅ Card gatewayFuture
    PLATFORM_WALLET❌ InternalInternal debit
    KITCHEN_WALLET❌ Kitchen handlesKitchen's own system
    KITCHEN_CHANNEL❌ Manual confirmPhysical payment

    8. Escrow System

    When to Hold

    Escrow flag (holdInEscrow) is set dynamically at transaction creation based on current business rules. Not hardcoded.

    Current default rules:

    • DELIVERY fulfillment → hold until delivery confirmed
    • All others → no hold (immediate split)

    Future rules can be added without code changes — just update the rule engine.

    Release Conditions

    ConditionTrigger
    IMMEDIATENo hold — split right away
    ORDER_CONFIRMEDWhen cashier approves (TABLE_QR)
    PICKUP_CONFIRMEDWhen customer collects food
    DELIVERY_CONFIRMEDWhen delivery partner confirms

    9. Money Splitting

    Splits are dynamic — configured per order based on what services are included.

    Split Types

    Split TypeDestinationExample
    KITCHEN_REVENUEKitchen earningsFood items total
    PACKAGING_FEEKitchen earningsPackaging cost
    DELIVERY_FEEDelivery partnerCourier payment
    PLATFORM_COMMISSIONREVENUE_COMMISSION accountPlatform % cut
    TAXTax accountVAT/government tax
    OFFER_SUBSIDYEXPENSE_OFFER_SUBSIDYPlatform covers discount

    New split types can be added as new services are introduced — no entity changes needed.


    10. Platform Offers

    Offer Types

    TypeDescriptionPlatform Pays
    FREE_DELIVERYPlatform covers delivery feeDelivery fee amount
    FREE_ORDERSFirst N orders freeFull order amount
    DISCOUNT_PERCENT% off orderDiscount amount
    FREE_ITEMSpecific item freeItem price

    Offer Validation Rules

    1. User must be eligible (e.g. first 2 orders check)
    2. Offer must be active
    3. Budget must not be exhausted
    4. Order must meet minimum conditions
    5. Channel must be APP — offers are app users only

    Budget Control

    PlatformOfferEntity.budget = TZS 1,000,000  (allocated)
    PlatformOfferEntity.budgetUsed = TZS 850,000 (spent so far)
    Remaining = TZS 150,000
    
    When budgetUsed >= budget:
    → offer.active = false (auto-deactivated)
    → No more usage allowed
    

    11. Settlements & Withdrawals

    Kitchen Settlement Rules

    1. Kitchen owner can request anytime
    2. Minimum payout amount (configurable)
    3. Cannot exceed available KitchenEarnings balance
    4. Processing time depends on external provider
    5. Failed settlements → DisbursementEntity FAILED → retry

    Admin Withdrawal Rules

    1. Only SUPER_ADMIN can request
    2. Requires second SUPER_ADMIN approval
    3. Cannot withdraw from escrow — those funds belong to customers
    4. Cannot withdraw more than available ASSET_FLOAT
    5. Full audit trail — who requested, who approved, when, where it went

    12. P&L & Reporting

    Revenue Report

    Period:| April 2026
    Commission:──────────────────────────────────────────────────────
    Current Balance: TZS 2,500,000
    Subscription fees:  TZS 1,200,000
    Service fees:       TZS   300,45,000
    ──────────────────────────────────────────────────────
    TotalDATE      Revenue:DESCRIPTION                  TZSIN        4,000,OUT   BALANCE
    Apr 23    Top up via Mpesa         50,000           
    50,000

    ExpenseApr Report

    23
    Period:Order #47 — Mama Lishe             5,000  45,000
    Apr 22    Order #31 earnings        8,500           53,500
    Apr 21    Withdrawal to Mpesa               15,000  38,500
    Apr 20    Subscription — April              2026
    
    Delivery payouts:   TZS   800,15,000  Offer subsidies:    TZS   400,000
    Refunds:            TZS   150,00053,500
    ─────────────────────────────────
    Total Expenses:     TZS 1,350,000─────────────────────
    

    Same wallet, same statement format — whether customer, kitchen owner, or rider. Transaction type field enables per-role breakdown reports.

    NetHow ProfitTreasury Gets Breakdown by Role

    NetTotal Profitrider earnings in wallets  =
      TZSsum(WalletTransactionEntity 4,000,000where - TZS 1,350,000type = TZSDELIVERY_EARNING 2,650,000and not withdrawn)
    
    Total kitchen earnings in wallets =
      sum(WalletTransactionEntity where type = ORDER_EARNING and not withdrawn)
    

    Balance

    Treasury Sheet

    sees
    ASSETSLIABILITY_WALLETS Float:= TZS 5,000,000.
    Escrow:Wallet TZStransaction 300,000types Receivables:explain TZSthe 200,000breakdown Totalunderneath Assets:it.

    TZS
    5,500,000

    17. LIABILITIESSafety KitchenRules settlements& due:Integrity TZSChecks

    2,000,000

    Primary PlatformSafety wallets:Check TZS(Runs 500,000Continuously)

    Total
    ASSET_PSP_SELCOM Liabilities:+ TZSASSET_PSP_AZAMPAY 2,500,000+ EQUITYASSET_ESCROW
    Capital:>=
    TZSLIABILITY_WALLETS 1,000,000+ RetainedLIABILITY_SETTLEMENTS
    
    earnings:If TZSfalse 2,000,000 TotalALERT Equity:IMMEDIATELY TZS 3,000,000🚨
    

    Projections

    Based on historical journal entries:

    • Month over month commission growth
    • Average order value trend
    • Offer subsidy burn rate
    • Settlement frequency per kitchen

    13. Security &Immutability Rules

    Immutability

    • JournalEntryEntity — never updated, never deleteddeleted. Append-only ledger.
    • TransactionEntity — status only moves forwardforward: (PENDING → COMPLETED → REFUNDED)REFUNDED. Never backwards.
    • PlatformOfferUsageEntityWalletTransactionEntity — never deleteddeleted. balanceBefore and balanceAfter on every record. History reconstructable at any point in time.

    BalanceEscrow Integrity Check

    • Account
      ASSET_ESCROW balance = sum of all creditEscrowEntity journalwhere entriesstatus -= sumHELD
      
      ofIf allmismatch debit entries
    • discrepancy
    • Runningalert balance🚨 maintained
    AND

    Admin verifiableWithdrawal byHard recalculationLimit

  • Discrepancy
    Withdrawal alertsamount <= net profit available
    
    System rejects if runningexceeded. balanceNo !=override. calculatedNo balance
  • exceptions.

Access Control

platform
Action Who
View treasury SUPER_ADMIN
Request kitchen settlementpayout KitchenAny owneruser (own wallet only)
Approve admin withdrawal Second SUPER_ADMIN
CreateView offers SUPER_ADMIN
Topup treasuryP&L SUPER_ADMIN
View own earningswallet KitchenAny owneruser
ViewManual ownpost-completion walletrefund AppSUPER_ADMIN user+ approval
Create platform offersSUPER_ADMIN

Audit
Trail

18.

EveryDecision entityLog

has Financialentitiesadditionally formanualoperations
DecisionChoiceRationale
Tax handlingDropped for V1Reduces complexity. Kitchen owner responsible for TRA compliance. Add later if legal pressure arises.
Escrow rule locationDynamic flag from checkout callerFinancial service stays dumb — just executes. Business logic lives in checkout. Decoupled.
Service fee refundabilityConfig flag in properties fileOne switch changes behavior platform-wide. No code change needed.
Separate wallets per roleNo — one wallet per personSame account = customer, owner, rider. No artificial separation by role.
Treasury breakdown per roleNot in treasury — in wallet transaction typesTreasury sees total obligation. Breakdown via createdByWalletTransactionEntity.type, createdAt.queries.
Full have:

accounting
    vs
  • approvedBysimple ledger
Proper double-entry ledger, not QuickBooksPlatform holds other people's money — can't skip proper tracking. Kept fit-for-purpose, not over-engineered.
PSP accounts in chartYes — one per PSPNeed to know where applicablephysical
  • referencemoney linkingsits. Enables clean reconciliation.
  • Counter orders in treasuryNoCash/kitchen custom never touch JikoXpress PSP. Platform is just a tool. Covered by subscription.
    Admin withdrawal restrictionRevenue/profit onlyCan never touch escrow or user wallet liabilities. Non-negotiable safety rule.
    Payout eligibilityAny userCustomers, kitchen owners, riders — same wallet system, same payout flow. Role irrelevant.
    Subscription payment methodUser's choiceFlexibility. Auto-deduct from wallet if chosen and balance sufficient. Fallback to externalmobile providermoney
  • noteprompt.
  • Kitchen walletCompletely separate from platformKitchen manages independently. Platform records usage only. No treasury involvement.

    QBIT SPARK CO LIMITED | JikoXpress Pro | April 2026
    Internal financial architecture document — confidential