YeboMart Services — Deep Dive
Complete reference for all backend services with methods, parameters, and business logic.
AuthService
Handles user registration, authentication, and session management.
Methods
registerShop(input: RegisterShopInput)
Creates a new shop with owner account.
interface RegisterShopInput {
name: string;
ownerName: string;
ownerPhone: string; // E.164 format (+268...)
ownerEmail?: string;
password: string;
assistantName?: string; // Default: "Yebo"
businessType?: string; // Default: "general"
countryCode?: string; // Auto-detected from phone
}Logic:
- Check phone uniqueness
- Hash password (bcrypt, 12 rounds)
- Detect country from phone prefix
- Create shop with localized settings
- Generate JWT tokens
- Return shop + tokens
// Country detection
const PHONE_TO_COUNTRY = [
['+268', 'SZ'], // Eswatini
['+27', 'ZA'], // South Africa
['+254', 'KE'], // Kenya
// ... 15+ countries
];loginShop(phone: string, password: string)
Owner login with phone and password.
Logic:
- Normalize phone to E.164 (handles local format like
7612 3456) - Find shop by phone
- Verify password with bcrypt
- Generate JWT tokens
- Return shop + tokens
loginUser(phone: string, pin: string)
Staff login with phone and 4-digit PIN.
Logic:
- Normalize phone
- Find user by phone
- Verify PIN (stored as plain 4-digit string)
- Update lastLoginAt
- Store refresh token
- Return shop + user + tokens
refreshToken(refreshToken: string)
Refresh access token using refresh token.
getMe(userId: string, type: 'shop' | 'user' | 'admin')
Get current authenticated user/shop details.
ProductService
CRUD and bulk operations for products.
Methods
create(input: CreateProductInput)
interface CreateProductInput {
shopId: string;
barcode?: string;
sku?: string;
name: string;
description?: string;
category?: string;
costPrice: number;
sellPrice: number;
quantity?: number; // Default: 0
reorderAt?: number; // Default: 10
unit?: string; // Default: "each"
imageUrl?: string;
localId?: string; // For offline sync
}Logic:
- Check barcode uniqueness within shop
- Create product
- If quantity > 0, create initial StockLog
list(params: ListProductsParams)
interface ListProductsParams {
shopId: string;
page?: number;
limit?: number;
search?: string; // Search name, barcode, SKU
category?: string;
lowStock?: boolean; // Filter to low stock only
isActive?: boolean;
}getById(productId: string, shopId: string)
getByBarcode(barcode: string, shopId: string)
update(productId: string, shopId: string, data: UpdateProductInput)
delete(productId: string, shopId: string) — Soft delete
bulkImport(shopId, products[], updateExisting)
Import multiple products from CSV or JSON.
Returns:
{
created: number;
updated: number;
skipped: number;
errors: { row: number; error: string }[];
}bulkUpdate(shopId, updates[])
Update prices/quantities for multiple products by ID or barcode.
exportCSV(shopId: string)
Export all active products as CSV string.
getCategories(shopId: string)
Get distinct categories for the shop.
SaleService
Handles transactions, receipts, and sale management.
Methods
create(input: CreateSaleInput)
interface CreateSaleInput {
shopId: string;
userId?: string; // Cashier
items: {
productId: string;
quantity: number;
discount?: number;
}[];
paymentMethod: 'CASH' | 'MOMO' | 'EMALI' | 'CARD' | 'MIXED' | 'CREDIT';
amountPaid: number;
discount?: number; // Order-level discount
localId?: string; // For offline sync
offlineAt?: Date;
}Logic (in transaction):
- Fetch all products
- Verify stock availability
- Calculate item totals and order total
- Validate payment ≥ total
- Generate receipt number
- Create Sale + SaleItems
- Deduct stock, create StockLogs
- Increment monthlyTransactions
// Receipt number format
const receiptNumber = `RCP-${dateStr}-${String(count + 1).padStart(4, '0')}`;
// Example: RCP-260319-0015list(params: ListSalesParams)
interface ListSalesParams {
shopId: string;
page?: number;
limit?: number;
status?: 'PENDING' | 'COMPLETED' | 'VOIDED' | 'REFUNDED';
paymentMethod?: PaymentMethod;
startDate?: Date;
endDate?: Date;
userId?: string;
}getById(saleId: string, shopId: string)
getByReceiptNumber(receiptNumber: string, shopId: string)
Supports partial match (e.g., "0015" finds "RCP-260319-0015").
voidSale(saleId, shopId, userId, reason)
Logic (in transaction):
- Find completed sale
- Update status to VOIDED, set voidReason
- Restore stock for all items
- Create StockLogs (type: RETURN)
getDailySummary(shopId: string, date?: Date)
// Returns
{
date: Date;
totalSales: number;
totalTransactions: number;
averageBasket: number;
totalDiscount: number;
totalCost: number;
grossProfit: number;
byPaymentMethod: { method, total, count }[];
topProducts: { id, name, quantity, revenue }[];
}StockService
Inventory management and tracking.
Methods
adjust(input: AdjustStockInput)
interface AdjustStockInput {
shopId: string;
productId: string;
userId?: string;
type: 'RESTOCK' | 'ADJUSTMENT' | 'DAMAGED' | 'EXPIRED' | 'TRANSFER' | 'INITIAL';
quantity: number; // Positive to add, negative to remove
note?: string;
reference?: string; // PO number, sale ID, etc.
}Logic:
- Get current product quantity
- Calculate new quantity (validate ≥ 0)
- Update product quantity
- Create StockLog with previousQty and newQty
- Increment monthlyStockMoves
receive(input: ReceiveStockInput)
Bulk restock multiple products at once.
interface ReceiveStockInput {
shopId: string;
userId?: string;
items: {
productId: string;
quantity: number;
note?: string;
}[];
reference?: string; // Supplier name, PO number
}getLowStockAlerts(shopId: string)
// Returns categorized alerts
{
total: number;
critical: number; // quantity === 0
low: number; // 0 < quantity <= reorderAt/2
warning: number; // reorderAt/2 < quantity <= reorderAt
items: {
critical: Product[];
low: Product[];
warning: Product[];
}
}getMovements(params: ListMovementsParams)
Query stock movement history with filters.
getStockLevels(shopId: string)
Get all products with stock summary:
{
products: Product[];
summary: {
totalProducts: number;
totalCostValue: number; // Sum of (costPrice * quantity)
totalSellValue: number; // Sum of (sellPrice * quantity)
potentialProfit: number; // sellValue - costValue
}
}AIService
AI-powered business insights using Google Gemini.
Methods
chat(input: { shopId, message })
Main conversational AI endpoint.
Logic:
- Gather comprehensive shop context
- Build system prompt with ALL business data
- Call Gemini 2.0 Flash
- Store conversation
- Increment monthlyAiQueries
Context gathered:
const context = {
shop: { name, ownerName, assistantName, currency },
todaySales: { totalSales, transactions, topProducts },
weekSales: { total, count },
lowStockAlerts: { critical, low, warning },
recentSales: [...last 10 sales with items...],
allProducts: [...first 100 products...],
slowMovers: [...products with <5 sales in 30 days...],
lowMarginProducts: [...margin < 15%...],
highMarginProducts: [...margin >= 30%...],
timeContext: { hour, period, isWeekend }
};System prompt includes:
- Shop name, owner, currency
- Today's and week's sales figures
- Top sellers with quantities
- Slow movers with stock value tied up
- Low/high margin products
- Low stock alerts
- Recent sales list
- Inventory snapshot
voice(shopId: string, transcription: string)
Process voice query (transcribed text from frontend).
generateInsights(input: { shopId })
Generate 3-5 actionable business insights.
Output:
{
insights: [
{
title: "🚨 Stock Emergency!",
insight: "3 products are OUT OF STOCK...",
action: "Reorder Bread immediately",
priority: "high"
},
// ... more insights
],
generated: Date,
offline?: boolean
}getSlowMovers(shopId: string)
Dedicated slow-moving products analysis.
{
slowMovers: [
{ name, quantity, sellPrice, soldLast30Days, stockValue }
],
totalStockValue: number,
recommendations: [
{ product, suggestion, potentialRecovery }
]
}getBusinessSummary(shopId: string)
Quick status overview with urgent actions.
ReportService
Business analytics and reporting.
Methods
getDailyReport(shopId, date?)
Comprehensive daily report:
{
date: Date;
summary: {
totalSales, totalTransactions, averageBasket,
totalCost, grossProfit, totalExpenses, netProfit
};
paymentBreakdown: { cash, momo, emali, card };
topProducts: [...];
lowStock: [...];
staffPerformance: [...];
}getWeeklyReport(shopId, weekStart?)
Aggregated weekly data with daily breakdown.
getProductReport(shopId, dateRange)
Product performance analysis:
{
range: { startDate, endDate };
products: [
{ id, name, category, quantitySold, revenue, cost, profit, margin, avgPrice }
];
categories: [
{ name, revenue, quantity }
];
}getStaffReport(shopId, dateRange)
Staff performance metrics:
{
staff: [
{ id, name, role, totalSales, transactionCount, averageTransaction, voidCount }
]
}generateDailyReport(shopId, date)
Generate and store daily report in DailyReport table.
BillingService
Stripe integration for subscription billing.
Methods
getPlans(countryCode: string)
Get pricing plans for a country:
{
country: "Eswatini",
countryCode: "SZ",
currency: "SZL",
currencySymbol: "E",
discountLabel: "Launch Special",
discountPercent: 80,
plans: [
{ tier: "LITE", name: "Lite", price: 499, discountPrice: 99, activePrice: 99 },
// ...
]
}createCheckout(opts)
Create Stripe Checkout session:
{
shopId: string;
shopEmail?: string;
countryCode: string;
tier: ShopTier;
successUrl: string;
cancelUrl: string;
}Logic:
- Get country pricing
- Convert to Stripe-supported currency if needed
- Create Checkout Session
- Return session URL
handleWebhookEvent(payload, signature)
Process Stripe webhook:
checkout.session.completed→ Update shop tier and license expiry
LicenseService
Subscription tier management and feature gating.
Methods
getTierLimits(tier: ShopTier)
// LITE tier limits
{
maxProducts: 100,
maxUsers: 1,
maxTransactions: 500,
maxStockMoves: 100,
aiQueriesPerMonth: 100,
aiModel: 'flash-lite',
whatsappReports: false,
advancedAnalytics: false
}getTierFeatures(tier: ShopTier)
Returns array of feature strings:
['basic_pos', 'stock_tracking', 'basic_reports', 'ai_assistant', ...]hasFeature(tier, feature)
Check if tier includes a feature.
getStatus(shopId)
Get license status with usage:
{
tier: "STARTER",
isActive: true,
isExpired: false,
expiresAt: Date,
daysRemaining: 25,
usage: { products: 45, users: 2, monthlyTransactions: 150, monthlyStockMoves: 30 },
limits: { maxProducts: 500, ... },
features: ['basic_pos', 'barcode_scanning', ...]
}generateLicenseKey(data)
validateLicenseKey(licenseKey)
validateAndApply(shopId, licenseKey)
createTrialLicense(shopId) — 30-day PRO trial
ShopService
Shop configuration and usage tracking.
Methods
incrementUsage(shopId, type: 'transaction' | 'stockMove')
Increment monthly counters.
resetMonthlyUsage(shopId)
Reset counters at month start.
getStats(shopId)
Get shop statistics overview.
CustomerService
Credit customer management.
Methods
create(input) — Create credit customer
list(shopId) — List customers
getById(customerId, shopId)
update(customerId, shopId, data)
addCredit(customerId, data) — Record credit transaction
interface AddCreditInput {
type: 'PURCHASE' | 'PAYMENT' | 'ADJUSTMENT' | 'REFUND';
amount: number;
saleId?: string;
note?: string;
}ReturnService
Refunds and exchanges.
Methods
create(input) — Create return request
process(returnId, action, data) — Approve/reject/complete
Return types:
REFUND— Money backEXCHANGE— Swap for different productSTORE_CREDIT— Credit to customer account
SupplierService
Vendor management.