MoveFast uses the Next.js App Router with a clean separation between frontend pages, API routes, and backend services. This page explains how everything fits together.
Folder Structure
src/
├── app/ # Next.js App Router (pages + API routes)
│ ├── (main)/ # Public pages (landing, pricing, blog, auth, etc.)
│ ├── admin/ # Admin dashboard (protected)
│ ├── api/ # API route handlers
│ └── layout.tsx # Root layout with providers
├── components/ # React components
│ ├── admin/ # Admin-specific components
│ ├── auth/ # Auth components (sign-in modal, forms)
│ ├── landing/ # Landing page sections
│ ├── ui/ # shadcn/ui primitives (button, card, dialog, etc.)
│ └── ... # Feature-specific components
├── config/ # App configuration
│ ├── pricing.config.ts # Pricing plans, currency, payment model
│ └── platform.config.ts # Platform access mode (open vs invite-only)
├── constants/ # Static values
│ ├── env.ts # All environment variable names
│ ├── routes.ts # Route path constants
│ ├── website.ts # Brand name, URLs, support email
│ └── statusCode.ts # HTTP status code constants
├── context/ # React context providers
│ └── AppContext.tsx # Global user state + auth helpers
├── hooks/ # Custom React hooks
│ ├── useCheckout.ts # Payment checkout logic
│ ├── useSubscription.ts # Subscription management
│ ├── useUserProfile.ts # Profile CRUD
│ └── ...
├── lib/ # Core logic
│ ├── auth.ts # NextAuth configuration
│ ├── auth/ # Auth utilities (page-auth, api-auth)
│ ├── backend/ # Backend services (see below)
│ ├── email/ # Email client + providers
│ ├── seo/ # Metadata helpers
│ ├── axios.ts # Axios HTTP client
│ └── types/ # TypeScript type definitions
├── types/ # Additional type definitions
└── utils/ # Utility functions
├── errorHandling/ # ApiError, error handlers
├── pricing.ts # Pricing display utilities
└── ...Backend Services Architecture
The src/lib/backend/ folder uses a layered pattern:
src/lib/backend/
├── auth/
│ ├── services/ # Business logic
│ │ ├── magicLink.service.ts
│ │ ├── platformAccess.service.ts
│ │ └── impersonation.service.ts
│ ├── repo/ # Data access (factory + implementations)
│ │ ├── magicLink.repository.ts # Interface + factory
│ │ ├── mongo.magicLink.repository.ts
│ │ └── supabase.magicLink.repository.ts
│ └── adapters/ # Data mapping between DB and app types
├── user/
│ ├── services/
│ ├── repo/
│ └── adapters/
├── payment/
│ ├── services/
│ ├── repo/
│ └── adapters/
├── subscription/
│ ├── services/
│ ├── repo/
│ └── adapters/
├── waitingList/
│ ├── services/
│ ├── repo/
│ └── adapters/
├── invite/
│ ├── services/
│ ├── repo/
│ └── adapters/
├── payment-providers/
│ ├── providers/ # Stripe, Dodo, Polar implementations
│ └── adapters/ # Webhook event adapters
└── webhooks/
└── webhook-coordinator.service.tsThe Repository Pattern
Every domain (user, payment, subscription, etc.) follows the same structure:
- Interface defines what operations are available (e.g.,
IUserRepository) - Factory function picks the right implementation based on your variant
- Implementations handle the actual database calls (Mongo or Supabase)
- Adapters transform database records into app-level types
// repo/user.repository.ts (factory)
export const createUserRepository = (): IUserRepository => {
return new MongoUserRepository(); // or SupabaseUserRepository in supabase variants
};In single-provider variants, the factory is compiled to return only the selected implementation. No runtime switching happens.
How a Request Flows
Here is a typical API request flow:
Client (React)
→ axios call to /api/payment/checkout
→ API route handler (src/app/api/payment/checkout/route.ts)
→ withAuth() middleware checks authentication + roles
→ validateBody() validates request with Zod schema
→ paymentService.initiateOneTimePayment() (business logic)
→ createPaymentProvider() factory returns Stripe/Dodo/Polar
→ provider.createOneTimePayment() calls external API
→ handleControllerResponse() returns standardized JSONAPI Response Format
All API routes return a consistent shape:
{
"success": true,
"payload": { ... },
"message": "Optional success message"
}On errors:
{
"success": false,
"error": "Error message",
"code": "OPTIONAL_ERROR_CODE"
}Authentication Layers
MoveFast has two auth utilities depending on context:
checkAuth()(insrc/lib/auth/page-auth.ts) is for Server Components and pages. It redirects users if they lack access.withAuth()(insrc/lib/auth/api-auth.ts) is for API routes. It returns 401/403 JSON responses if access is denied.
Both support: PUBLIC, AUTHENTICATED, role-based ({ roles: [UserRole.ADMIN] }), and custom predicate functions.
Error Handling
MoveFast uses a centralized error system:
ApiErroris a custom error class with HTTP status code and optional error codehandleControllerError()catches errors in route handlers and returns proper HTTP responseshandleInternalServerError()is used inside services. It re-throwsApiErrorinstances and wraps unexpected errors.
Validation
All API request bodies are validated with Zod schemas before reaching business logic:
const validatedData = await validateBody(req, CreateCheckoutSchema);Schemas live in src/lib/zod-schemas/.
Key Configuration Files
| File | What it controls |
|---|---|
src/config/pricing.config.ts | Plans, prices, currency, payment model |
src/config/platform.config.ts | Access mode (open vs invite-only) |
src/constants/website.ts | Brand name, support email, social URLs |
src/constants/env.ts | All environment variable names |
src/constants/routes.ts | Frontend route paths |
src/lib/api-routes.ts | API endpoint paths for the axios client |
