← Back to Case Studies

Building a Production-Grade POS Platform in Under 2 Weeks Using AI

A deep technical case study of My Dukan POS

Role

Founder & Lead Engineer

Timeline

~12 days

Status

Production MVP

Stack

Next.js, Supabase, RxDB, PostgreSQL, TypeScript

Executive Summary

My Dukan POS is a production-grade point-of-sale system built specifically for small retail shops in Pakistan. It solves fundamental problems that existing POS systems ignore: unreliable internet, cash-first transactions, customer credit (udhaar), multi-outlet management, and informal workforce structures.

This is not a prototype or demo. It's a real system designed for real shops, with offline-first architecture that guarantees billing continuity regardless of connectivity. The entire platform—from data modeling to deployment—was built in under two weeks.

AI tooling (v0, Codex, ChatGPT) served as a force multiplier for execution speed, but the system design, architectural decisions, and domain modeling came from engineering judgment. AI accelerated the build; it didn't replace the thinking.

The Problem Space

Retail in Pakistan operates under constraints that most POS systems aren't built for:

  • Internet unreliability: Connectivity drops constantly. A POS that requires internet for every transaction is unusable.
  • Cash-first economy: Digital payments exist but cash dominates. The system must handle mixed payment methods seamlessly.
  • Customer credit (udhaar): Shops extend credit to regular customers. This isn't an edge case—it's core business logic.
  • Multi-outlet shops: Many owners run 2-3 shops. They need unified inventory and sales visibility across locations.
  • Informal workforce: Workers are often family or trusted helpers. Role-based access needs to be simple but enforceable.

Typical POS systems fail here because they assume reliable connectivity, card-first payments, and enterprise-grade user management. They're built for a different market.

Product Vision & Principles

Offline-First

Every operation must work without internet. Sync happens in the background when connectivity returns. Users should never see a loading spinner or error due to network state.

Eventual Consistency

Data syncs when possible, but local state is always authoritative for the current session. Conflicts are resolved automatically using timestamp-based ordering.

Local Retail Abstractions

The data model reflects how Pakistani shops actually operate: udhaar, partial payments, outlet-specific inventory, supplier relationships.

Role Separation

Owners see everything. Cashiers see only what they need. This isn't complex RBAC—it's two well-defined permission sets that match real shop hierarchies.

Extensible Data Model

The schema is designed to support future features (purchase orders, expense tracking, reporting) without migrations that break existing data.

Security by Default

Row-level security on every table. No data leaks between businesses. Every query is scoped to the authenticated user's business context.

System Architecture

CLIENTSYNC LAYERBACKENDDATABASENext.js POS UIServer + Client ComponentsRxDB Local StoreIndexedDB / Offline DataSync Engine• products-sync (pull)• sales-sync (push)• checkpointed changesSupabase API SurfaceAuth / PostgREST / RPC / Next API RoutesReal-time SubscriptionsPostgreSQL + RLSTenant IsolationSQL Functions (RPC)Business Logic

Offline-first writes locally, syncs with checkpointed changes, and enforces tenant isolation with Postgres RLS.

Next.js Frontend: Server components for initial render, client components for interactive billing. Optimized for low-end Android devices running in browser.

RxDB Local Database: IndexedDB-backed reactive database. Stores products, sales, and customer data locally. Queries are instant regardless of network state.

Sync Engine: Custom bidirectional sync layer. Pulls product catalog from server, pushes sales data when online. Handles conflict resolution and retry logic.

Supabase Backend: Auth, real-time subscriptions, and PostgreSQL hosting. Provides the server-side source of truth.

PostgreSQL + RLS: All business logic that touches data lives here. Row-level security ensures complete tenant isolation.

Offline-First Design

This is the core differentiator. The system was designed from day one to function without internet.

Why Offline-First Was Mandatory

Pakistani retail internet is unreliable. A shop can't stop billing because the connection dropped. Every competitor that requires connectivity for basic operations fails in this market.

RxDB Implementation

RxDB provides a reactive, offline-capable database that syncs to remote backends. Data is stored in IndexedDB and survives browser restarts.

// Local database setup with RxDB
const db = await createRxDatabase({
  name: 'mydukan',
  storage: getRxStorageDexie(),
});

await db.addCollections({
  products: { schema: productSchema },
  sales: { schema: saleSchema },
  customers: { schema: customerSchema },
});

Local Writes First

Every sale is written to RxDB immediately. The UI updates instantly. Background sync handles server persistence.

// Sale creation - local first
async function createSale(saleData: Sale) {
  // Write to local DB immediately
  await db.sales.insert({
    ...saleData,
    id: generateUUID(),
    syncStatus: 'pending',
    createdAt: Date.now(),
  });
  
  // Queue for background sync
  syncQueue.push({ type: 'sale', data: saleData });
}

Failure-Tolerant Billing

If sync fails, data persists locally and retries automatically. Users are never blocked. The worst case is delayed server-side visibility—never data loss.

Sync Engine & Data Consistency

Separate Product Sync vs Sales Sync

Product catalog syncs down from server (owner controls inventory). Sales sync up from devices (cashiers generate transactions). This separation simplifies conflict handling.

Idempotent Operations

Every sync operation uses unique IDs. Re-syncing the same sale twice doesn't create duplicates. The server checks for existing records before insert.

Status-Based Syncing

Records have a syncStatus field: pending, synced, or failed. The sync engine processes pending records in batches, updates status on success, and retries failures with exponential backoff.

Why This Avoids Data Corruption

No optimistic locking, no merge conflicts. Sales are append-only. Products sync one-way. The data model eliminates the scenarios where conflicts could occur.

Domain-Driven Data Modeling

The schema reflects real retail operations, not generic e-commerce patterns:

Business

Top-level tenant. All data is scoped to a business. Owners can have multiple businesses.

Outlet

Physical shop location. A business can have multiple outlets. Inventory and sales are outlet-specific.

Sale

A transaction. Contains line items, payment breakdown (cash/card/credit), customer reference, and timestamps.

Customer

Optional association for credit tracking. Stores outstanding balance, payment history, and contact info.

Supplier

Product source. Links to products for traceability. Enables future purchase order and cost tracking features.

Worker

Employee with role (owner/cashier) and outlet assignment. Determines permissions and data visibility.

Subscription

Business billing state. Controls feature access and usage limits. Enables future monetization.

Credit (Udhaar) as a First-Class Feature

In Pakistani retail, extending credit to trusted customers is standard practice. This isn't an afterthought—it's built into the core transaction model.

Paid Amount vs Credit Amount

Every sale records both. A ₨1000 purchase might be ₨700 paid and ₨300 on credit. The system tracks both values independently.

Partial Payments

Customers can pay down their credit balance over time. Each payment links to the original sales and reduces the outstanding amount.

Outstanding Balances

Customer records show total credit extended, total paid, and current balance. Owners see this at a glance.

Customer Dashboards

Clear visibility into who owes what. Sortable by amount, date, or customer. No more paper ledgers or mental tracking.

Payments & Settlements

Partial Payments

Any sale can be partially paid. The UI shows remaining balance and accepts additional payments at any time.

Linking Payments to Sales

When a customer pays off credit, the payment links to specific outstanding sales. This maintains a complete audit trail.

Owner-Controlled Settlement

Only owners can mark credit as settled or write off bad debt. Cashiers can record payments but can't modify credit terms.

Auditability

Every payment is timestamped with the user who recorded it. Full history is preserved for dispute resolution.

Customers, Workers & Access Control

Worker Roles

Two roles: owner and cashier. Owners have full access. Cashiers can create sales and view products but can't modify inventory, see reports, or access other outlets.

Outlet Assignment

Workers are assigned to specific outlets. A cashier at Outlet A can't see or affect Outlet B, even within the same business.

Why RLS Is Critical

Row-level security enforces these boundaries at the database level. Even if application code has bugs, the database won't return unauthorized data.

-- RLS policy for sales table
CREATE POLICY "Workers can only see sales from their outlet"
ON sales FOR SELECT
USING (
  outlet_id IN (
    SELECT outlet_id FROM workers 
    WHERE user_id = auth.uid()
  )
);

Suppliers & Inventory Traceability

Supplier Management

Suppliers are tracked with contact info, payment terms, and product associations. This prepares for future purchase order functionality.

Linking Suppliers to Products

Products reference supplier IDs, not names. This enables queries like "show all products from Supplier X" and prevents data duplication.

Future Extensibility

The schema supports adding cost tracking, purchase orders, and supplier payments without restructuring existing tables.

Supabase & Security Architecture

Why Supabase

Managed PostgreSQL with built-in auth, real-time subscriptions, and RLS support. Eliminates infrastructure management overhead while providing enterprise-grade security.

PostgreSQL Over NoSQL

Relational data model matches the domain (businesses → outlets → sales → line items). SQL enables complex reporting queries. ACID guarantees prevent data corruption.

RLS Policies

Every table has row-level security. Users can only access data within their business context. This is enforced at the database level, not application code.

SQL RPCs for Dashboards

Complex aggregations (daily sales, top products, credit outstanding) run as server-side functions. This keeps business logic close to data and reduces client complexity.

AI-Accelerated Development

AI tools accelerated execution. They did not design the system.

v0 for UI Scaffolding

Generated initial component structures, form layouts, and data tables. Saved hours of boilerplate while maintaining full control over final implementation.

Codex for Repetitive Wiring

CRUD operations, API routes, type definitions. The patterns are predictable; AI handles the tedious parts.

ChatGPT for Architecture & Edge Cases

Rubber-ducking complex decisions, exploring RxDB sync strategies, validating RLS policy logic. Useful for thinking through problems, not for generating solutions.

The system architecture, data model, offline-first design, and domain abstractions came from engineering experience—not prompts. AI was a productivity multiplier, not a replacement for judgment.

Timeline & Execution Speed

DayMilestone
1-2Domain modeling, schema design, Supabase setup
3-4RxDB integration, offline-first architecture
5-6Core billing flow, product management
7-8Customer credit system, payment tracking
9-10Sync engine, conflict resolution, RLS policies
11-12Multi-outlet support, worker roles, polish

A project of this scope—offline-first architecture, multi-tenant security, domain-specific features—would typically take 2-3 months with a small team. AI tooling compressed this to under two weeks without sacrificing quality.

Competitive Comparison

FeatureTypical POSMy Dukan POS
Offline SupportLimited or noneFull offline-first
Credit (Udhaar)Not supportedFirst-class feature
Multi-OutletEnterprise tier onlyBuilt-in
Security ModelApplication-levelDatabase RLS
Local Market FitGeneric/WesternPakistan-specific
ExtensibilityVendor-lockedOpen architecture

Final Reflection

My Dukan POS demonstrates that production-grade software can be built rapidly when you combine deep domain understanding with modern tooling. The two-week timeline wasn't about cutting corners—it was about eliminating waste.

This project reflects senior-level system thinking: choosing the right abstractions, designing for real constraints, building security in from the start, and knowing when to leverage AI versus when to rely on engineering judgment.

The approach scales beyond POS. Any domain with offline requirements, multi-tenant data, and complex business rules can benefit from this architecture pattern. The specific implementation is for Pakistani retail; the methodology is universal.

Ship fast, but ship right. AI helps with the former; experience ensures the latter.