The problem
CiCi 21 Chùa Láng is a women's fashion accessories store in Hanoi. Orders already lived in KiotViet, but shifts, attendance, payroll, storage cleaning schedules and cash flow were still run on Excel and paper notebooks. Payroll took several sessions at the end of every month. Items about to run out or mismatched orders were usually only noticed too late.
Spark Store was written to handle exactly those jobs. Once it ran smoothly at CiCi, the system was split into a platform so other stores could share the infrastructure while keeping their own brand and data.

Who uses it, and where
| User | Platform | Main work |
|---|---|---|
| Store owner | Admin web and app | Revenue, profit and loss, cost of goods, payroll, shareholders, store settings, AI assistant |
| Manager | Web and app | Scheduling and approving shifts, stock counts, purchasing, approving attendance |
| Staff | iOS/Android app | Clocking in, signing up for and swapping shifts, viewing pay, selling at the counter, cash counts |
| Customer | Storefront (web) | Browsing products, asking the AI assistant about items and stock, ordering when the store sells online |
| Platform operator | Spark Console | Creating stores, attaching domains, choosing plans, setting branding, viewing logs |
Features
Staff and shifts
- Shift templates and weekly schedules. Staff sign up for shifts themselves; managers approve.
- Shift marketplace: release a shift, pick one up, swap, or "cover part of it" when a colleague is running late.
- Clock-in by face recognition, GPS within the store's radius, or a paired kiosk at the counter. Includes history and a shift audit log.
- Storage cleaning schedules built from templates and copied week to week. Staff mark tasks done, managers approve, and missed tasks incur penalties.
Payroll
- Pay periods close automatically, with penalty policies, holidays and per-person pay settings.
- Staff see their estimated pay right in the app.
Sales
- POS on the web and in the app: several draft orders at once, barcode search, variant selection.
- Staff sell at the listed price. Only managers can change prices, give discounts or edit invoices.
- Sales orders, returns, discount codes, promotions, partner vouchers.
- Dynamic QR payments: the order confirms itself when the bank reports the incoming transfer.
Inventory and purchasing
- Products, units, suppliers, purchase orders, purchase returns, stock counts, damage and internal-use slips.
- Low-stock alerts that only count items currently on sale and below their threshold.
- The owner adjusts stock right in the app, and the adjustment is pushed to KiotViet.
Finance
- Receipts and payments, petty cash, expenses, cash counts per shift.
- Shareholder management, settlements, tax and expense reports.
Communication
- Real-time internal chat, push notifications in the app and via Telegram.
Each store turns modules on or off according to its plan. There are currently 11 feature groups: attendance, scheduling, cleaning, payroll, penalties, POS, inventory, KiotViet sync, chatbot, storefront home page and AI assistant. Beyond the plan, individual features can be enabled for a single store.
The Spark Store app

- The app is written in React Native (Expo, expo-router, NativeWind). One codebase builds two versions: the CiCi app and the Spark Store app shared by the SaaS stores. The Spark Store version is on its way to the App Store.
- Users open the app, enter a store code or link, then sign in with Apple, Google or email. After sign-in, the interface switches to that store's brand colors.
- Sessions are tied to each device and renew automatically for 30 days. Losing the connection does not sign the user out.
- What each person can see depends on their role. Only owners and managers see cost prices. Staff can only open invoices they sold that day. To open the cash count screen, staff must have a shift today and be physically at the store.
- The app is available in English and Vietnamese, with OTA updates via EAS Update.
AI assistant and MCP

- MCP per store. Each store has
/api/mcp(Streamable HTTP) with 176 tools: payroll, shifts, attendance, orders, inventory, POS, cash flow, shareholders, reports. Owners create role-scoped API keys to connect Claude, Cursor or their own agents to the store's real data. - Writes must be confirmed. On the first call, a critical write only describes what it would do. The agent must call again with
confirm: truefor it to run. Every session and call is logged for 90 days. - The in-app assistant is for owners and managers. It is read-only: for each question the system issues a short-lived key with read permissions matching the asker's role, then calls the same MCP tools above. So the assistant has no permissions beyond those of the person asking. Answers stream back to the app over SignalR.
- The storefront assistant answers customers 24/7 about products, stock and store information.
Architecture
- Multi-store. The tenant is resolved from the request's host. A domain that matches no store never returns another store's data. Data is isolated with Row-Level Security in PostgreSQL, and each service uses a least-privilege database role.
- New stores with no manual steps. The backend commits the new store's Ingress to the GitOps repo via the GitHub API. ArgoCD syncs, cert-manager issues TLS, and the store is live at
<code>.store.devbyspark.com. - Central sign-in via
auth.devbyspark.com. One account works across multiple stores and can link one Google, one Apple and one Facebook identity. - Backend: .NET 8, Clean Architecture, CQRS (MediatR). PostgreSQL with pgvector stores face embeddings, MongoDB stores chat messages, plus Redis, Kafka, a YARP gateway and background workers.
- Frontend: Next.js and MUI, real-time over SignalR.
- Face recognition (in internal testing, not yet released): a Face Tracking Service written in Python, running ONNX Runtime on CPU. The pipeline covers face detection (SCRFD), tracking (ByteTrack), anti-spoofing (MiniFASNet) and embedding matching (ArcFace). The service only does AI inference and is kept separate from the attendance business logic.
- Operations: api, fe, gateway and worker run on Kubernetes (K3s) managed by ArgoCD. CI builds images and updates the GitOps repo automatically. The Face Tracking Service has its own GitOps repo and is being trialed in the same cluster.
Results
- CiCi dropped Excel. Shifts, attendance, storage cleaning schedules and payroll for 10+ staff are calculated automatically.
- Low stock and mismatched orders are flagged immediately, without waiting for end-of-day reconciliation.
- The owner has tax and expense reports for shareholders.
- The platform serves 2 brands with 20+ users. Demo store: demo.store.devbyspark.com.
Highlights
Designed and built the entire platform single-handedly: .NET 8 backend, Next.js web, React Native apps, Kubernetes/GitOps infrastructure.
Turned a single-store system into a multi-tenant SaaS. Tenants are resolved by domain and data is isolated with PostgreSQL Row-Level Security. When a new store is created, its Ingress and TLS certificate are provisioned automatically through GitOps.
One React Native codebase ships two apps: the CiCi app and the Spark Store app shared by every store (Apple/Google sign-in, English and Vietnamese).
Attendance by face recognition, GPS geofence and an in-store kiosk. An in-house Face Tracking Service (SCRFD → ByteTrack → MiniFASNet anti-spoofing → ArcFace) is in internal testing to move recognition to the server.
Each store has its own MCP server with 176 business tools. Critical writes must be confirmed before they run, and every call is logged. The in-app AI assistant reuses exactly this permission layer.
Dynamic QR payments are confirmed automatically via ACB bank webhooks, with a fallback channel that reads bank notifications on an Android device (HMAC-signed per device).
Two-way sync with KiotViet: pulls products, orders and stock via API/webhooks; pushes stock adjustments back to KiotViet.