System Architecture
UberLotto v2 is a three-layer system: a PWA client layer, a Shopify Oxygen edge layer, and a multi-provider data layer.
Architecture Diagram
┌─────────────────────────────────────────────────────────────────┐
│ CLIENT LAYER │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ Web Browser │ │ Mobile PWA │ │ Desktop PWA │ │
│ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘ │
└──────────┼──────────────────┼──────────────────┼────────────────┘
└──────────────────┼──────────────────┘
│
┌─────────────────────────────▼───────────────────────────────────┐
│ EDGE LAYER (Cloudflare) │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Shopify Oxygen Runtime │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ Hydrogen SSR Application │ │ │
│ │ │ ┌──────────────┐ ┌──────────┐ ┌──────────┐ │ │ │
│ │ │ │ React Router │ │ Loaders │ │ Actions │ │ │ │
│ │ │ │ (v7) │ │ (Server) │ │ (Server) │ │ │ │
│ │ │ └──────────────┘ └──────────┘ └──────────┘ │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────────┘ │
└────────────┬──────────────┬──────────────┬──────────────┬───────┘
│ │ │ │
▼ ▼ ▼ ▼
┌────────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│ Shopify │ │ Supabase │ │ Plisio │ │ MoonPay │
│ Storefront API │ │ PostgreSQL │ │ Payment API│ │ On-Ramp │
│ (GraphQL) │ │ REST API │ │ Webhooks │ │ Webhooks │
└────────────────┘ └────────────┘ └────────────┘ └────────────┘Client Layer
The application is a Progressive Web App (PWA) that runs across:
- Web Browsers — full desktop experience
- Mobile PWA — installable on iOS/Android
- Desktop PWA — installable on Windows/macOS/Linux
Key capabilities:
| Feature | Implementation |
|---|---|
| Service Worker | Workbox via vite-plugin-pwa — offline caching, runtime caching strategies |
| App Manifest | manifest.webmanifest with icons, shortcuts, screenshots |
| Responsive UI | Tailwind CSS v4 |
| Animations | Motion library |
| State Management | Zustand stores (cart, favorites, sidebar, global state) |
| Install Prompts | Custom PWAProvider component with Safari-specific modal |
Edge Layer (Shopify Oxygen)
The application runs on Shopify's Oxygen platform, which uses Cloudflare Workers.
Runtime characteristics:
- Edge-deployed globally (low latency)
- Serverless, stateless execution
- 50ms CPU time limit per request
- No persistent in-memory storage
Framework stack:
| Component | Role |
|---|---|
| Hydrogen | Shopify's React framework for headless commerce |
| React Router v7 | File-based routing, server loaders/actions, SSR |
| Vite | Build tool, dev server, HMR |
| Mini Oxygen | Local dev emulation of the Oxygen runtime |
Entry Point
The server entry (server.ts) is an Oxygen worker that:
- Creates the Hydrogen context (storefront, customer account, cart, session)
- Passes context to React Router's request handler
- Handles session cookie commits
- Falls back to Shopify storefront redirects on 404s
Data Layer
Shopify Storefront API (GraphQL)
- Product catalog and collections
- Cart management
- Customer accounts and authentication
- Checkout creation
- Shop analytics
Supabase (PostgreSQL)
- Jackpot data (
jackpotstable) - Past drawing results (
past_drawingstable) - Wallet transactions
- Security events and audit logging
- Webhook nonces for replay protection
Plisio API
- Cryptocurrency invoice creation
- Webhook notifications for payment status
- Transaction status polling
MoonPay API
- Fiat-to-crypto on-ramp purchases
- Widget integration via
@moonpay/moonpay-react - Webhook notifications for transaction updates
- HMAC-SHA256 signature verification
Shopify Checkout (Credit Loading)
- "Load Credits" collection with UBL Point products
- Cart creation via Storefront API
cartCreatemutation - Redirect to Shopify checkout for payment processing
- Authenticated endpoint — requires customer login
Key Architectural Decisions
1. Custom Fetch-based Supabase Client
Decision: Use native fetch API instead of @supabase/supabase-js SDK.
Rationale:
- Avoids SSR compatibility issues in the edge runtime
- Smaller bundle size (no SDK overhead)
- Direct control over request/response handling
- Better error handling for edge-specific constraints
Location: app/lib/supabase-client.server.ts
2. Server-Side Security Modules
Decision: All security-critical logic runs server-side only via .server.ts files.
Modules:
| Module | Purpose |
|---|---|
rate-limiter.server.ts | IP and global request rate limiting |
replay-protection.server.ts | Webhook replay attack prevention |
security-logger.server.ts | Security event audit logging to Supabase |
webhook-validator.server.ts | HMAC signature verification |
Rationale: Edge runtime provides isolation; secrets never exposed to client; centralized security logging.
3. Zustand for Client State
Decision: Use Zustand instead of Redux or React Context.
Rationale:
- Minimal boilerplate
- Works well with React 18 concurrent features
- Easy integration with TanStack Query for server state
- Good DevTools support
Stores: useCartLoadingStore, useCartPanelStore, useFavoritesStore, useGlobalStore, useSidebarStore
4. File-Based Routing with i18n Prefix
Decision: Use React Router v7's file-based routing with ($locale). prefix convention.
Rationale:
- Convention over configuration
- Automatic code splitting per route
- Server-side loaders and actions per route
- i18n support via optional locale URL segment
Performance Considerations
Edge Caching Strategy
| Asset Type | Strategy | Cache Duration |
|---|---|---|
| Static images | CacheFirst | 30 days |
| Google Fonts | CacheFirst | 365 days |
| API responses | NetworkFirst | 5 minutes |
| Shopify GraphQL | NetworkFirst | 2 minutes |
Bundle Optimization
- Code Splitting — automatic per route via React Router
- Tree Shaking — enabled via Vite
- Asset Inlining — disabled (
assetsInlineLimit: 0) for strict CSP compliance - SSR Optimization — specific packages pre-bundled for edge compatibility
Security Architecture
Key security layers:
- Network — Supabase network restrictions (Cloudflare IPs only)
- Application — Rate limiting, input validation, CSRF protection
- Data — Row Level Security (RLS) in PostgreSQL
- Webhooks — HMAC signature verification, replay protection, IP allowlisting
Scalability
| Component | Scaling Model |
|---|---|
| Oxygen | Auto-scales based on traffic (Cloudflare Workers) |
| Supabase | Pro plan with connection pooling |
| Plisio | Rate limited by API tier |
| MoonPay | Rate limited by API tier |
Bottlenecks to monitor:
- Supabase connection pool exhaustion
- Webhook processing throughput
- Large GraphQL queries to Shopify Storefront API