Frontend Architecture
Aero2's frontend is a single-page application (SPA) built with React 19 and Vite, served by the Cloudflare Worker.
Tech Stack
| Technology | Purpose |
|---|---|
| React 19 | UI framework |
| Vite | Build tool and dev server |
| React Router | Client-side routing |
| CSS Modules | Component styling |
| React Context | State management (AuthContext) |
Phase 1 Approach: Single SPA with Context-Based Routing
In the current architecture, a single build serves both the developer dashboard and per-app auth pages. The Worker passes an appContext object to the SPA that determines which layout and routes to render.
App Context
The Worker injects the app context into the HTML page:
// appContext passed from Worker to SPA
interface AppContext {
mode: "dashboard" | "app";
app: {
slug: string;
name: string;
branding: {
logo_url?: string;
favicon_url?: string;
primary_color?: string;
};
};
}mode: "dashboard"-- The current hostname is the dashboard subdomain. Render the full developer console with sidebar navigation, app management, team settings, etc.mode: "app"-- The current hostname is an application subdomain. Render branded auth pages (login, signup, MFA) using the app's branding configuration.
Dashboard Layout
When mode === "dashboard", the SPA renders the developer console:
- Sidebar navigation: Apps, Team, Account
- App list page: Cards showing name, slug, user count, creation date
-
App management pages:
- Overview (user count, login activity, quick links)
- Users (browse/search, view profiles, disable/enable)
- Auth Methods (toggle email/password, social providers, MFA policy)
- Identity Providers (add/edit/remove IdPs)
- Branding (logo upload, color picker, login page preview)
- API Keys (list, create, revoke, rotate)
- Roles and Permissions (configure role system)
- Organizations (view orgs and members)
- Audit Logs (app-scoped event log)
- Settings (signup mode, session TTL, domain restrictions)
- Team management: Invite members, manage roles, transfer app ownership
- Account: Developer profile, change password, MFA setup
Dashboard Routes
dashboard.aero2.dev/
/login -> Developer sign-in
/signup -> Developer sign-up
/ -> Application list (after login)
/teams -> Developer Team management
/apps/:slug/overview -> App overview
/apps/:slug/users -> App user management
/apps/:slug/auth -> Auth method configuration
/apps/:slug/idps -> Identity provider management
/apps/:slug/branding -> Login page customization
/apps/:slug/api-keys -> API key management
/apps/:slug/roles -> Roles and permissions
/apps/:slug/organizations -> Organization management
/apps/:slug/logs -> Audit logs
/apps/:slug/settings -> App settings
/account -> Developer profile
/account/team -> Team membersApp Layout
When mode === "app", the SPA renders branded auth pages for end users:
- Login form (email/password + social IdP buttons)
- Signup form with email verification
- MFA verification page
- Password reset flow
- OAuth2 authorization consent
Per-App Routes
swift-maple.aero2.dev/
/login -> End-user sign-in (branded)
/signup -> End-user sign-up
/mfa -> MFA verification
/forgot-password -> Password reset
/oauth2/authorize -> OAuth2 authorization endpoint
/oauth2/token -> Token endpoint
/oauth2/userinfo -> UserInfo endpoint
/oauth2/jwks.json -> JWKS endpoint
/.well-known/openid-config.. -> OIDC discovery
/api/users/me -> Current user profile
/api/sessions -> Session management
/api/organizations -> Org management (if enabled)Component Library
Reusable UI components live in src/frontend/components/ui/:
- Button -- Primary, secondary, danger, ghost variants with loading state
- Card -- Container with header, body, footer sections
- Input -- Text, email, password inputs with validation states
- Modal -- Dialog overlay with confirm/cancel actions
- Spinner -- Loading indicator
- Toast -- Notification system (success, error, warning, info)
- Table -- Data table with sorting and pagination
- Badge -- Status indicator labels
- Dropdown -- Menu and select dropdowns
State Management
State is managed through React Context:
- AuthContext -- Provides
user,isAuthenticated,isLoading,signOut(), and session information to all components - No external state management library (Redux, Zustand, etc.) -- React Context is sufficient for the current scope
Routing
React Router handles client-side navigation. The Worker serves the SPA HTML for all non-API routes, and React Router matches the path client-side.
Phase 2 (Future): Split Builds
A planned future optimization is to produce two separate builds:
dist/dashboard/-- Full developer console bundle (larger, feature-rich)dist/auth/-- Lightweight auth page bundle (smaller, loads branding dynamically)
The Worker would serve the appropriate bundle based on subdomain. The auth bundle would be significantly smaller since it only needs login, signup, and MFA components.