Skip to main content

JikoXpress Pro — Offer Engine Architecture

Version 3.0 | May 2026 | QBIT SPARK CO LIMITED Full offer engine design — psychology, architecture, user journeys, UI flows, and competitive positioning. Updated: Three discount layers defined. Menu discount as Layer 1. Offer governance and loss prevention added. Implementation prerequisites defined — offer engine builds only after core order flow is stable. No code. No schema. Pure design thinking.


Table of Contents

  1. Why Offers Win or Kill a Platform
  2. The Psychology Behind Offers
  3. The Three Offer Worlds
  4. The Three Discount Layers — The Full Picture
  5. Phase Strategy — What We Build Now vs Later
  6. The Coupon Engine — Phase 1 Architecture
  7. Offer Types — Deep Dive
  8. The Rule Engine
  9. Coupon Scope — What a Coupon Can Target
  10. Delivery Configuration vs Offers
  11. Offer Governance & Loss Prevention
  12. Referral System — Built on Coupon Engine
  13. B2B — Kitchen Subscription Offers
  14. Notification & Preference System
  15. User Journeys — All Levels
  16. UI Ideas & Flow Concepts
  17. Where JikoXpress Wins
  18. Financial Impact of Offers
  19. Entity Overview
  20. Implementation Prerequisites
  21. Decision Log

1. Why Offers Win or Kill a Platform

Jumia failed in food not because of bad tech — they failed because customers had no reason to stay loyal. An offer engine done wrong either burns money with zero return, or is so stingy users ignore it entirely. JikoXpress needs to get this exactly right.

The three ways platforms lose with offers:

TOO GENEROUS    → burns budget, users only order when there's a deal, unsustainable
TOO STINGY      → users don't feel valued, go to competitor
TOO COMPLEX     → users don't understand the deal, ignore it entirely

The winning formula:

RIGHT OFFER → RIGHT PERSON → RIGHT TIME → IRRESISTIBLE

This document designs exactly that — starting with the simplest, most powerful tool: the coupon code.


2. The Psychology Behind Offers

Understanding why humans respond to offers is the foundation of the entire engine. Every offer type maps to a specific psychological trigger.

2.1 Loss Aversion — The Most Powerful Trigger

Humans feel the pain of losing TZS 2,000 more than the pleasure of gaining TZS 2,000.

How JikoXpress uses it:

  • "Your coupon expires tonight" → time pressure creates urgency
  • "You have TZS 1,500 in your wallet — don't let it go to waste" → loss framing
  • Showing crossed-out delivery fee → TZS 1,500 → FREE

2.2 Reciprocity — I Got Something, Now I Owe You

When someone gives us something, we feel compelled to give back.

How JikoXpress uses it:

  • Referral coupon gives new user free delivery → they feel obligated to complete the order
  • Kitchen gives free item coupon → customer feels loyalty to that kitchen
  • First order deal → customer feels obligated to return

2.3 Social Proof — Others Are Doing It

Humans look at what others do to decide what to do.

How JikoXpress uses it:

  • "127 people used this coupon today" on the offer card
  • Referral system shows friend already uses the platform

2.4 Scarcity — Limited Makes It Valuable

We want what is running out.

How JikoXpress uses it:

  • "Only 14 redemptions left for this coupon"
  • "This kitchen's lunch special ends at 2pm"
  • Coupon with totalUseLimit shows remaining count

2.5 Identity & Reward — I Earned This

We value things more when we feel we worked for them or were specially chosen.

How JikoXpress uses it:

  • Birthday coupon — platform "remembered" you, feels personal
  • Referral reward — you helped a friend, you get rewarded
  • Kitchen coupon on flyer — feels exclusive, like insider access

2.6 Anchoring — The Original Price Matters

Humans judge value based on the first number they see.

How JikoXpress uses it:

  • Always show original price crossed out → TZS 8,000TZS 6,000
  • Show "You saved TZS 2,000" at order confirmation
  • Delivery fee shown then zeroed → feels better than just "Free delivery"

3. The Four Offer Worlds

JikoXpress operates four completely separate offer worlds. Each has different actors, different funding, different purpose, and different implementation timing. Understanding these worlds is the foundation of the entire offer system.

┌─────────────────────────────────────────────────────────────────┐
│              WORLD 1: MENU ITEM OFFER                           │
│                                                                 │
│   Actor     → Kitchen Owner (menu management)                  │
│   Funded by → Kitchen (absorbed in their margin)               │
│   Purpose   → Permanent or semi-permanent price reduction       │
│              on a specific menu item                            │
│   Trigger   → None — always active while item is active        │
│   Code      → No code needed                                   │
│   Channels  → ALL channels, always, no restriction             │
│   Phase 1   → ✅ BUILD NOW (part of menu management)           │
│   Examples  → Pilau TZS ~~8,000~~ → TZS 7,500                 │
│              Juice TZS ~~3,000~~ → TZS 2,500                   │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│              WORLD 2: KITCHEN COUPON                            │
│                                                                 │
│   Actor     → Kitchen Owner (offer dashboard)                  │
│   Funded by → Kitchen (deducted from their settlement)         │
│   Purpose   → Time-limited promotions to attract customers,    │
│              boost slow hours, push specific items             │
│   Trigger   → Customer enters code at checkout                 │
│   Code      → Yes — e.g. MAMA20, FRIDAY10, OPENDAY            │
│   Channels  → All channels (configurable per coupon)           │
│   Phase 1   → ✅ BUILD NOW (after core order flow stable)      │
│   Examples  → 15% off this weekend, free delivery Friday,      │
│              TZS 1,000 off orders above TZS 8,000              │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│              WORLD 3: PLATFORM COUPON                           │
│                                                                 │
│   Actor     → JikoXpress Admin                                 │
│   Funded by → Platform (marketing cost, EXPENSE_OFFER_SUBSIDY) │
│   Purpose   → Customer acquisition, retention, market growth   │
│   Trigger   → Customer enters code at checkout                 │
│   Code      → Yes — e.g. JIKO20, WELCOME50, FREESHIP          │
│              Also: system-generated referral codes (REF-*)     │
│   Channels  → All channels (configurable per coupon)           │
│   Phase 1   → ✅ BUILD NOW (after core order flow stable)      │
│   Examples  → 20% off first order, free delivery new users,    │
│              referral reward coupons                           │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│              WORLD 4: AUTO / MANUAL PLATFORM OFFERS             │
│                                                                 │
│   Actor     → JikoXpress Admin (defines rules)                 │
│              System (fires automatically based on triggers)    │
│   Funded by → Platform                                         │
│   Purpose   → Targeted offers fired by system events or        │
│              scheduled by admin — no code needed by customer   │
│   Trigger   → System event (birthday, first session, schedule) │
│              OR admin manually pushes to eligible users        │
│   Code      → No — applies transparently at checkout           │
│   Channels  → All channels                                     │
│   Phase 1   → ⏳ NOT YET — Phase 2 only                        │
│   Examples  → Free delivery this whole week (manual, admin     │
│              sets it and it runs for all orders)               │
│              Birthday offer — 30% off on user's birthday       │
│              Welcome offer — free delivery first order ever    │
│              Happy hour — 15% off between 3pm–5pm daily        │
│              B2B trial — PROFESSIONAL plan free 30 days        │
└─────────────────────────────────────────────────────────────────┘

Critical rule: These four worlds never mix financially. Each has its own cost center, its own accounting entry, its own audit trail. A kitchen coupon cost never touches the platform marketing budget. A platform coupon never reduces what a kitchen earns.

How the Four Worlds Relate to the Three Discount Layers

Layer 1 (menu discount)    ←→   World 1 (menu item offer)
Layer 2 (coupon code)      ←→   World 2 + World 3 (kitchen + platform coupons)
Layer 3 (auto-offer)       ←→   World 4 (auto / manual platform offers)

Same concept, two views. The layers describe the checkout calculation sequence. The worlds describe who owns and funds each type of offer.


4. The Three Discount Layers — The Full Picture

This is the most important framing in the entire document. JikoXpress has three completely separate discount layers. They are independent, they serve different purposes, and they must never be confused with each other — not in design, not in code, not in financial accounting.

┌─────────────────────────────────────────────────────────────────────────┐
│  LAYER 1 — MENU ITEM DISCOUNT                                           │
│                                                                         │
│  What it is:   A price reduction set directly on a menu item            │
│  Who sets it:  Kitchen owner (in menu management)                       │
│  How:          Fixed amount off OR percent off the base price           │
│  Trigger:      None — always active while item is active                │
│  Channels:     ALL channels (App, WhatsApp, Counter, Kiosk)            │
│  Lifespan:     No expiry — kitchen edits manually to change             │
│  Budget:       None — kitchen accepts the reduced earnings              │
│  Code needed:  No                                                       │
│  Financial:    Changes the item's selling price                         │
│                Baked into the order subtotal before anything else       │
│                                                                         │
│  Example:                                                               │
│    Pilau base price:   TZS 8,000                                       │
│    Menu discount:      TZS 500 (fixed)                                 │
│    Selling price:      TZS 7,500 ← this is now THE price               │
│    Shown as:           TZS ~~8,000~~ → TZS 7,500 on all channels      │
└─────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────┐
│  LAYER 2 — COUPON CODE                                                  │
│                                                                         │
│  What it is:   A promotional code applied at checkout                  │
│  Who sets it:  Admin (platform coupon) or Kitchen owner (kitchen coupon)│
│  How:          Customer enters a code at checkout                       │
│  Trigger:      Customer action — manual code entry                     │
│  Channels:     All channels (can be restricted per coupon config)       │
│  Lifespan:     Defined startDate → endDate, auto-expires               │
│  Budget:       Hard cap — auto-deactivates when exhausted               │
│  Code needed:  Yes — e.g. JIKO20, MAMA15, REF-GRACE7X                 │
│  Financial:    Applied on top of already-discounted subtotal (Layer 1) │
│                Platform coupon → platform absorbs cost                  │
│                Kitchen coupon → deducted from kitchen settlement        │
│                                                                         │
│  Example:                                                               │
│    Order subtotal (after menu discounts): TZS 15,000                   │
│    Coupon JIKO20 (20% off):             - TZS 3,000                    │
│    Customer pays:                         TZS 12,000                   │
└─────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────┐
│  LAYER 3 — PLATFORM AUTO-OFFER (Phase 2 only)                          │
│                                                                         │
│  What it is:   An offer applied automatically by the system             │
│  Who sets it:  Admin defines rules, system fires automatically         │
│  How:          System checks eligibility on every checkout              │
│  Trigger:      System — based on user profile, order history, date     │
│  Channels:     All or specific channels                                 │
│  Lifespan:     Defined, auto-expires                                    │
│  Budget:       Hard cap                                                 │
│  Code needed:  No — transparent to customer, just applies              │
│  Financial:    Applied after Layer 1 and Layer 2                        │
│                Platform always absorbs cost                             │
│                                                                         │
│  Examples:                                                              │
│    Birthday offer — 30% off on user's birthday, auto-applied           │
│    Welcome offer — free delivery on first order, auto-applied          │
│    ⚠ NOT BUILT IN PHASE 1                                              │
└─────────────────────────────────────────────────────────────────────────┘

4.1 How the Three Layers Interact at Checkout

The layers are resolved in strict order. Each layer is independent — a change in one does not affect the others.

CHECKOUT CALCULATION SEQUENCE
══════════════════════════════════════════════════════

Step 1 — LAYER 1: Apply menu item discounts
  For each item in cart:
    selling price = base price - menu discount (if any)
  Order subtotal = sum of all selling prices

  ···············································
  Result: discounted subtotal
  e.g. TZS 15,000 (already reflects item discounts)
  ···············································

Step 2 — Calculate delivery fee
  From kitchen distance tiers or flat fee
  e.g. TZS 1,500

Step 3 — Kitchen delivery subsidy active?
  YES → delivery fee = 0, kitchen billed at settlement
  NO  → delivery fee stays

Step 4 — LAYER 2: Customer entered a coupon?
  YES → validate coupon → apply on discounted subtotal
  NO  → skip
  ···············································
  Result: coupon discount deducted
  e.g. JIKO20 20% off TZS 15,000 = - TZS 3,000
  New total: TZS 12,000
  ···············································

Step 5 — LAYER 3: Platform auto-offer eligible? (Phase 2)
  YES → apply platform offer
  NO  → skip

Step 6 — Final total shown to customer
  Subtotal (after layer 1):    TZS 15,000
  Coupon JIKO20 (layer 2):   - TZS 3,000
  Delivery:                    TZS 1,500
  ─────────────────────────────────────────
  You pay:                     TZS 13,500
  Savings shown:               TZS 3,500 (item discounts + coupon)

4.2 The Clean Separation Rule

Layer 1 (menu discount)
  → Is a PRICE. Not a promotion. Not tracked as offer usage.
  → No budget. No rules. No code. No audit trail as offer.
  → Kitchen absorbs it silently in their margin.

Layer 2 (coupon)
  → Is a PROMOTION. Tracked. Has budget. Has rules. Has audit trail.
  → Goes through the full coupon engine.
  → Creates CouponRedemptionEntity, updates budgetUsed, perUserCount.

Layer 3 (auto-offer, phase 2)
  → Is a PLATFORM PROMOTION. System-triggered.
  → Full audit trail. Platform absorbs cost.
  → Only applies if no coupon was entered (coupon wins).

4.3 Channel Behaviour Per Layer

                    App    WhatsApp   Counter   Kiosk
                    ───    ────────   ───────   ─────
Layer 1 (menu)       ✅       ✅         ✅        ✅   always, no config
Layer 2 (coupon)     ✅       ✅         ✅        ✅   configurable per coupon
Layer 3 (auto)       ✅       ✅         ✅        ✅   phase 2

Menu discounts are never channel-restricted. A price is a price everywhere. Coupons can optionally be restricted — but default is all channels.


5. Phase Strategy — What We Build Now vs Later

This is the most important section for implementation planning.

Why Coupons First is the Right Decision

Auto-applied offers require:                Coupons require:
  → User profiling                            → User enters a code
  → Order history queries at checkout         → System validates
  → Real-time eligibility on every session    → Done
  → Complex targeting logic
  → Easy to get wrong silently

Coupons give you 80% of the value at 20% of the complexity. More importantly — coupons give you market feedback before you build more. You learn which offer types actually drive orders in Tanzania before over-engineering.

Phase 1 — Build Now

✅ Coupon engine
     Admin creates platform coupons
     Kitchen owner creates kitchen coupons
     Full rule engine behind every coupon
     Full scope targeting (whole kitchen, menu item, delivery)
     All channels (App, WhatsApp, Counter, Kiosk)

✅ Referral system
     Built on top of coupon engine
     System generates unique referral coupon per user
     Referrer reward via wallet credit after referee completes first order

✅ B2B subscription offers
     Manual — admin grants trial or discount via subscription admin panel
     No separate offer engine needed
     Subscription system handles it directly

Phase 2 — After Real User Data

⏳ Auto-applied offers
     Birthday offers (daily scheduled job)
     Welcome offer for new users (auto-apply on first checkout)
     New user window offers

⏳ Automated B2B offer engine
     System detects kitchen growth signals
     Auto-triggers trial offer
     Tracks acceptance and conversion

⏳ Advanced offer types
     Flash sales with countdown
     Happy hour triggers
     Community offers

The Key Mindset

Phase 1 coupon engine is NOT a simplified version.
It IS the full engine — rules, scope, budget, limits, all of it.
The only thing missing is the auto-apply trigger.
When Phase 2 comes → you add AUTO_APPLIED redemption type
and write the trigger logic. The engine itself doesn't change.

5. The Coupon Engine — Phase 1 Architecture

5.1 The Full Flow

COUPON CREATED (Admin or Kitchen Owner)
  Code set (e.g. JIKO20)
  Offer type set (FREE_DELIVERY, PERCENT_DISCOUNT, etc.)
  Scope set (whole kitchen, menu item, delivery only)
  Rules attached (first order, min amount, time window, etc.)
  Budget + limits set
  Lifespan set (startDate → endDate)
        │
        ▼
COUPON ACTIVE
  Discoverable in kitchen deal badges (if kitchen coupon)
  Shareable by admin via WhatsApp / SMS / social
  Printable by kitchen on physical flyers
        │
        ▼
CUSTOMER ENTERS CODE AT CHECKOUT
        │
        ▼
VALIDATION LAYER (atomic — no side effects yet)
  ├── Does this code exist?
  ├── Is the coupon ACTIVE?
  ├── Is the channel eligible?
  ├── Does the order scope match? (right kitchen? right item?)
  ├── Does customer pass ALL rules?
  ├── Is totalBudget remaining?
  ├── Has user hit perUserLimit?
  ├── Is dailyUseLimit still available?
  │
  ├── ANY FAIL → clear error shown, no money moved
  │
  └── ALL PASS →
        │
        ▼
  SLOT LOCKED (prevents race condition on last redemption)
        │
        ▼
  DISCOUNT COMPUTED + SHOWN TO CUSTOMER
        │
        ▼
  PAYMENT PROCESSED
        │
        ├── PAYMENT SUCCESS →
        │     CouponRedemptionEntity created
        │     CouponUsageEntity updated (perUser count)
        │     budgetUsed updated
        │     totalUsed updated
        │     Auto-deactivate check (budget or limit exhausted?)
        │
        └── PAYMENT FAILED →
              Slot released
              Coupon still available
              Customer can retry

5.2 Validation is Atomic

Validation happens before payment. If validation fails, nothing has happened — no money, no records, no side effects. This is non-negotiable.

5.3 One Coupon Per Order — Phase 1

One coupon code per order. No stacking. Ever. Phase 1.

This is a deliberate decision, not a limitation. Here is the full reasoning:

Financial clarity:
  One coupon → discount calculation is clean and predictable
  Two coupons → edge cases multiply:
    Do they stack on original price or already-discounted price?
    What if one is platform-funded and one is kitchen-funded?
    What if FREE_DELIVERY + PERCENT_DISCOUNT both apply?
    → Financial math becomes ambiguous fast

Abuse prevention:
  User finds two 20% off coupons → stacks them → 40% off
  Platform or kitchen bleeds money on one order
  One coupon → cost is controlled and predictable

Market learning:
  You don't yet know which coupon types resonate in Tanzania
  Run one coupon per order → collect data → understand behavior
  Then decide if stacking makes sense and for which combinations

The rule at checkout:

Customer enters first code    → validated and applied, shown in summary
Customer enters second code   → first code is REPLACED by second
                                 customer sees new discount
                                 only the last entered code applies at payment
Customer removes code         → order returns to full price

Last code entered wins. Customer can change their mind freely — but only one applies when they place the order.

Phase 2 — Controlled Stacking (when data justifies it):

One platform coupon + one kitchen coupon  → potentially allowed (different funders)
Two platform coupons                      → never allowed
Two kitchen coupons                       → never allowed
FREE_DELIVERY + PERCENT_DISCOUNT          → potentially allowed (different targets)
Two PERCENT_DISCOUNT coupons              → never allowed

This is future thinking only. Build it when kitchens are running coupons constantly and users are actively requesting it.

5.4 Validation Response — Always Specific

✅ VALID           → show discount amount, "JIKO20 applied ✓"
❌ NOT_FOUND       → "This code doesn't exist"
❌ EXPIRED         → "This offer has ended"
❌ NOT_YET_ACTIVE  → "This offer starts on [date]"
❌ ALREADY_USED    → "You've already used this code"
❌ LIMIT_REACHED   → "This offer is fully redeemed"
❌ BUDGET_EXHAUSTED→ "This offer is no longer available"
❌ WRONG_KITCHEN   → "This code is only valid at [Kitchen Name]"
❌ WRONG_ITEM      → "This code only applies to [Item Name]"
❌ MIN_NOT_MET     → "Minimum order TZS [X] required"
❌ WRONG_DAY       → "This offer is only valid on [days]"
❌ WRONG_TIME      → "This offer is only valid between [time] – [time]"
❌ NOT_FIRST_ORDER → "This offer is for first-time orders only"
❌ NOT_NEW_USER    → "This offer is for new users only"
❌ WRONG_CHANNEL   → "This code is not valid on this channel"

Never a vague "invalid code." Always tell the user exactly why. This is UX that builds trust.


6. Offer Types — Deep Dive

6.1 FREE_DELIVERY

Customer pays zero delivery fee. The delivery cost is absorbed by whoever owns the coupon.

Platform coupon → platform pays rider from treasury (EXPENSE_OFFER_SUBSIDY)
Kitchen coupon  → deducted from kitchen earnings at settlement

This is different from:

  • Kitchen self-delivery setting → kitchen uses own riders, JikoXpress not involved (not a coupon)
  • Kitchen delivery subsidy setting → standing "cover all delivery this week" config (not a coupon)

FREE_DELIVERY coupon is promotional — has rules, budget, lifespan, code. Always goes through the coupon engine.

Psychology: #1 checkout abandonment reason is delivery fee. Removing it with a code converts hesitant users instantly.


6.2 PERCENT_DISCOUNT

X% off the order subtotal. Optional maximum cap.

Example: 20% off, max TZS 5,000
Order TZS 12,000 → discount TZS 2,400 (20%) → customer pays TZS 9,600
Order TZS 30,000 → discount capped at TZS 5,000 → customer pays TZS 25,000

Almost always paired with MIN_ORDER_AMOUNT rule to protect margin.

Psychology: Anchoring. Customer calculates savings themselves, feels smart.


6.3 FIXED_DISCOUNT

Flat TZS amount off. Simpler to market than percent.

Example: TZS 2,000 off orders above TZS 8,000
"TZS 2,000 OFF" on a banner → more readable than "20% off up to TZS 5,000"

Psychology: Simplicity. Customer knows exactly what they save before doing math.


6.4 FREE_ITEM

A specific menu item is free on this order.

Coupon: FREEJUICE
Offer:  Get one Mango Juice free with any main course
Scope:  SPECIFIC_MENU_ITEM (menuItemId = juice item)
Rule:   MIN_ORDER_AMOUNT = 8,000 (must order a main course worth this)

Kitchen use case — push a new menu item by making it free for first 100 orders. Sampling strategy that works in physical markets too (print flyers, drive digital orders).

Psychology: Reciprocity. Free gift creates obligation to order again.


7. The Rule Engine

Every coupon can have multiple eligibility rules. All rules must pass (AND logic) for the coupon to apply. Rules are stored as separate records linked to the coupon — new rule types can be added in future without changing the coupon structure.

7.1 Phase 1 Rules

┌──────────────────────────────┬──────────────────────────────────────────────┐
│ Rule Type                    │ What It Checks                               │
├──────────────────────────────┼──────────────────────────────────────────────┤
│ FIRST_ORDER                  │ User has zero completed orders ever          │
│ FIRST_ORDER_AT_KITCHEN       │ User has zero completed orders at this       │
│                              │ specific kitchen                             │
│ MIN_ORDER_AMOUNT             │ Order subtotal >= configured amount (TZS)    │
│ NEW_USER_DAYS                │ User registered within last N days           │
│ VALID_TIME_WINDOW            │ Current time is between start and end time   │
│ VALID_DAYS_OF_WEEK           │ Today is one of the configured days          │
│ MAX_USES_PER_USER            │ User redemption count < configured limit     │
│ ELIGIBLE_CHANNEL             │ Order channel is in the allowed list         │
└──────────────────────────────┴──────────────────────────────────────────────┘

7.2 How Rules Compose — Real Examples

"Welcome coupon — new user, first order ever"
  FIRST_ORDER
  NEW_USER_DAYS = 7

"Lunch special — weekdays only, 12pm–2pm, above TZS 10,000"
  VALID_DAYS_OF_WEEK = [MON, TUE, WED, THU, FRI]
  VALID_TIME_WINDOW  = 12:00 – 14:00
  MIN_ORDER_AMOUNT   = 10,000

"New customer promo — first time at this kitchen, above TZS 8,000, weekend"
  FIRST_ORDER_AT_KITCHEN
  MIN_ORDER_AMOUNT   = 8,000
  VALID_DAYS_OF_WEEK = [FRI, SAT]

"Simple discount — no restrictions, anyone, any time"
  (no rules attached — just budget and lifespan limits)

7.3 Future Rule Types — Phase 2

MIN_ORDERS_COMPLETED      → "Must have ordered at least 5 times total"
REFERRED_USER             → "Must have come via a referral link"
BIRTHDAY_MONTH            → "User's birthday is this month"
SPECIFIC_PAYMENT_METHOD   → "Must pay via mobile money"
REPEAT_CUSTOMER           → "Has ordered from this kitchen before"

Adding a new rule = new enum value + new validation handler. Zero schema changes.


8. Coupon Scope — What a Coupon Can Target

Every coupon has a scope that defines which orders and items it applies to.

┌─────────────────────┬───────────────────────────────────────────────────┐
│ Scope               │ Meaning                                           │
├─────────────────────┼───────────────────────────────────────────────────┤
│ ALL_KITCHENS        │ Platform coupon — works at any kitchen            │
│ SPECIFIC_KITCHEN    │ Only at one named kitchen                         │
│ WHOLE_KITCHEN       │ Any item from this kitchen qualifies              │
│ SPECIFIC_MENU_ITEM  │ Only this specific item gets the discount         │
│ DELIVERY_ONLY       │ Only the delivery fee is affected                 │
│                     │ Food price unchanged                              │
└─────────────────────┴───────────────────────────────────────────────────┘

Scope + Offer Type Combinations

DELIVERY_ONLY + FREE_DELIVERY      → classic free shipping coupon
SPECIFIC_MENU_ITEM + FREE_ITEM     → free specific item
WHOLE_KITCHEN + PERCENT_DISCOUNT   → % off everything at this kitchen
ALL_KITCHENS + FIXED_DISCOUNT      → TZS X off any order anywhere
SPECIFIC_KITCHEN + FREE_DELIVERY   → partnership deal with one kitchen

10. Delivery Configuration vs Offers

This is the most important separation in the delivery + offer system. Three things look similar on the surface but are fundamentally different systems.

┌───────────────────────────┬─────────────────────────────────────────────┐
│ Concept                   │ What It Is                                  │
├───────────────────────────┼─────────────────────────────────────────────┤
│ Kitchen Self-Delivery     │ Kitchen uses own riders.                    │
│ (KitchenDeliveryConfig)   │ JikoXpress NOT involved at all.             │
│                           │ NOT a coupon. NOT financial.                │
│                           │ Just a capability flag.                     │
├───────────────────────────┼─────────────────────────────────────────────┤
│ Kitchen Delivery Subsidy  │ "I cover all delivery fees this week."      │
│ (KitchenDeliverySubsidy)  │ JikoXpress still dispatches riders.         │
│                           │ NOT a coupon. Standing config with          │
│                           │ lifespan. No code. No rules.                │
├───────────────────────────┼─────────────────────────────────────────────┤
│ FREE_DELIVERY Coupon      │ Promotional. Has code, rules, budget,       │
│ (CouponEntity)            │ lifespan. Platform or kitchen funded.       │
│                           │ Goes through full coupon engine.            │
└───────────────────────────┴─────────────────────────────────────────────┘

Distance-Based Delivery Pricing

Kitchen can configure delivery fee by distance — this is kitchen config, not a coupon:

Kitchen X delivery tiers:
  0 – 2 km   → Free delivery
  2 – 5 km   → TZS 1,000
  5 – 10 km  → TZS 2,500
  Above 10km → Not deliverable

Priority Chain at Delivery Checkout

When a customer places a delivery order, system resolves in this exact order:

Step 1: Does kitchen handle own delivery?
        YES → customer uses kitchen's own system, JikoXpress out entirely
        NO  → continue

Step 2: Is customer within kitchen's max delivery radius?
        NO  → reject (cannot deliver to this location)
        YES → continue

Step 3: Calculate base delivery fee from distance tiers (or flat fee)

Step 4: Is there an active Kitchen Delivery Subsidy for this order?
        YES → fee = 0, kitchen billed at settlement
        NO  → continue

Step 5: Did customer enter a FREE_DELIVERY coupon that passed validation?
        YES → fee = 0, coupon owner (platform or kitchen) absorbs cost
        NO  → continue

Step 6: Customer pays the calculated delivery fee


11. Offer Governance & Loss Prevention

This section exists because offers, done without controls, will bleed money silently. Every control here is deliberate — designed to prevent the three failure modes: overspending, abuse, and accidental duplication.

11.1 Who Can Trigger What — Strict Lane Separation

┌─────────────────────┬──────────────────────────────────────────────────┐
│ Actor               │ What They Can Create / Trigger                   │
├─────────────────────┼──────────────────────────────────────────────────┤
│ JikoXpress Admin    │ Platform coupons (any type, any kitchen scope)   │
│                     │ Platform free delivery offers                    │
│                     │ Referral reward configuration                    │
│                     │ B2B subscription trials (manual)                 │
├─────────────────────┼──────────────────────────────────────────────────┤
│ Kitchen Owner       │ Kitchen coupons (their kitchen only)             │
│                     │ Menu item discounts (their items only)           │
│                     │ Kitchen delivery subsidy (their orders only)     │
├─────────────────────┼──────────────────────────────────────────────────┤
│ System (automated)  │ Referral coupon generation (on user request)     │
│                     │ Auto-deactivation when budget/limit exhausted    │
│                     │ Auto-expiry at endDate                           │
│                     │ Phase 2 only: auto-offer triggering              │
└─────────────────────┴──────────────────────────────────────────────────┘

Nobody crosses their lane. Admin cannot touch kitchen pricing. Kitchen cannot touch platform offers. System only does what it is explicitly programmed to do.


11.2 The Six Hard Controls

These controls are non-negotiable. Every coupon must have all applicable controls set before it can go active.

Control 1 — Hard Budget Cap

Every coupon must have a totalBudget set.
When budgetUsed reaches totalBudget → coupon auto-deactivates immediately.
No human intervention needed. No override possible.
No open-ended "unlimited budget" coupons allowed in the system.

Platform coupon budget = marketing cost line (admin accountable)
Kitchen coupon budget  = kitchen's own money (they feel the pain directly)

Control 2 — Hard Time Boundary

Every coupon must have startDate and endDate.
System auto-expires at endDate — midnight, no exceptions.
No open-ended coupons. No "runs until we decide to stop it."
Admin must set an end date before publishing.

Control 3 — Per-User Limit

perUserLimit prevents one person from emptying the budget alone.
Default: 1 use per user unless explicitly set higher.
System checks CouponUsageEntity before every redemption.

Control 4 — Daily Redemption Limit

dailyUseLimit = max redemptions across all users per day.
Even if budget remains, daily cap protects against day-1 rush abuse.
Spreads the cost over the full lifespan rather than burning in hours.

Control 5 — Total Redemption Limit

totalUseLimit = max redemptions ever, regardless of budget.
Useful for "first 100 customers only" style campaigns.
Whichever hits first (budget or redemption limit) auto-deactivates.

Control 6 — Duplicate Offer Warning

When admin creates a new coupon, system checks:
  Is there already an ACTIVE coupon of the same type
  covering the same scope?

  Example: FREE_DELIVERY coupon already active for ALL_KITCHENS?
  → System warns: "A free delivery coupon (FREESHIP) is already running.
     Creating another will double your committed delivery budget.
     Deactivate FREESHIP first, or confirm you want both active."

Admin must explicitly confirm before publishing the duplicate.
This prevents accidental budget doubling — the most common admin mistake.

11.3 The Real-Time Governance Dashboard (Admin)

Admin sees a live view of all active offer costs:

┌──────────────────────────────────────────────────────────┐
│ Active Offers — Live Overview                            │
│                                                          │
│ Total active coupons:          4                         │
│ Total budget committed:        TZS 1,200,000             │
│ Total burned today:            TZS 187,000               │
│ Projected burn by end dates:   TZS 820,000               │
│                                                          │
│ ⚠ At risk (>80% budget used):                           │
│   JIKO20 — 84% used — TZS 32,000 remaining             │
│                                                          │
│ COUPON      TYPE          USED    BUDGET     STATUS      │
│ JIKO20      20% off       168×    84% used   ACTIVE ●   │
│ FREESHIP    Free delivery  43×    43% used   ACTIVE ●   │
│ REF-*       Referral       89×    62% used   ACTIVE ●   │
│ MAMA15      Kitchen 15%    31×    78% used   ACTIVE ●   │
└──────────────────────────────────────────────────────────┘

You see the bleeding before it kills you.


11.4 How Conflict Is Actually Prevented

The real-world conflict scenarios and how each is handled:

SCENARIO 1: Two free delivery coupons active simultaneously
  FREESHIP (platform) active
  Admin creates FREERIDE (platform) — same scope
  → Duplicate warning fires before publishing
  → Admin must confirm or deactivate FREESHIP first
  → Even if both go active, one coupon per order rule means
     customer only uses one — no double cost per order
  → But total budget is double what was intended — warning saves this

SCENARIO 2: Platform coupon + kitchen coupon same order
  JIKO20 (platform 20% off) — customer enters this
  MAMA15 (kitchen 15% off) — customer tries to add this
  → Second code replaces first (our one-coupon rule)
  → Customer chooses which one to use
  → No stacking, no conflict, no double cost

SCENARIO 3: Menu discount + coupon
  Item has TZS 500 menu discount already (Layer 1)
  Customer applies JIKO20 coupon (Layer 2)
  → Coupon applies to the already-discounted subtotal
  → Both discounts apply — by design, no conflict
  → Menu discount absorbed by kitchen margin
  → Coupon cost absorbed by platform or kitchen (whoever owns it)
  → Separate cost centers, no confusion

SCENARIO 4: Budget exhausted mid-day
  FREESHIP budget TZS 200,000
  Order 87 pushes budgetUsed to TZS 200,000
  → Auto-deactivates immediately
  → Order 88 tries FREESHIP → "This offer is no longer available"
  → No over-spending. Ever.

11.5 Kitchen-Level Protection

Kitchen owners also need protection from their own offers:

Kitchen creates MAMA15 — 15% off, no budget cap set
→ System REQUIRES a budget before publishing
   "Set a maximum budget to protect your earnings"

Kitchen's dashboard shows real-time:
  MAMA15 used 31×  ·  TZS 28,500 subsidized  ·  Budget: 71% remaining
  Estimated end: Sunday (at current rate)

At 90% budget → kitchen gets a warning notification:
  "Your MAMA15 coupon budget is almost used up.
   Add more budget or let it auto-stop when exhausted."

12. Referral System — Built on Coupon Engine

The referral system is not a separate engine. It sits on top of the coupon engine. A referral is a system-generated coupon with special attributes.

10.1 How It Works

Customer A (Grace) wants to refer a friend
Grace goes to "Refer a Friend" section
System generates a unique referral coupon: REF-GRACE7X
        │
        ▼
Grace shares code/link with Zawadi via WhatsApp, SMS, or any channel
        │
        ▼
Zawadi registers on JikoXpress
Zawadi places her first order
Zawadi enters REF-GRACE7X at checkout
        │
        ▼
Coupon engine validates:
  ✓ Code exists and is a referral code (REF- prefix)
  ✓ Zawadi is a new user (NEW_USER_DAYS rule)
  ✓ This is Zawadi's first order (FIRST_ORDER rule)
  ✓ Code not yet used (perUserLimit = 1, totalUseLimit = 1)
  ✓ Grace cannot refer herself (device/phone check)
        │
        ▼
Offer applied: FREE_DELIVERY on Zawadi's first order
        │
        ▼
Order completes
        │
        ├── Zawadi already got free delivery (applied at checkout)
        │
        └── ReferralRewardEntity created for Grace
              Status: PENDING → UNLOCKED
              TZS 2,000 wallet credit → Grace's wallet
              Push notification: "Zawadi placed her first order! TZS 2,000 added to your wallet 💰"

10.2 Referral Coupon Properties

Code format       → REF-[shortcode] (e.g. REF-GRACE7X)
Generated by      → system (not human-readable marketing code)
Offer type        → FREE_DELIVERY (referee gets free delivery on first order)
Rules attached    → FIRST_ORDER + NEW_USER_DAYS
perUserLimit      → 1 (referee can only use one referral code)
totalUseLimit     → 1 (each referral code is single-use)
Funded by         → Platform (marketing cost)
linkedReferrer    → Grace's userId (for reward tracking)

10.3 Referral Entities

ReferralEntity
  referrerId       → Grace
  refereeId        → Zawadi (set when Zawadi registers with the link)
  couponCode       → REF-GRACE7X
  status           → PENDING | COMPLETED | REWARDED | VOIDED

ReferralRewardEntity
  referralId       → links to ReferralEntity
  beneficiary      → REFERRER (Grace) or REFEREE (Zawadi)
  rewardType       → WALLET_CREDIT | OFFER_APPLIED
  amount           → TZS 2,000 (Grace) / TZS 1,500 delivery value (Zawadi)
  status           → PENDING | UNLOCKED | PAID | EXPIRED

10.4 Anti-Abuse Rules

Self-referral check      → Grace cannot use her own code
Device fingerprint       → same device cannot be both referrer and referee
Phone number check       → same number cannot register twice
Reward only on complete  → Zawadi must complete order (not just register)

10.5 Financial Impact

Cost per referral:
  Zawadi's free delivery subsidy:  TZS 1,500 → EXPENSE_OFFER_SUBSIDY
  Grace's wallet credit:           TZS 2,000 → EXPENSE_REFERRAL_REWARD
  Total platform cost:             TZS 3,500

vs. acquiring a new user via digital ads in Tanzania:
  Estimated CAC via ads:           TZS 15,000 – 25,000+

Referral CAC: TZS 3,500 with two happy, engaged users.

13. B2B — Kitchen Subscription Offers

Why B2B Is Not in the Coupon Engine (Phase 1)

Coupon engine target  → customers (end users placing food orders)
B2B target            → kitchen owners (business operators)
B2B currency          → subscription months, plan access
B2B logic             → lives in the subscription system

Building a separate B2B coupon engine in phase 1 is overengineering. The subscription system already has everything needed.

Phase 1 — Manual Admin Actions

Admin handles B2B directly from the subscription admin panel:

FREE TRIAL
  Admin selects kitchen → "Grant free trial"
  Selects plan (PROFESSIONAL) and duration (30 days)
  SubscriptionEntity updated:
    plan = PROFESSIONAL
    trialEndDate = today + 30 days
    isTrial = true
  Kitchen owner notified via WhatsApp
  Day 28 → system reminder to kitchen owner
  Day 30 → auto-revert to previous plan if not upgraded

DISCOUNTED UPGRADE
  Admin selects kitchen → "Apply discount"
  Sets discount percent and duration (N billing cycles)
  Subscription billing uses discounted rate for those cycles
  Normal rate resumes after

LOYALTY REWARD
  Admin manually adjusts kitchen's subscription rate
  "You've been with us 12 months — 20% off forever"
  Admin note recorded for audit trail

Phase 2 — Automated B2B Engine

When you have enough kitchens that manual management doesn't scale:

System detects growth signals (order volume threshold)
Auto-triggers trial offer to qualifying kitchens
Tracks acceptance, trial usage, conversion rate
Full B2B offer engine with targeting rules

14. Notification & Preference System

12.1 User Notification Preferences

Every customer controls their offer notification preferences:

Master toggle: Notify me for offers  [ON / OFF]

If ON — what types do you want?
  ☑ Free delivery deals
  ☑ Discounts & coupons
  ☑ New kitchen promotions
  ☑ Birthday offers
  ☐ Flash sales
  ☑ Referral rewards

One UserOfferPreferenceEntity per user. System only notifies users who opted in to the relevant category.

12.2 Notification Triggers

TRIGGER                          ACTION
───────────────────────────────  ──────────────────────────────────────────────
New platform coupon published  → notify all eligible opted-in users
New kitchen coupon published   → notify users who ordered from this kitchen
                                  and opted in
Referral reward unlocked       → notify referrer "TZS 2,000 added to wallet"
Coupon about to expire         → 24hr warning if user viewed but didn't redeem
B2B trial offer granted        → WhatsApp to kitchen owner
B2B trial ending soon          → reminder 2 days before trial ends

12.3 Notification Channels

Push notification   → app users
WhatsApp message    → WhatsApp channel users (highest open rate in Tanzania)
SMS                 → fallback for users without WhatsApp or app
In-app banner       → shown next time user opens app

15. User Journeys — All Levels

13.1 New Customer — Platform Coupon (Admin Drops Code on WhatsApp)

[JikoXpress admin posts in a WhatsApp group]:
"New on JikoXpress? Use code JIKO20 — 20% off your first order! 🎉"

Maria sees the message, downloads the app, registers
        │
        ▼
Maria browses kitchens, adds items (TZS 10,000 food)
        │
        ▼
Checkout → Maria types: JIKO20
        │
        ▼
System validates:
  ✓ Code exists
  ✓ Coupon is ACTIVE
  ✓ Channel: App (eligible)
  ✓ FIRST_ORDER rule → Maria has 0 completed orders ✓
  ✓ NEW_USER_DAYS = 7 → Maria registered today ✓
  ✓ Budget remaining
  ✓ perUserLimit not hit
        │
        ▼
Checkout updates:
  Food total:     TZS 10,000
  20% discount:   - TZS 2,000
  You pay:        TZS 8,000
  "JIKO20 applied — You saved TZS 2,000 ✓"
        │
        ▼
Maria pays TZS 8,000. Order placed. Order arrives.
        │
        ▼
Order confirmation: "You saved TZS 2,000 today 🎉
 Share JikoXpress with a friend — you BOTH get a reward. [Share]"
        │
        ▼
Maria immediately shares her referral code.
New user acquired. Referral loop started.

13.2 Regular Customer — Kitchen Coupon from Physical Flyer

[Juma walks past a flyer in Mbeya town]
Flyer: "Order from Mama Lishe online — use MAMA15 for 15% off this weekend 🍽"
        │
        ▼
Juma opens JikoXpress (app or WhatsApp), finds Mama Lishe, adds items (TZS 12,000)
        │
        ▼
Checkout → types: MAMA15
        │
        ▼
System validates:
  ✓ Code exists
  ✓ Coupon is ACTIVE, scope = SPECIFIC_KITCHEN (Mama Lishe) ✓
  ✓ VALID_DAYS_OF_WEEK = [FRI, SAT] → today is Saturday ✓
  ✓ MIN_ORDER_AMOUNT = 8,000 → order is TZS 12,000 ✓
  ✓ perUserLimit = 2 → Juma has used 0 times ✓
        │
        ▼
Checkout updates:
  Food:          TZS 12,000
  15% discount:  - TZS 1,800
  You pay:       TZS 10,200
  "MAMA15 applied — You saved TZS 1,800 ✓"
        │
        ▼
Order placed.
Kitchen Mama Lishe receives:
  Gross:             TZS 12,000 (full food amount)
  Less offer subsidy:- TZS 1,800 (kitchen funded this)
  Net settlement:     TZS 10,200
Platform earns service fee on original TZS 12,000.

Physical flyer → digital order. Tanzania market unlocked.


13.3 New User — Referral Coupon

[Grace is a happy JikoXpress user]
Grace goes to "Refer a Friend" → gets code REF-GRACE7X
Grace sends it to her sister Zawadi via WhatsApp
        │
        ▼
Zawadi registers on JikoXpress
Zawadi browses, adds items (TZS 9,000 food, delivery TZS 1,500)
        │
        ▼
Checkout → Zawadi enters: REF-GRACE7X
        │
        ▼
System validates:
  ✓ Referral code exists and is valid
  ✓ Zawadi is a new user ✓
  ✓ This is Zawadi's first order ✓
  ✓ Code not yet used ✓
  ✓ Grace ≠ Zawadi (self-referral check passed) ✓
        │
        ▼
Offer: FREE_DELIVERY applied
  Food:           TZS 9,000
  Delivery:       ~~TZS 1,500~~ → FREE ✓
  You pay:        TZS 9,000
  "Welcome gift — Free delivery on your first order 🎁"
        │
        ▼
Zawadi pays TZS 9,000. Order completes.
        │
        ▼
System creates ReferralRewardEntity for Grace
Status: PENDING → UNLOCKED
TZS 2,000 credited to Grace's wallet
        │
        ▼
Grace gets push notification:
"Your sister Zawadi placed her first order! TZS 2,000 added to your wallet 💰"
        │
        ▼
Grace uses wallet credit on her next order.
Two users engaged. Total platform cost: TZS 3,500.

13.4 Kitchen Owner — Creating a Weekend Promo Coupon

[Mama Lishe logs into kitchen dashboard — Thursday afternoon]
Goes to Offers → clicks [+ New Coupon]
        │
        ▼
Form:
  Coupon code:     MAMA15 (she types this — her brand, memorable)
  Offer type:      PERCENT_DISCOUNT
  Discount:        15%
  Applies to:      Whole kitchen
  Rules:
    Min order:     TZS 8,000
    Valid days:    Friday, Saturday
    Time window:   All day (no time restriction)
  Budget:          TZS 40,000 (won't spend more than this)
  Per user limit:  2 uses
  Runs:            This Friday → Sunday night
        │
        ▼
Coupon goes ACTIVE
Deal badge appears on Mama Lishe's kitchen card in the app
        │
        ▼
Kitchen dashboard shows real-time:
  "MAMA15 — Used 18× today · TZS 28,500 subsidized · Budget: 29% remaining"
        │
        ▼
Sunday midnight → coupon auto-expires
Kitchen sees performance report:
  Total orders from coupon: 31
  Total subsidy paid:       TZS 40,000 (budget fully used, auto-deactivated)
  New customers acquired:   14 first-time orders at this kitchen

Kitchen owner has full control, zero surprises.


13.5 Kitchen Owner — Receiving B2B Trial Offer (Manual Phase 1)

[Kitchen Bora Bora — 4 months on STARTER, growing fast]
Admin notices 3x order volume growth in last 60 days
Admin goes to subscription admin panel
Selects Bora Bora → [Grant Free Trial]
  Plan: PROFESSIONAL
  Duration: 30 days
  Note: "Growth milestone reward"
        │
        ▼
Admin sends WhatsApp to Bora Bora owner:
"Habari! Your kitchen is growing fast 🚀
 We're giving you FREE access to PROFESSIONAL plan for 30 days.
 Enjoy: unlimited menu items, advanced analytics, priority support.
 No action needed — it's already active. Try it!"
        │
        ▼
Day 28 → system auto-sends reminder to kitchen:
"Your free PROFESSIONAL trial ends in 2 days.
 Upgrade to keep your features — TZS 45,000/month.
 Reply to talk to our team."
        │
        ▼
Kitchen has grown accustomed to PROFESSIONAL features → upgrades.

16. UI Ideas & Flow Concepts

14.1 Home Screen — Coupon Discovery

┌─────────────────────────────────────────────┐
│  JikoXpress              🔔  👤             │
│                                             │
│  ┌─────────────────────────────────────┐   │
│  │  🎉 Use code JIKO20 — 20% off       │   │
│  │     your order today!               │   │
│  │     [Copy Code]                     │   │
│  └─────────────────────────────────────┘   │
│                                             │
│  🔥 Kitchens With Deals                    │
│  ┌────────────┐  ┌────────────┐            │
│  │ [Photo]    │  │ [Photo]    │            │
│  │ Mama Lishe │  │ Bora Bora  │            │
│  │ 🏷 MAMA15  │  │ 🚚 Free    │            │
│  │ 15% OFF    │  │ delivery   │            │
│  └────────────┘  └────────────┘            │
└─────────────────────────────────────────────┘

Deal badges are visible before clicking into a kitchen. Value is shown upfront.

14.2 Checkout — Coupon Entry & Applied State

┌──────────────────────────────────────┐
│ Order Summary                        │
│                                      │
│ Ugali na Nyama        TZS 7,000      │
│ Pilau                 TZS 5,000      │
│ ───────────────────────────────────  │
│ Subtotal              TZS 12,000     │
│ Delivery              TZS 1,500      │
│                                      │
│ ┌──────────────────────────────┐    │
│ │ 🏷 Enter coupon code         │    │
│ │ [MAMA15          ] [APPLY]   │    │
│ └──────────────────────────────┘    │
│                                     │
│ ✅ MAMA15 applied!                  │
│ Discount:             - TZS 1,800   │
│ ───────────────────────────────────  │
│ Total                 TZS 10,200    │
│                                      │
│ 💚 You saved TZS 1,800 today!       │
│                                      │
│ [Place Order — TZS 10,200]          │
└──────────────────────────────────────┘

Savings celebrated before payment. Positive reinforcement at the most important moment.

14.3 Order Confirmation — Savings + Referral CTA

┌──────────────────────────────────────┐
│ ✅ Order Confirmed!                  │
│                                      │
│ Estimated delivery: 30 minutes       │
│                                      │
│ ┌──────────────────────────────┐    │
│ │ 💰 You saved TZS 1,800       │    │
│ │    with code MAMA15          │    │
│ └──────────────────────────────┘    │
│                                      │
│ 🎁 Know someone who'd love this?    │
│    Share your referral code and      │
│    you BOTH get a reward.            │
│    Your code: REF-MARIA3K           │
│    [Share Now]                       │
└──────────────────────────────────────┘

Every confirmation is a referral opportunity. Strike when satisfaction is highest.

14.4 Coupon Validation — Error State

┌──────────────────────────────────────┐
│ [MAMA15            ] [APPLY]         │
│                                      │
│ ❌ This offer is only valid on       │
│    Fridays and Saturdays.            │
│    Come back this weekend!           │
└──────────────────────────────────────┘

Specific error. Not just "invalid." And crucially — "come back this weekend" keeps the user engaged for a future order.

14.5 Kitchen Dashboard — Coupon Management

┌──────────────────────────────────────┐
│ My Coupons                 [+ New]   │
│                                      │
│ ● MAMA15 — Weekend Special  ACTIVE   │
│   15% off · Fri–Sat                 │
│   Used 18× · Budget: 29% left       │
│   Expires Sunday                     │
│   [Pause]  [Edit]  [Stats]          │
│                                      │
│ ○ OPENDAY — Grand Opening   EXPIRED  │
│   20% off · 3 days                  │
│   Used 87× · Budget fully used      │
│   New customers: 41                  │
│   [Duplicate as new]                 │
└──────────────────────────────────────┘

Performance visible at a glance. Kitchen owners see ROI clearly.

14.6 Offer Notification Preferences

┌──────────────────────────────────────┐
│ ← Offer Notifications                │
│                                      │
│ Get notified about deals             │
│ ●────────────────── ON              │
│                                      │
│ What interests you?                  │
│                                      │
│ 🚚 Free Delivery deals    ☑          │
│ 🏷 Discounts & coupons    ☑          │
│ 🆕 New kitchen promos     ☑          │
│ 🎂 Birthday offers        ☑          │
│ 🎁 Referral rewards       ☑          │
│ ⚡ Flash sales             ☐          │
│                                      │
│ [Save]                               │
└──────────────────────────────────────┘

User in control. Builds trust. Reduces unsubscribes.


17. Where JikoXpress Wins

15.1 The Tanzania-Specific Advantages

Physical coupon → digital order bridge Kitchen prints MAMA15 on a flyer, sticks it at a bus station, a market stall, a university notice board. Customer orders on WhatsApp or app using that code. No other food platform in Tanzania does this cleanly. This is the entire informal economy brought into the digital platform.

WhatsApp as a first-class coupon channel Admin drops JIKO20 in a WhatsApp group. Kitchen shares MAMA15 in their neighborhood group. These codes work on WhatsApp ordering directly. The channel Tanzanians already use becomes a marketing and ordering channel simultaneously.

Kitchen empowerment Kitchens are not passive suppliers. They create their own coupons, set their own rules, control their own budget. They become invested in JikoXpress success because JikoXpress invests in their success.

Referral at TZS 3,500 CAC Acquiring users via digital ads in Tanzania costs TZS 15,000–25,000+. A referral costs TZS 3,500 and gives you two engaged users. This is how JikoXpress grows without burning investor money.

15.2 What Jumia Got Wrong — What JikoXpress Fixes

Jumia's mistake                       JikoXpress answer
────────────────────────────────────  ──────────────────────────────────────────
App-only offers                    →  Coupons work on App + WhatsApp + Counter
No physical coupon bridge          →  Kitchen prints codes on flyers
Generic "save money" messaging     →  Specific errors, specific savings shown
No kitchen marketing tools         →  Kitchen dashboard with full coupon control
No referral program                →  Structured referral built on coupon engine
Burned budget on wrong users       →  Rule engine filters eligible users precisely

15.3 The Retention Loop

Customer discovers JikoXpress via referral code or admin coupon
        │
        ▼
First order → coupon gives value → positive experience
        │
        ▼
Refers a friend → wallet credit → uses wallet → orders again
        │
        ▼
Favorite kitchen runs a weekend promo → orders again
        │
        ▼
Habit formed → orders without needing a coupon
        │
        ▼
Becomes organic referrer

The coupon engine's real job is not discounts. Its job is to convert a first-time user into a habitual customer before they even notice it happened.


18. Financial Impact of Offers

16.1 Platform Coupon — Financial Flow

Platform coupon applied (e.g. JIKO20 — 20% off):

Customer pays:      TZS 8,000 (discounted)
Platform absorbs:   TZS 2,000 (the discount)
Kitchen receives:   TZS 10,000 (full original amount — always)

Journal:
  DEBIT   EXPENSE_OFFER_SUBSIDY    2,000
  CREDIT  ASSET_PSP_SELCOM         2,000

Platform service fee earned on original TZS 10,000 — not discounted amount.
Platform marketing cost = TZS 2,000.

16.2 Kitchen Coupon — Financial Flow

Kitchen coupon applied (e.g. MAMA15 — 15% off TZS 12,000 order):

Customer pays:      TZS 10,200 (discounted)
Kitchen absorbs:    TZS 1,800 (they chose to discount)
Kitchen receives:   TZS 10,200 net (after subsidy deduction at settlement)

Settlement:
  Kitchen gross:         TZS 12,000
  Less: coupon subsidy:  - TZS 1,800
  Kitchen net:           TZS 10,200

Platform service fee earned on original TZS 12,000.
Platform earns same regardless of kitchen's promotional decisions.

16.3 FREE_DELIVERY Coupon — Financial Flow

FREE_DELIVERY coupon applied:

Customer pays:      food total only (e.g. TZS 9,000)
Platform absorbs:   delivery fee (e.g. TZS 1,500) if platform coupon
Kitchen absorbs:    delivery fee if kitchen coupon (deducted at settlement)
Rider receives:     full delivery fee as normal

Platform coupon journal:
  DEBIT   EXPENSE_OFFER_SUBSIDY    1,500
  CREDIT  ASSET_PSP_SELCOM         1,500

16.4 Budget Controls — Automatic

Every coupon with a budget has automatic controls:

budgetUsed reaches 80% of budgetTotal → admin / kitchen notification
budgetUsed reaches 100%               → coupon auto-deactivates immediately
totalUsed reaches totalUseLimit       → coupon auto-deactivates immediately

No manual intervention needed.
No over-spending possible.

16.5 Referral Financial Impact

Per referral:
  Referee free delivery:     TZS 1,500 → EXPENSE_OFFER_SUBSIDY
  Referrer wallet credit:    TZS 2,000 → EXPENSE_REFERRAL_REWARD
  Total platform cost:       TZS 3,500

Industry digital ad CAC:     TZS 15,000 – 25,000+
Referral CAC:                TZS 3,500 with two engaged users

19. Entity Overview

No code. No schema. Just entities and their relationships.

CouponEntity
  → defines the coupon (code, type, owner, scope, discount config, budget, dates)
  → offerOwner: PLATFORM | KITCHEN
  → has many CouponRuleEntity
  → has many CouponUsageEntity (per user tracking)
  → has many CouponRedemptionEntity (per order)

CouponRuleEntity
  → one rule per record (ruleType + ruleValue)
  → many rules per coupon, ALL must pass (AND logic)

CouponUsageEntity
  → one record per user per coupon
  → tracks how many times this user used this coupon
  → prevents per-user limit violations

CouponRedemptionEntity
  → one record per order that used a coupon
  → stores exact discount applied, amount subsidized
  → funded by: PLATFORM or KITCHEN
  → linked to both coupon and order

KitchenDeliveryConfig
  → deliveryHandledBy: JIKOXPRESS | KITCHEN_SELF
  → deliveryPricingModel: FLAT_FEE | DISTANCE_BASED | FREE_ALWAYS
  → maxDeliveryRadiusKm
  → has many KitchenDeliveryTierEntity

KitchenDeliveryTierEntity
  → fromKm, toKm, fee, isDeliverable
  → child of KitchenDeliveryConfig

KitchenDeliverySubsidyEntity
  → standing delivery cost coverage (not a coupon)
  → coverageType: ALL_ORDERS | SPECIFIC_ORDERS
  → startDate, endDate, status: ACTIVE | EXPIRED | CANCELLED

UserOfferPreferenceEntity
  → one per user
  → notificationsEnabled (master toggle)
  → preferredTypes: list of OfferNotificationType

ReferralEntity
  → referrerId, refereeId
  → couponCode (the REF- code generated)
  → status: PENDING | COMPLETED | REWARDED | VOIDED

ReferralRewardEntity
  → referralId (links to ReferralEntity)
  → beneficiary: REFERRER | REFEREE
  → rewardType: WALLET_CREDIT | OFFER_APPLIED
  → amount, status: PENDING | UNLOCKED | PAID | EXPIRED


20. Implementation Prerequisites

The offer engine is designed. It is complete. Do not build it yet.

This is not because the design is incomplete — it is because offers touch every financial layer of the platform. Building offers while those layers are still moving creates financial bugs that are hard to trace and expensive to fix.

The offer engine implementation begins only when all of the following are green:

PREREQUISITE                              WHY IT MATTERS FOR OFFERS
────────────────────────────────────────  ─────────────────────────────────────────────
✅ Order lifecycle complete               Offer redemption is tied to order status.
   (checkout → confirmed → delivered)    Can't track "order completed" for FIRST_ORDER
                                         rule or referral reward unlock without this.

✅ Payment splitting working             Platform coupons debit EXPENSE_OFFER_SUBSIDY.
   (kitchen vs platform vs rider)        Kitchen coupons deduct from settlement.
                                         If splitting is wrong, offer accounting is wrong.

✅ Kitchen settlement working            Kitchen coupon subsidy is deducted at settlement.
   (earnings, deductions, payouts)       Can't deduct what hasn't been calculated.

✅ Journal entries flowing correctly     Every offer redemption creates journal entries.
                                         If double-entry bookkeeping isn't stable,
                                         offer entries will pollute the ledger.

✅ User order history queryable          FIRST_ORDER rule queries: "has this user ever
                                         completed an order?"
                                         FIRST_ORDER_AT_KITCHEN queries per kitchen.
                                         Needs reliable order history.

✅ Wallet system working                 Referral rewards credit the referrer's wallet.
                                         Wallet must exist and be transactionally safe
                                         before referral rewards are issued.

✅ Menu item management stable           Layer 1 (menu discount) is set on menu items.
                                         Menu item CRUD must be stable before adding
                                         discount fields to it.

When all seven are confirmed stable and tested in a real environment — open this document and begin entity design and implementation.

The design will not change significantly. The thinking is done. Build the foundation first.


21. Decision Log

Decision Choice Reason
Three discount layers Layer 1 (menu), Layer 2 (coupon), Layer 3 (auto-offer phase 2) Each serves a different purpose, different actor, different financial impact. Must never be confused.
Menu discount channels All channels, always A price is a price. Not a promotion. Channel restriction makes no sense for item pricing.
Menu discount lifespan None in phase 1 — kitchen edits manually Adding lifespan blurs the line between menu pricing and the coupon engine. Keep layers clean.
Menu discount financial Absorbed in kitchen margin, not tracked as offer It is a price reduction, not a promotional cost. No CouponRedemptionEntity created.
Phase 1 redemption Coupon codes only 80% of value, 20% complexity. Market feedback before building auto-apply.
Auto-applied offers Phase 2 Requires user profiling and eligibility checks on every checkout. Build when you have data.
Rule engine Separate CouponRuleEntity table Future-proof. New rule types added as enum values without schema changes.
Referral implementation System-generated coupon on top of coupon engine Reuses validation engine. Not a separate system. Clean separation of concerns.
B2B phase 1 Manual via subscription admin panel Not enough kitchens to justify automation. Admin handles manually.
Coupon codes on all channels Yes, default Physical flyer → WhatsApp/app/counter bridge is a real Tanzania market advantage.
Coupon stacking One coupon per order, phase 1 Financial math stays clean. Prevents abuse. Last code entered replaces previous. Phase 2 may allow controlled stacking when market data justifies it.
Kitchen always gets full amount Yes (platform coupons) Platform subsidy is platform's marketing cost. Kitchen is not penalized.
Platform earns on original price Yes (kitchen coupons too) Kitchen's promotional decision does not affect platform service fee.
Delivery config separation Three distinct systems Self-delivery config, subsidy standing instruction, and FREE_DELIVERY coupon are fundamentally different. Must never mix.
Distance-based delivery Kitchen config tiers Pricing decision by kitchen, resolved at checkout before coupons are checked.
Validation specificity Always specific error message "Come back this weekend" keeps user engaged. Vague errors kill conversion.
Budget auto-deactivation Yes, at 100% usage No over-spending possible. No manual intervention needed.
Budget required Mandatory before publishing any coupon No open-ended coupons. Every coupon has a financial ceiling.
Duplicate offer warning Yes — system warns before admin publishes duplicate type/scope Most common admin mistake. Prevents accidental budget doubling.
Referral CAC TZS 3,500 target TZS 1,500 (referee delivery) + TZS 2,000 (referrer wallet). Far below digital ad CAC.
Offer engine implementation timing Only after 7 core prerequisites are stable Offers touch every financial layer. Building on unstable foundation creates untraceable financial bugs.

QBIT SPARK CO LIMITED | JikoXpress Pro | May 2026 Internal offer engine architecture — confidential