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
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
| Day | Milestone |
|---|---|
| 1-2 | Domain modeling, schema design, Supabase setup |
| 3-4 | RxDB integration, offline-first architecture |
| 5-6 | Core billing flow, product management |
| 7-8 | Customer credit system, payment tracking |
| 9-10 | Sync engine, conflict resolution, RLS policies |
| 11-12 | Multi-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
| Feature | Typical POS | My Dukan POS |
|---|---|---|
| Offline Support | Limited or none | Full offline-first |
| Credit (Udhaar) | Not supported | First-class feature |
| Multi-Outlet | Enterprise tier only | Built-in |
| Security Model | Application-level | Database RLS |
| Local Market Fit | Generic/Western | Pakistan-specific |
| Extensibility | Vendor-locked | Open 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.