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/numbersKey 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-00424. 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 packEnvironment 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=yebomartRelated Docs
- Services Deep Dive — All service methods and logic
- Routes Reference — Complete API route map
- Data Models — Full Prisma schema with relations
- Middleware — Auth, validation, rate limiting
- Billing — Stripe integration and pricing
- Frontend — App pages and components
- Admin Dashboard — Admin interface