Skip to content

YeboMart — Architecture Overview

Technical deep dive into YeboMart's architecture and codebase structure.


Repository Structure

YeboMart is a monorepo with five main components:

yebomart/
├── api/                    # Backend API (Express + Prisma)
│   ├── src/
│   │   ├── config/         # Database, pricing, environment
│   │   ├── controllers/    # Request handlers
│   │   ├── middleware/     # Auth, validation, rate limiting
│   │   ├── routes/         # API route definitions
│   │   ├── services/       # Business logic
│   │   ├── utils/          # Helpers (JWT, pagination, response)
│   │   └── server.ts       # Entry point
│   ├── prisma/
│   │   └── schema.prisma   # Database schema
│   └── package.json

├── app/                    # Main POS application (React)
│   ├── src/
│   │   ├── api/            # API client
│   │   ├── components/     # Reusable UI components
│   │   ├── lib/            # IndexedDB, utilities
│   │   ├── pages/          # Route pages
│   │   ├── stores/         # Zustand state stores
│   │   ├── types/          # TypeScript types
│   │   └── App.tsx         # Root component
│   └── package.json

├── admin/                  # Admin dashboard (React)
│   ├── src/
│   │   ├── api/            # Admin API client
│   │   ├── components/     # Dashboard components
│   │   ├── context/        # Auth context
│   │   ├── pages/          # Admin pages
│   │   └── App.tsx
│   └── package.json

├── frontend/               # Public website (if separate)
│   └── ...

└── landing/                # Marketing landing page
    └── ...

System Architecture

┌─────────────────────────────────────────────────────────────────────────┐
│                              CLIENTS                                     │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐                 │
│  │   YeboMart  │    │   Admin     │    │   Landing   │                 │
│  │     App     │    │  Dashboard  │    │    Page     │                 │
│  │   (React)   │    │   (React)   │    │   (React)   │                 │
│  └──────┬──────┘    └──────┬──────┘    └─────────────┘                 │
│         │                  │                                            │
│         │  JWT Auth        │  Admin JWT                                 │
│         ▼                  ▼                                            │
└─────────────────────────────────────────────────────────────────────────┘

                            │ HTTPS (Cloud Run URL)

┌─────────────────────────────────────────────────────────────────────────┐
│                           YeboMart API                                  │
│                      (Express + TypeScript)                             │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  ┌─────────────────────────────────────────────────────────────┐       │
│  │                      MIDDLEWARE LAYER                        │       │
│  ├───────────┬───────────┬───────────┬───────────┬─────────────┤       │
│  │   CORS    │  Helmet   │   Auth    │   Rate    │  License    │       │
│  │           │           │ Middleware│  Limiter  │  Checker    │       │
│  └───────────┴───────────┴───────────┴───────────┴─────────────┘       │
│                                                                         │
│  ┌─────────────────────────────────────────────────────────────┐       │
│  │                      ROUTE LAYER                             │       │
│  ├──────┬────────┬───────┬───────┬──────┬────────┬─────────────┤       │
│  │ auth │products│ sales │ stock │  ai  │billing │   admin     │       │
│  └──────┴────────┴───────┴───────┴──────┴────────┴─────────────┘       │
│                                                                         │
│  ┌─────────────────────────────────────────────────────────────┐       │
│  │                     CONTROLLER LAYER                         │       │
│  │  (Parse requests, validate, call services, send response)   │       │
│  └─────────────────────────────────────────────────────────────┘       │
│                                                                         │
│  ┌─────────────────────────────────────────────────────────────┐       │
│  │                      SERVICE LAYER                           │       │
│  ├─────────────┬───────────────┬─────────────┬─────────────────┤       │
│  │ AuthService │ProductService │ SaleService │  StockService   │       │
│  ├─────────────┼───────────────┼─────────────┼─────────────────┤       │
│  │ AIService   │BillingService │ReportService│ LicenseService  │       │
│  └─────────────┴───────────────┴─────────────┴─────────────────┘       │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

         ┌──────────────────┼──────────────────┐
         ▼                  ▼                  ▼
   ┌──────────┐       ┌──────────┐       ┌──────────┐
   │PostgreSQL│       │  Gemini  │       │  Stripe  │
   │  (Neon)  │       │ 2.0 Flash│       │  Billing │
   └──────────┘       └──────────┘       └──────────┘

Data Flow

Sale Creation Flow

1. User taps product in POS


2. CartStore.addItem() - Updates local cart state


3. User selects payment method, taps "Complete"


4. CartStore.checkout() calls api.createSale()


5. POST /api/v1/sales with cart items


6. SaleController validates via Joi schema


7. SaleService.create():
   ├── Verify all products exist
   ├── Check stock availability
   ├── Calculate totals
   ├── Generate receipt number (RCP-YYMMDD-XXXX)
   ├── Create sale + items in transaction
   ├── Deduct stock, create StockLog entries
   └── Increment shop.monthlyTransactions


8. Return sale with items, receipt number


9. CartStore clears, shows receipt modal


10. InventoryStore refreshes products (stock updated)

AI Chat Flow

1. User types question in AI Chat


2. POST /api/v1/ai/chat { message: "what's not selling?" }


3. AIController validates, calls AIService.chat()


4. AIService.getShopContext() gathers:
   ├── Shop info (name, owner, currency)
   ├── Today's sales summary
   ├── Week's sales
   ├── Low stock alerts
   ├── Recent sales
   ├── All products (first 100)
   ├── Slow movers (< 5 sold in 30 days)
   └── Profit margin analysis


5. Build comprehensive system prompt with ALL data


6. Call Gemini 2.0 Flash with context + user message


7. Store conversation in AIConversation table


8. Increment shop.monthlyAiQueries


9. Return AI response with specific product names/numbers

Key Design Decisions

1. Country-First Localization

typescript
// Phone number → Country detection
const PHONE_TO_COUNTRY: [string, string][] = [
  ['+268', 'SZ'],   // Eswatini
  ['+27', 'ZA'],    // South Africa
  ['+254', 'KE'],   // Kenya
  // ... 15+ countries
];

// Registration auto-detects country from phone
const phoneCountry = getCountryFromPhone(input.ownerPhone);
const resolvedCountry = phoneCountry || input.countryCode || 'SZ';

2. Usage-Based AI Limits

All tiers get AI access, but with monthly query limits:

typescript
const AI_TIER_LIMITS = {
  LITE: 100,
  STARTER: 500,
  BUSINESS: 2000,
  PRO: 10000,
  ENTERPRISE: Infinity,
};

3. Receipt Number Format

typescript
// Format: RCP-YYMMDD-XXXX (sequential per day per shop)
const dateStr = today.toISOString().slice(2, 10).replace(/-/g, '');
const receiptNumber = `RCP-${dateStr}-${String(count + 1).padStart(4, '0')}`;
// Example: RCP-260319-0042

4. Multi-Price Products

Products support single items, packs, and wholesale pricing:

typescript
// Pricing hierarchy
sellPrice       // Standard unit price
wholesalePrice  // Bulk discount (if buying ≥ wholesaleMinQty)
packPrice       // Pack price (e.g., 6-pack)
packSize        // Units per pack

Environment Variables

bash
# Database
DATABASE_URL="postgresql://..."

# JWT
JWT_SECRET="your-secret"
JWT_EXPIRES_IN="1d"
JWT_REFRESH_EXPIRES_IN="7d"

# Stripe
STRIPE_MODE="live"  # or "test"
STRIPE_TEST_SECRET_KEY="sk_test_..."
STRIPE_LIVE_SECRET_KEY="sk_live_..."
STRIPE_WEBHOOK_SECRET="whsec_..."

# AI
GEMINI_API_KEY="AIza..."

# License
LICENSE_SECRET="yebomart-license-secret"

Deployment

Backend (Cloud Run)

yaml
# cloudbuild.yaml
steps:
  - name: 'gcr.io/cloud-builders/docker'
    args: ['build', '-t', 'gcr.io/$PROJECT_ID/yebomart-api', '.']
  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'gcr.io/$PROJECT_ID/yebomart-api']
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    args:
      - 'run'
      - 'deploy'
      - 'yebomart-api'
      - '--image=gcr.io/$PROJECT_ID/yebomart-api'
      - '--region=us-central1'
      - '--platform=managed'

Frontend (Cloudflare Pages)

bash
cd app
npm run build
npx wrangler pages deploy dist --project-name=yebomart

One chat. Everything done.