MyanTop - Comprehensive Technical Documentation
This document provides a detailed, single-source-of-truth technical overview of the MyanTop Automated Mobile Top-up System. It covers system architecture, database design, automation engine details, REST APIs, administration features, and local development setup.
1. Project Overview
MyanTop is a production-grade, highly secure mobile top-up automation platform built on Next.js 15 and native Supabase (PostgreSQL). The system utilizes a direct REST API for provider interaction and QR code generation while providing users with a comprehensive wallet transaction system and administrators with granular dashboard control.
Core System Features
- Secure Authentication: Integrated Supabase SSR authentication supporting Passwordless OTP and Google OAuth.
- Wallet Balance Management: Localized digital wallets enabling customers to hold funds in MMK, request deposits, make top-up purchases, and receive automatic refunds on failed processing runs.
- Synchronous Direct-to-Memory Processing: Processes checkouts and payments inline synchronously, providing blistering-fast responses and minimal infrastructure overhead.
- Direct REST API (High Performance): Processes checkout transactions and fetches payment QR codes using a fast, lightweight API client directly interacting with MyEzTopup core backend endpoints synchronously and serverless-compatibly.
- Myanmar Phone Number Intelligence & Formatting: Dynamic UI formatter that formats numbers as "09 - XXXX - XXXX" automatically. It includes real-time auto-detection of carrier prefixes (MPT, Ooredoo, Atom, Mytel).
- Brand Asset Overlay: Modernized carrier inputs that dynamically overlay brand logos (
Atom.webp,MPT.webp,Mytel.webp,U9.webp) depending on the auto-detected mobile carrier prefix. - Dual-Language UI (i18n): Fully internationalized frontend supporting English (
en) and Myanmar (my) translations powered bynext-intldynamic routing. Includes new interactive About Us and Support (FAQ + ticket submission) pages. Runtime errors resolved by adding complete pagination keys (previous,next,showingPage). - Dual-Method Checkout Options:
- MMQR Direct: Customers pay via auto-generated MMQR codes scanned in banking apps. Includes a dynamic, real-time 5-minute expiration countdown that enforces session validity and automatically disables payment capabilities upon timeout.
- MyanTop Wallet: Logged-in customers pay instantly from their pre-funded account. UI includes real-time balance lookup, overdraft protection, and direct balance funding shortcuts.
- Note: The Payment Method selector features a premium, glassmorphic layout with radial backdrop glows, standard Lucide icons, and state-driven visual indicators.
- Atomic Transactions & Idempotency: All financial balance mutations (payments, approvals, and refunds) are executed at the database-engine level using native PostgreSQL Stored Procedures (RPCs) to prevent double-spending and race conditions. Strict idempotency key constraints are enforced to prevent double-charging during concurrent requests.
- Granular Admin Control & Order Recovery: Dual-purpose dashboard structure featuring order management at
/adminand wallet deposit approvals at/admin/deposits. Features a hardened, synchronous Order Recovery architecture with robust error handling for upstream gateway outages. - Observability & Analytics: Integrated Sentry for real-time error tracking and performance monitoring, alongside PostHog for comprehensive user behavior analytics.
- Fail-Safe Admin Alerts: Immediate alert notifications dispatched via the Telegram Bot API on critical checkout API failures.
- Order Deletion Policies: Admin-only privilege to delete completed or failed records to maintain a clean database index.
2. Architecture & Data Flow
MyanTop orchestrates a clean separation between client-side interactions, server routes, synchronous API automation, and database persistence.
🔄 MMQR-Based Order Creation & Confirmation Flow (Synchronous Direct Execution)
sequenceDiagram
actor User as Client Browser
participant API as Next.js API Routes
participant DB as Supabase DB
participant MyEzAPI as core.myeztopup.com
%% Phase 1
User->>User: Select MPT & Enter Phone (Auto-carrier detected)
User->>API: POST /api/order {phone, provider, amount, paymentMethod: 'MMQR'}
activate API
API->>MyEzAPI: POST /api/v1/payment/topup/create (Auth Bearer JWT)
MyEzAPI-->>API: Return paymentQrCode payload string
API->>API: Draw base64 QR code Data URL (node-qrcode in-memory)
API->>DB: Save QR Code in DB via save_qr_code_secure
API-->>User: HTTP 201 Created (with waiting_payment & base64 QR URL)
deactivate API
User->>User: Scans QR & Pays via KBZPay / WavePay
User->>API: POST /api/order/[id]/confirm
activate API
API->>MyEzAPI: GET /api/v1/products & POST /api/v1/checkout/direct (Wallet checkout + PIN)
MyEzAPI-->>API: Return transaction success
API->>DB: Update order to 'completed'
API-->>User: HTTP 200 Order Completed Successfully
deactivate API
💰 Wallet-Based Instant Happy Path (Synchronous Direct Execution)
sequenceDiagram
actor User as Client Browser
participant API as Next.js API Routes
participant DB as Supabase DB
participant MyEzAPI as core.myeztopup.com
User->>User: Select Provider & paymentMethod: 'wallet'
User->>API: POST /api/order {phone, provider, amount, paymentMethod: 'wallet'}
activate API
API->>DB: Atomic decrement wallet balance (RPC)
alt Balance Overdraft
DB-->>API: Exception: Insufficient Balance
API-->>User: HTTP 402 Insufficient Balance
else Balance Deducted Successfully
API->>MyEzAPI: GET /api/v1/products & POST /api/v1/checkout/direct (Wallet checkout + PIN)
MyEzAPI-->>API: Return transaction success
API->>DB: Update order to 'completed'
API-->>User: HTTP 201 Created (Order Completed Instantly)
end
deactivate API
3. Database Schema (Supabase & PostgreSQL)
The database layers are fully managed natively within Supabase PostgreSQL. Strongly-typed definitions are maintained in types/supabase.ts.
📋 Database Tables
1. User
Stores system accounts, handles profile metadata, and maintains roles.
id:UUID(Primary Key, maps toauth.users.idvia Foreign Key)name:text | null- User's full name or screen nameemail:text | null- Authenticated email addressemailVerified:timestamptz | null- Timestamp when email verifiedphoneNumber:text | null- User primary phone numberimage:text | null- Avatar URLrole:Enums["Role"]- Account privileges:"USER"or"ADMIN"createdAt:timestamptz- Account creation timestampupdatedAt:timestamptz- Account update timestamp
2. Wallet
Maintains the monetary balances for each user.
id:UUID(Primary Key)userId:UUID(Foreign Key ->User.id, unique1:1constraint)balance:numeric/float8- Current liquid cash in MMK (defaults to0)
3. Transaction
Logs all historical modifications to wallet balances for auditing.
id:UUID(Primary Key, defaults to random UUID)userId:UUID(Foreign Key ->User.id)amount:numeric/float8- Mutated value (always absolute positive)type:Enums["TransactionType"]-"deposit" | "payment" | "refund"status:Enums["TransactionStatus"]-"pending" | "completed" | "failed"orderId:UUID | null(Foreign Key ->Order.id) - Associated order reference (for payments and refunds)phoneNumber:text | null- Reference phone number of KBZPay/WavePay account used for manual transfersmethod:text | null- Selected payment channel (e.g."KBZPay","WavePay")createdAt:timestamptz- Transaction timestamp
4. Order
Maintains the execution state of REST API checks and merchant payments.
id:UUID(Primary Key, defaults to random UUID)userId:UUID(Foreign Key ->User.id)phoneNumber:text- The target mobile number receiving top-up creditsprovider:text- Telecom company (e.g.MPT,Ooredoo,Atom,Mytel)amount:numeric/float8- Desired top-up amount in MMKpaymentMethod:text- Selected payment route:"MMQR"or"wallet"providerOrderId:text | null- Remote provider's unique transaction identifierstatus:Enums["OrderStatus"]- Lifecycle execution code (see below)qrCode:text | null- Base64 Data URL string containing the generated provider checkout QR code imagecreatedAt:timestamptz- Order submission timestamp
5. SystemConfig
Stores centralized, persistent key-value configuration like API authentication tokens and catalog caches.
id:text(Primary Key) - String identifier (e.g.,myeztopup_auth,myeztopup_catalog)value:jsonb- Configuration payloadupdatedAt:timestamptz- Last modification timestamp
📂 Database Enums
OrderStatus
Governs order stages and client dashboard tracking.
pending: Order received; initiating top-up QR code generation.processing: Transaction is currently being processed by the merchant API.waiting_payment: MMQR code generated and waiting for client scan/payment.paid: Client verified scanning and clicking "I have paid".completed: Top-up successfully completed and completed via merchant API.failed: Explicit manual cancel, timeout, or merchant provider transaction issue.
Role
USER: Standard customer; wallet limits apply.ADMIN: Elevated administrator; grants access to dashboard and action controls.
TransactionType
deposit: Increment requested via external payment.payment: Deducted value corresponding to a top-up checkout.refund: Automatic balance return following a failed checkout automation.
TransactionStatus
pending: Awaiting admin verify or bank deposit verification.completed: Funds successfully deposited, paid, or returned.failed: Rejected or errored transfer.
⚡ Stored Procedures & RPC Functions
To guarantee transaction isolation and prevent double-spending, balance changes are handled natively inside PostgreSQL database procedures:
increment_wallet_balance(p_amount: numeric, p_user_id: UUID)- SQL Definition:
UPDATE "Wallet" SET balance = balance + p_amount WHERE "userId" = p_user_id; - Usage: Applied on admin deposit approval and automated order failure refunds.
- SQL Definition:
decrement_wallet_balance(p_amount: numeric, p_user_id: UUID)- SQL Definition:
UPDATE "Wallet" SET balance = balance - p_amount WHERE "userId" = p_user_id; - Usage: Triggered inside a single operation block upon submitting a valid
pendingorder. Throws DB exceptions on overdraft.
- SQL Definition:
approve_deposit_secure(p_transaction_id: text)[UPDATED]- Usage: Validates caller permissions via
is_admin()orservice_role. Directly credits theWalletbalance and sets the originalTransactionstatus tocompletedin a single query, preventing duplicate transaction logs. - Note: Wallet-related RPCs (
approve_deposit_secure,add_wallet_balance_secure,deduct_wallet_balance_secure) were recently refactored to remove the legacyp_system_secretparameter, relying strictly on native PostgreSQL roles (authenticated) andis_admin()checks.
- Usage: Validates caller permissions via
is_admin()[SECURITY CLEANUP]- Usage: Securely validates whether the caller holds administrative privileges. To protect database access, direct execution of
is_admin()is revoked from standardPUBLIC,anon, andauthenticatedroles, but is explicitly granted toservice_role,authenticated, andanonto allow internal evaluation of row-level security (RLS) policies without exposing direct API query endpoints.
- Usage: Securely validates whether the caller holds administrative privileges. To protect database access, direct execution of
refund_wallet_order_secure(p_order_id: text, p_system_secret: text)[NEW]- Usage: Secured via SHA-256 nextauth system secret passcode. Securely processes a refund for a failed order by returning the paid amount to the user's wallet and creating a refund transaction record.
save_qr_code_secure(p_order_id: text, p_qr_code: text, p_system_secret: text)[NEW]- Usage: Secured via SHA-256 nextauth system secret passcode. Securely stores the in-memory base64 QR code Data URL and updates the order status to
waiting_paymentin a single transactional operation.
- Usage: Secured via SHA-256 nextauth system secret passcode. Securely stores the in-memory base64 QR code Data URL and updates the order status to
4. System API Endpoints (REST API Reference)
All requests and responses utilize standard JSON payloads. Protected endpoints verify authorization through cookies.
👤 Client-Facing API Endpoints
POST /api/order
Creates a top-up order and initiates direct, synchronous REST API execution.
- Authentication: Required (Supabase session)
- Request Body:
{ "phoneNumber": "09971234567", "provider": "Ooredoo", "amount": 10000, "paymentMethod": "MMQR" // or "wallet" } - Responses:
201 Created:{"orderId": "uuid", "status": "waiting_payment", "qrCode": "data:image/png;base64,...", "message": "Order created successfully."}402 Payment Required:{"error": "Failed to create order. Insufficient balance"}400 Bad Request: Validation failure.
GET /api/order/[id]
Used by clients to poll/view order state.
- Authentication: Required
- Response (
200 OK):{ "id": "uuid", "phoneNumber": "09971234567", "provider": "Ooredoo", "amount": 10000, "paymentMethod": "MMQR", "status": "waiting_payment", "qrCode": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...", "createdAt": "2026-05-17T14:16:55.000Z" }
POST /api/order/[id]/confirm
Clients invoke this to verify they scanned the provider QR and sent the top-up payment.
- Authentication: Required
- Response (
200 OK):
Updates database status to{ "orderId": "uuid", "message": "Payment confirmed and top-up processed successfully." }completedupon successful inline checkout API call.
GET /api/wallet
Retrieves a customer's liquid balance and chronological wallet transactions.
- Authentication: Required
- Response (
200 OK):{ "wallet": { "id": "uuid", "userId": "uuid", "balance": 25000 }, "transactions": [ { "id": "uuid", "amount": 10000, "type": "payment", "status": "completed", "orderId": "uuid", "createdAt": "...", "order": { "provider": "Ooredoo", "phoneNumber": "09971234567" } } ] }
POST /api/wallet/deposit
Submits a deposit cash transfer request for admin checking.
- Authentication: Required
- Request Body:
{ "amount": 50000 } - Response (
201 Created):{ "id": "uuid", "userId": "uuid", "amount": 50000, "type": "deposit", "status": "pending", "createdAt": "..." }
🛡️ Administrator-Facing API Endpoints
All admin routes require verification via the isAdminAuthenticated utility, validating an HTTP-Only secure SHA-256 session cookie matching ADMIN_PASSWORD.
GET /api/order
Lists all submitted orders.
- Authentication: Admin Required
- Query Parameters:
status(Optional filter) - Response (
200 OK): Array ofOrderrecords.
PATCH /api/order/[id]
Allows admins to override statuses, bypass automation blocks, or mark checkouts complete.
- Authentication: Admin Required
- Request Body:
{ "status": "completed" } - Response (
200 OK): UpdatedOrderobject.
DELETE /api/order/[id]
Deletes an order record. Allowed only for terminal states (completed, failed).
- Authentication: Admin Required
- Response (
200 OK):{"success": true}
5. Automation Engine & Direct REST API Integration
The entire top-up lifecycle has been migrated from legacy asynchronous Puppeteer browser workers to 100% synchronous direct API integration, communicating with core.myeztopup.com using standard, lightweight REST requests.
Key System Components
myeztopup-api-client.ts: Manages secure token authentication, automated JWT cookie/token refreshes, and structured HTTPS clients. Uses a Supabase-backed persistent cache (SystemConfig) to share tokens and product catalogs across serverless functions, preventing race conditions and hitting rate limits.myeztopup-api-service.ts: Implements the main API-driven service logic:- Stage 1 (
generateQRCode): Posts order parameters directly to the merchant backend, receives the raw payment QR code string, draws the MMQR code usingnode-qrcodeinside an in-memory canvas, converts it to a base64 Data URL, and writes it directly to the database via secure stored procedures. - Stage 2 (
completeWalletTopup): Queries product categories (cached centrally) to match desired provider and amount, resolves the exact target product ID, and executes a direct checkout using the secure PIN wallet transaction endpoint. ReturnsproviderOrderIdfrom upstream upon success.
- Stage 1 (
myeztopup.types.ts: Houses strongly typed definitions for direct API requests, catalog products, categorizations, and transaction response structures.
Direct API Safety & Error Handling
- Synchronous Execution: Eliminates complex PostgreSQL queue locking and state tracking. Errors are returned inline to clients, avoiding duplicate state drifts or hanging worker threads.
- Atomic Transactions: Balance checking and debiting happen inside atomic DB procedures, ensuring that if subsequent Stage 1 or Stage 2 checkout actions fail, wallet funds are rolled back cleanly and securely.
6. Environment Variables (.env)
Configure these settings inside the root .env file of your workspace:
| Variable | Description | Requirement / Default |
| :--- | :--- | :--- |
| NEXT_PUBLIC_SUPABASE_URL | Endpoint URL of your Supabase project | Required |
| NEXT_PUBLIC_SUPABASE_ANON_KEY | Supabase Client Anonymous API Access key | Required |
| SUPABASE_SERVICE_ROLE_KEY | Highly privileged DB key bypasses RLS policies | Required |
| NEXTAUTH_SECRET | System-wide secret token used for secure RPCs | Required |
| ADMIN_PASSWORD | Password used for /admin panel access | Default: admin123 |
| MYEZTOPUP_EMAIL | Merchant provider login email address | Required |
| MYEZTOPUP_PASSWORD | Merchant provider login account password | Required |
| MYEZTOPUP_API_BASE_URL | Base endpoint URL for the direct merchant platform REST API | Default: https://core.myeztopup.com |
| MYEZTOPUP_PIN | Secure checkout PIN used to authenticate direct API checkout transactions | Required |
| TELEGRAM_BOT_TOKEN | API Token generated by BotFather | Optional |
| TELEGRAM_CHAT_ID | Telegram Chat/Channel ID receiving failure reports | Optional |
7. Logging & Diagnostics
Event Tracing
API route actions, system errors, and transaction outcomes are logged to help monitor direct REST operations.
- Output Channel: Standard console streams (e.g., Vercel / server stdout).
- Exceptions: Critical failures (e.g., wallet authentication token expiration or invalid PIN codes) dispatch direct notifications when configured.
System Health Service
Crucial connectivity diagnostics are implemented inside services/health/health.service.ts. This executes lightweight queries (select id from User limit 1) to verify API-to-Supabase round-trips, responding with:
status:"ok"message:"Service is running"database:"Supabase connected"
8. Development & Commands
Initial System Setup
- Dependencies: Execute
npm installin your workspace. - Credentials: Create a
.envfile copied from.env.examplecontaining active Supabase credentials and provider passwords. - Database Migration: Run RPC triggers, tables, and enum definitions in your Supabase DB dashboard (e.g.
supabase/migrations/). - Local Server: Run
npm run devto start Next.js. No separate background worker process is required!
Reference Scripts
npm run dev: Starts the Next.js App Router local development server.npm run build: Bundles compiling assets for production execution (fully compatible with serverless/read-only runtimes like Vercel).npm run lint: Performs static analysis and ESLint code checks.npx tsx scripts/test-api-direct.ts: Runs manual transaction verification tests directly against the REST endpoints.
9. Coding Conventions
- TypeScript Verification: Strict compilation rules apply. Ensure types for database rows (
UserRow,OrderRow,WalletRow,TransactionRow) are fully verified. - Imports: Always use path aliases
@/for imports (e.g.@/components/navbaror@/services/wallet/...). - Atomic Balance Calculations: Under no circumstances should balance addition/subtraction occur client-side. Always leverage
increment_wallet_balanceanddecrement_wallet_balanceSupabase RPC procedures. - Controller Safety: Keep REST route files highly modular. Business decisions, direct API checkout drivers, and database queries must stay contained inside
services/.