Skip to content

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.

typescript
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:

  1. Check phone uniqueness
  2. Hash password (bcrypt, 12 rounds)
  3. Detect country from phone prefix
  4. Create shop with localized settings
  5. Generate JWT tokens
  6. Return shop + tokens
typescript
// 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:

  1. Normalize phone to E.164 (handles local format like 7612 3456)
  2. Find shop by phone
  3. Verify password with bcrypt
  4. Generate JWT tokens
  5. Return shop + tokens

loginUser(phone: string, pin: string)

Staff login with phone and 4-digit PIN.

Logic:

  1. Normalize phone
  2. Find user by phone
  3. Verify PIN (stored as plain 4-digit string)
  4. Update lastLoginAt
  5. Store refresh token
  6. 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)

typescript
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:

  1. Check barcode uniqueness within shop
  2. Create product
  3. If quantity > 0, create initial StockLog

list(params: ListProductsParams)

typescript
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:

typescript
{
  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)

typescript
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):

  1. Fetch all products
  2. Verify stock availability
  3. Calculate item totals and order total
  4. Validate payment ≥ total
  5. Generate receipt number
  6. Create Sale + SaleItems
  7. Deduct stock, create StockLogs
  8. Increment monthlyTransactions
typescript
// Receipt number format
const receiptNumber = `RCP-${dateStr}-${String(count + 1).padStart(4, '0')}`;
// Example: RCP-260319-0015

list(params: ListSalesParams)

typescript
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):

  1. Find completed sale
  2. Update status to VOIDED, set voidReason
  3. Restore stock for all items
  4. Create StockLogs (type: RETURN)

getDailySummary(shopId: string, date?: Date)

typescript
// 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)

typescript
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:

  1. Get current product quantity
  2. Calculate new quantity (validate ≥ 0)
  3. Update product quantity
  4. Create StockLog with previousQty and newQty
  5. Increment monthlyStockMoves

receive(input: ReceiveStockInput)

Bulk restock multiple products at once.

typescript
interface ReceiveStockInput {
  shopId: string;
  userId?: string;
  items: {
    productId: string;
    quantity: number;
    note?: string;
  }[];
  reference?: string; // Supplier name, PO number
}

getLowStockAlerts(shopId: string)

typescript
// 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:

typescript
{
  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:

  1. Gather comprehensive shop context
  2. Build system prompt with ALL business data
  3. Call Gemini 2.0 Flash
  4. Store conversation
  5. Increment monthlyAiQueries

Context gathered:

typescript
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:

typescript
{
  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.

typescript
{
  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:

typescript
{
  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:

typescript
{
  range: { startDate, endDate };
  products: [
    { id, name, category, quantitySold, revenue, cost, profit, margin, avgPrice }
  ];
  categories: [
    { name, revenue, quantity }
  ];
}

getStaffReport(shopId, dateRange)

Staff performance metrics:

typescript
{
  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:

typescript
{
  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:

typescript
{
  shopId: string;
  shopEmail?: string;
  countryCode: string;
  tier: ShopTier;
  successUrl: string;
  cancelUrl: string;
}

Logic:

  1. Get country pricing
  2. Convert to Stripe-supported currency if needed
  3. Create Checkout Session
  4. 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)

typescript
// 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:

typescript
['basic_pos', 'stock_tracking', 'basic_reports', 'ai_assistant', ...]

hasFeature(tier, feature)

Check if tier includes a feature.

getStatus(shopId)

Get license status with usage:

typescript
{
  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

typescript
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 back
  • EXCHANGE — Swap for different product
  • STORE_CREDIT — Credit to customer account

SupplierService

Vendor management.

Methods

create(input) — Add supplier

list(shopId) — List suppliers

getById(supplierId, shopId)

update(supplierId, shopId, data)

linkProduct(supplierId, productId, pricing) — Associate product with supplier

getPurchaseOrders(shopId) — List POs

createPurchaseOrder(input) — Create new PO

One chat. Everything done.