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.