Project Structure
Overview of the UberLotto v2 codebase organization.
Top-Level Directory
uberlotto-v2/
├── app/ # Application source code
│ ├── routes/ # File-based route definitions (68 files)
│ ├── components/ # React components (~97 files)
│ │ ├── ui/ # Shadcn/ui primitives (40 files)
│ │ ├── sections/ # Page section components
│ │ ├── skeletons/ # Loading skeleton components
│ │ ├── shared/ # Shared components
│ │ ├── game-card/ # Game card component variants
│ │ ├── game-detail/ # Game detail page components
│ │ ├── lottery/ # Lottery-specific components
│ │ └── prizes/ # Prize display components
│ ├── lib/ # Core utilities (30 files)
│ ├── store/ # Zustand state stores (8 files)
│ ├── hooks/ # Custom React hooks (13 files)
│ ├── graphql/ # GraphQL queries (3 directories)
│ ├── services/ # Business logic services
│ ├── utils/ # Utility functions (22 files)
│ ├── styles/ # CSS/SCSS stylesheets
│ ├── providers/ # React context providers
│ ├── shared-types/ # Shared TypeScript types
│ └── entry.server.tsx # Server entry for SSR
├── public/ # Static assets (favicons, PWA icons)
├── supabase/ # Database migrations
│ └── migrations/ # SQL migration files
├── types/ # Global TypeScript type declarations
├── server.ts # Oxygen worker entry point
├── vite.config.ts # Vite + Hydrogen + PWA configuration
├── tsconfig.json # TypeScript configuration with path aliases
├── react-router.config.ts # React Router configuration
├── eslint.config.js # ESLint configuration
├── components.json # Shadcn/ui component configuration
├── package.json # Dependencies and scripts
└── env.d.ts # Environment variable type declarationsapp/routes/ — Route Definitions
68 route files using React Router v7 file-based routing with the ($locale). prefix for i18n support.
Naming Convention
Routes follow the pattern ($locale).<path-segments>.tsx:
($locale)._index.tsx → / (homepage)
($locale).collections.$handle.tsx → /collections/:handle
($locale).products.$handle.tsx → /products/:handle
($locale).account._index.tsx → /account
($locale).account.orders.$id.tsx → /account/orders/:id
($locale).pages.game-detail.tsx → /pages/game-detail($locale)— Optional locale prefix (e.g.,/en-US/collections/all)_index— Index route for a parent path$param— Dynamic URL parameter_prefix — Layout/pathless route (e.g.,account_for auth routes)
Route Categories
| Category | Files | Examples |
|---|---|---|
| Pages | 17 | pages.games-schedule, pages.past-drawings, pages.how-to-play |
| Account | 8 | account._index, account.orders, account.profile, account.load-credit |
| API | 10 | api.plisio-webhook, api.moonpay-webhook, api.shopify-checkout |
| Commerce | 5 | products.$handle, collections.$handle, cart, discount.$code |
| Content | 5 | blogs._index, blogs.$blogHandle.$articleHandle, policies.$handle |
| System | 5 | [robots.txt], [sitemap.xml], sitemap.$type.$page[.xml], search |
| Auth | 3 | account_.login, account_.logout, account_.authorize |
API Routes (No UI)
API routes export action and/or loader functions without React components:
api.plisio-invoice.ts # Create Plisio crypto invoice
api.plisio-webhook.ts # Handle Plisio payment webhooks
api.plisio-status.ts # Check Plisio payment status
api.moonpay-sign.ts # Sign MoonPay widget URLs
api.moonpay-webhook.ts # Handle MoonPay payment webhooks
api.shopify-checkout.ts # Create Shopify checkout cart
api.cleanup-pending-transactions.ts # Cron: expire stale transactions
api.wallet-transactions.ts # Wallet transaction queries
api.get-product.$handle.ts # Fetch product by handle
api.get-product-variants.$handle.ts # Fetch product variantsapp/lib/ — Core Utilities
Central library for framework-level utilities and server-side modules.
| File | Purpose |
|---|---|
context.ts | Creates HydrogenRouterContext with storefront, cart, session |
session.ts | Cookie-based session management |
fragments.ts | Shared GraphQL fragments (header, footer, cart) |
i18n.ts | Internationalization locale extraction |
settings.ts | App-wide settings (collection IDs, display config) |
auth.ts | Authentication utilities |
redirect.ts | Redirect helpers |
supabase-client.server.ts | Custom fetch-based Supabase client (server-only) |
supabase-client.ts | Supabase client for non-sensitive operations |
plisio.server.ts | Plisio API integration (server-only) |
rate-limiter.server.ts | IP and global rate limiting |
replay-protection.server.ts | Webhook replay attack prevention |
security-logger.server.ts | Security event logging to Supabase |
security-types.ts | Security event type definitions |
webhook-validator.server.ts | HMAC signature verification |
webhook-extractor.server.ts | Webhook payload extraction |
webhook-processor.server.ts | Webhook processing logic |
webhook-utils.server.ts | Webhook utility functions |
amount-validator.server.ts | Payment amount validation |
shop-limits.server.ts | Shop-level quantity limits |
cart-limits.ts | Cart quantity limits |
mitt.ts | Event emitter (mitt library wrapper) |
favorites-events.ts | Favorites event system |
layout-context.ts | Layout context provider |
root-data.ts | Root loader data utilities |
search.ts | Search utilities |
variants.ts | Product variant utilities |
utils.ts | General utilities (cn() for class merging) |
Server vs Client Convention
Files ending in .server.ts contain server-only code:
// app/lib/supabase-client.server.ts — NEVER imported by client code
// Contains: SUPABASE_SERVICE_ROLE_KEY usage, direct DB operations
// app/lib/supabase-client.ts — Safe for client import
// Contains: Public anon key operations with RLS protectionWARNING
Importing a .server.ts file from client code will cause a build error. This boundary is enforced by the bundler.
app/store/ — Zustand Stores
Client-side state management using Zustand v5.
| Store | Purpose |
|---|---|
useCartLoadingStore.ts | Cart loading/updating state |
useCartPanelStore.ts | Cart panel open/close state |
useFavoritesStore.ts | User's favorite products |
useGlobalStore.ts | Global app state |
useSidebarStore.ts | Sidebar navigation state |
StoreProvider.tsx | Zustand store context provider |
utils.ts | Store utility functions |
app/hooks/ — Custom Hooks
| Hook | Purpose |
|---|---|
useFavorites.ts | Favorites CRUD with Shopify metafields |
useGameCard.ts | Game card data and interactions |
useGameCardModal.ts | Game card modal state |
useInstantCart.ts | Quick add-to-cart functionality |
useLotteryProducts.ts | Lottery product data fetching |
usePlisioPayment.ts | Plisio payment flow management |
usePriceAnimation.ts | Jackpot price animation effects |
usePWA.ts | PWA install prompt and status |
usePWAFallback.ts | PWA fallback for unsupported browsers |
usePWASplashScreen.ts | PWA splash screen management |
useQuickView.ts | Product quick view modal |
useMinimumLoadingTime.ts | Ensures minimum loading indicator display |
use-mobile.ts | Mobile viewport detection |
app/graphql/ — GraphQL Queries
Organized by API source:
graphql/
├── customer-account/ # Customer Account API queries
│ ├── CustomerDetailsQuery.ts
│ ├── CustomerOrderQuery.ts
│ ├── CustomerOrdersQuery.ts
│ ├── CustomerAddressMutations.ts
│ ├── CustomerUpdateMutation.ts
│ └── CustomerFavoritesMutation.ts
├── game-detail/ # Game detail page queries
│ └── GameDetailQuery.ts
└── load-credits/ # Credit loading queries
└── LoadCreditsQuery.tsTIP
Most Storefront API queries are co-located in route files or in app/lib/fragments.ts. The graphql/ directory is for larger, reusable queries that serve specific features.
app/services/ — Business Logic
| Service | Purpose |
|---|---|
lottery-product-enrichment.service.ts | Matches Shopify products to Supabase jackpot data via custom.game_slug metafield. O(1) slug-based lookup, batch enrichment, deduplication. |
app/utils/ — Utility Functions
| File | Purpose |
|---|---|
jackpot.server.ts | Fetch jackpot data from Supabase by slug |
pastDrawings.server.ts | Fetch past drawing results from Supabase |
shopify-checkout.server.ts | Checkout cart creation utilities |
validation.server.ts | Server-side input validation |
calculateNextDrawing.ts | Next drawing date calculation |
formatJackpotValue.ts | Jackpot amount formatting |
priceCalculations.ts | Price and discount calculations |
game-card.ts | Game card display utilities |
game-logo-mapping.ts | Game logo asset mapping |
logo-resolver.ts | Dynamic logo resolution |
gameOfTheDay.ts | "Game of the Day" selection logic |
games.ts | Game data utilities |
prize-utils.ts | Prize tier display utilities |
cart/ | Cart-related utility functions |
countries.ts | Country data for address forms |
data.ts | Static data constants |
dummyData.ts | Development placeholder data |
browser-detection.ts | Browser/device detection |
pwa-helpers.ts | PWA utility functions |
getUserInitials.ts | User initials from name |
debug.ts | Development debugging helpers |
app/components/ — Component Categories
UI Primitives (components/ui/)
40 Shadcn/ui components configured via components.json (New York style, Lucide icons):
accordion, badge, button, calendar, card, checkbox, dialog, drawer, dropdown-menu, input, pagination, popover, select, separator, sheet, sidebar, skeleton, slider, switch, table, tabs, textarea, toast, tooltip, and more.
Feature Components
| Component | Purpose |
|---|---|
GameCard.tsx | Lottery game card with jackpot display |
GamePay.tsx | Payment page for game purchases |
MoonPayCheckout.tsx | MoonPay widget integration |
PlisioPaymentModal.tsx | Plisio payment modal |
LoadCreditPopup.tsx | Credit loading amount selector |
LoadCreditActions.tsx | Credit loading action buttons |
Cart.tsx, CartMain.tsx, CartSummary.tsx | Shopping cart |
Favorites.tsx, FavoritesButton.tsx | Favorites system |
Header.tsx, Footer.tsx, Sidebar.tsx | Layout components |
InstallPrompt.tsx, PWAProvider.tsx | PWA install experience |
TransactionHistory.tsx | Transaction history display |
Search.tsx, SearchResults.tsx | Search functionality |
supabase/migrations/ — Database Migrations
SQL migration files for Supabase schema changes. These are applied in order during deployment. See the Database documentation for table schemas.