Directory Structure
Understanding the generated project layout is essential for navigating and extending your FORGE application. Every directory and file serves a specific purpose, and the structure is consistent across all generated projects.
Top-Level Overview
When you run forge new --name=myapp, FORGE generates the following structure:
myapp/
├── apps/
│ ├── api/ # Rust (Axum) backend
│ ├── web/ # Next.js public website
│ └── admin/ # Next.js admin dashboard
├── database/
│ ├── migrations/ # Versioned SQL migrations
│ └── seeders/ # Default data seeders
├── infra/
│ ├── docker/ # Docker Compose and Dockerfiles
│ ├── caddy/ # Caddyfile for reverse proxy
│ └── certs/ # Local SSL certificates
├── forge.yaml # Project configuration
├── .env # Environment variables (not committed)
├── .env.example # Environment template (committed)
└── .gitignore # Git ignore rulesEach top-level directory maps to a distinct concern:
| Directory | Purpose |
|---|---|
apps/ | Application source code — one subdirectory per service |
database/ | Database migrations and seed data |
infra/ | Infrastructure configuration (Docker, Caddy, SSL) |
forge.yaml | FORGE project manifest (Configuration) |
API Application (apps/api/)
The Rust backend is a fully structured Axum application with clear separation of concerns:
apps/api/
├── Cargo.toml # Rust dependencies
├── Cargo.lock # Locked dependency versions
├── .env # API environment variables
├── src/
│ ├── main.rs # Application entry point
│ ├── config/
│ │ ├── mod.rs # Config module
│ │ ├── app.rs # App configuration (name, port, env)
│ │ ├── database.rs # Database connection config
│ │ └── auth.rs # JWT and auth config
│ ├── models/
│ │ ├── mod.rs # Model re-exports
│ │ ├── user.rs # User model (struct + queries)
│ │ ├── role.rs # Role model with permissions
│ │ ├── permission.rs # Permission model
│ │ ├── content.rs # CMS content pages
│ │ ├── menu.rs # Navigation menus
│ │ ├── media.rs # Media/file uploads
│ │ ├── lookup.rs # Lookup/reference tables
│ │ └── audit_log.rs # Audit trail entries
│ ├── handlers/
│ │ ├── mod.rs # Handler re-exports
│ │ ├── auth.rs # Login, register, password reset
│ │ ├── profile.rs # User profile (self)
│ │ ├── contents.rs # Public content by slug
│ │ ├── menus.rs # Public menu retrieval
│ │ ├── lookups.rs # Public lookup data
│ │ └── admin/
│ │ ├── mod.rs # Admin handler re-exports
│ │ ├── users.rs # User CRUD
│ │ ├── roles.rs # Role CRUD
│ │ ├── permissions.rs # Permission listing
│ │ ├── contents.rs # Content CRUD
│ │ ├── menus.rs # Menu CRUD
│ │ ├── media.rs # Media upload/management
│ │ ├── lookups.rs # Lookup CRUD
│ │ ├── settings.rs # Application settings
│ │ └── audit_logs.rs # Audit log viewing
│ ├── services/
│ │ ├── mod.rs # Service re-exports
│ │ ├── auth.rs # Authentication logic
│ │ ├── content.rs # Content business logic
│ │ ├── menu.rs # Menu business logic
│ │ ├── media.rs # File handling and processing
│ │ └── lookup.rs # Lookup table logic
│ ├── dto/
│ │ ├── mod.rs # DTO re-exports
│ │ ├── common.rs # Shared types (pagination, responses)
│ │ ├── auth.rs # Auth request/response types
│ │ ├── user.rs # User DTOs
│ │ ├── role.rs # Role DTOs
│ │ ├── content.rs # Content DTOs
│ │ ├── menu.rs # Menu DTOs
│ │ └── lookup.rs # Lookup DTOs
│ ├── middleware/
│ │ ├── mod.rs # Middleware re-exports
│ │ ├── auth.rs # JWT token extraction and validation
│ │ ├── rbac.rs # Permission-based access control
│ │ └── request_id.rs # Request ID injection
│ ├── routes/
│ │ ├── mod.rs # Route registration (public + admin)
│ │ ├── auth.rs # Auth route group
│ │ ├── public.rs # Public API routes
│ │ └── admin.rs # Admin API routes (protected)
│ ├── docs/
│ │ └── mod.rs # OpenAPI spec generation (utoipa)
│ └── utils/
│ ├── mod.rs # Utility re-exports
│ ├── response.rs # Standardized JSON responses
│ ├── pagination.rs # Pagination helpers
│ └── validation.rs # Input validation helpers
├── migrations/ # SQL migration files
│ ├── 00001_create_users_table.sql
│ ├── 00002_create_roles_table.sql
│ ├── 00003_create_permissions_table.sql
│ ├── 00004_create_role_permissions_table.sql
│ ├── ...
│ ├── 00014_create_contents_table.sql
│ ├── 00015_create_menus_table.sql
│ └── 00017_create_lookups_table.sql
└── seeders/ # SQL seed files
├── 01_roles.sql
├── 02_permissions.sql
├── 03_users.sql
├── 04_role_permissions.sql
├── 05_user_roles.sql
└── 06_translations.sqlLayered architecture
The backend follows a clear request lifecycle: Routes define endpoints, Middleware enforces auth and permissions, Handlers parse requests and return responses, Services contain business logic, Models interact with the database, and DTOs define the shapes of data crossing boundaries.
Key Files
| File | Purpose |
|---|---|
main.rs | Bootstraps the Axum server, connects to the database and Redis, registers all routes |
config/*.rs | Reads environment variables and forge.yaml into typed configuration structs |
middleware/auth.rs | Extracts and validates JWT tokens from the Authorization header |
middleware/rbac.rs | Checks the authenticated user's permissions against the required permission for the route |
docs/mod.rs | Generates the OpenAPI specification served at /docs |
Web Application (apps/web/)
The public-facing Next.js application with App Router:
apps/web/
├── package.json
├── next.config.js
├── tailwind.config.ts
├── tsconfig.json
├── .env.local # Frontend environment variables
├── public/ # Static assets
│ ├── favicon.ico
│ └── images/
├── app/
│ ├── layout.tsx # Root layout (HTML, fonts, providers)
│ ├── page.tsx # Home page
│ ├── [slug]/
│ │ └── page.tsx # Dynamic content pages (CMS)
│ ├── (auth)/
│ │ ├── login/
│ │ │ └── page.tsx # Login page
│ │ ├── register/
│ │ │ └── page.tsx # Registration page
│ │ └── forgot-password/
│ │ └── page.tsx # Password reset
│ └── (protected)/
│ ├── layout.tsx # Auth-guarded layout
│ └── profile/
│ └── page.tsx # User profile page
├── components/
│ ├── ui/ # shadcn/ui primitives
│ │ ├── button.tsx
│ │ ├── input.tsx
│ │ ├── card.tsx
│ │ └── ...
│ ├── providers/
│ │ ├── query-provider.tsx # TanStack Query provider
│ │ └── i18n-provider.tsx # Internationalization provider
│ ├── site-header.tsx # Site header with navigation
│ ├── site-footer.tsx # Site footer
│ ├── dynamic-nav.tsx # Dynamic navigation from menus API
│ └── language-switcher.tsx # Language/locale switcher
└── lib/
├── api.ts # API client (fetch wrapper)
├── auth.ts # Auth utilities (token management)
├── types.ts # TypeScript type definitions
└── utils.ts # Shared utility functionsRoute Groups
The web application uses Next.js Route Groups to organize pages:
| Group | Path | Purpose |
|---|---|---|
(auth) | /login, /register, /forgot-password | Authentication pages — redirect if already logged in |
(protected) | /profile | Requires authentication — redirects to login if not authenticated |
[slug] | /:slug | Dynamic CMS pages — fetches content by slug from the API |
Admin Application (apps/admin/)
The admin dashboard is a separate Next.js application with full CRUD interfaces:
apps/admin/
├── package.json
├── next.config.js
├── tailwind.config.ts
├── tsconfig.json
├── .env.local
├── app/
│ ├── layout.tsx # Root layout
│ ├── (auth)/
│ │ └── login/
│ │ └── page.tsx # Admin login page
│ └── (dashboard)/
│ ├── layout.tsx # Dashboard layout (sidebar + header)
│ ├── page.tsx # Dashboard home (stats overview)
│ ├── users/
│ │ ├── page.tsx # User list (paginated, searchable)
│ │ ├── create/
│ │ │ └── page.tsx # Create user form
│ │ └── [id]/
│ │ ├── page.tsx # View user details
│ │ └── edit/
│ │ └── page.tsx # Edit user form
│ ├── roles/
│ │ ├── page.tsx # Role list
│ │ ├── create/
│ │ │ └── page.tsx # Create role with permissions
│ │ └── [id]/
│ │ └── edit/
│ │ └── page.tsx # Edit role
│ ├── contents/
│ │ ├── page.tsx # Content page list
│ │ ├── create/
│ │ │ └── page.tsx # Rich text content editor
│ │ └── [id]/
│ │ ├── page.tsx # View content
│ │ └── edit/
│ │ └── page.tsx # Edit content
│ ├── menus/
│ │ ├── page.tsx # Menu list
│ │ ├── create/
│ │ │ └── page.tsx # Create menu with items
│ │ └── [id]/
│ │ └── edit/
│ │ └── page.tsx # Edit menu
│ ├── lookups/
│ │ ├── page.tsx # Lookup table list
│ │ └── [id]/
│ │ └── page.tsx # Lookup entries
│ ├── media/
│ │ └── page.tsx # Media library
│ ├── settings/
│ │ └── page.tsx # Application settings
│ └── audit-logs/
│ └── page.tsx # Audit trail viewer
├── components/
│ ├── ui/ # shadcn/ui components
│ ├── layout/
│ │ ├── sidebar.tsx # Collapsible navigation sidebar
│ │ ├── header.tsx # Top header with user menu
│ │ └── breadcrumbs.tsx # Dynamic breadcrumb navigation
│ ├── providers/
│ │ ├── query-provider.tsx
│ │ └── i18n-provider.tsx
│ ├── data-table.tsx # Reusable data table component
│ ├── rich-text-editor.tsx # Content editor (TipTap)
│ └── media-picker.tsx # Media selection dialog
└── lib/
├── api.ts # Admin API client
├── auth.ts # Admin auth utilities
├── types.ts # Admin TypeScript types
└── utils.ts # Admin utilitiesAdmin follows CRUD conventions
Every resource in the admin panel follows the same pattern: list -> create -> view -> edit. This consistency makes the admin codebase predictable and easy to extend when adding new features.
Infrastructure (infra/)
Infrastructure configuration for local development and deployment:
infra/
├── docker/
│ ├── docker-compose.yml # Service definitions (PostgreSQL, Redis, Caddy)
│ ├── docker-compose.dev.yml # Development overrides
│ ├── docker-compose.prod.yml # Production overrides
│ ├── Dockerfile.api # Multi-stage Rust build
│ ├── Dockerfile.web # Next.js web build
│ └── Dockerfile.admin # Next.js admin build
├── caddy/
│ └── Caddyfile # Reverse proxy + HTTPS configuration
└── certs/
├── myapp.test.pem # SSL certificate (generated by mkcert)
└── myapp.test-key.pem # SSL private keyCaddy Configuration
The Caddyfile routes requests to the correct application:
myapp.test {
reverse_proxy localhost:3001 # → Next.js web app
tls /etc/caddy/certs/myapp.test.pem /etc/caddy/certs/myapp.test-key.pem
}
admin.myapp.test {
reverse_proxy localhost:3002 # → Next.js admin app
tls /etc/caddy/certs/myapp.test.pem /etc/caddy/certs/myapp.test-key.pem
}
api.myapp.test {
reverse_proxy localhost:3000 # → Rust API server
tls /etc/caddy/certs/myapp.test.pem /etc/caddy/certs/myapp.test-key.pem
}Database (database/)
Database management files that live outside the API application for visibility:
database/
├── migrations/ # Ordered SQL migration files
│ ├── 00001_create_users_table.sql
│ ├── 00002_create_roles_table.sql
│ ├── 00003_create_permissions_table.sql
│ ├── 00004_create_role_permissions_table.sql
│ ├── 00005_create_user_roles_table.sql
│ ├── 00006_create_settings_table.sql
│ ├── 00007_create_audit_logs_table.sql
│ ├── 00008_create_api_keys_table.sql
│ ├── 00009_create_password_resets_table.sql
│ ├── 00010_create_refresh_tokens_table.sql
│ ├── 00011_create_media_table.sql
│ ├── 00012_create_translations_table.sql
│ ├── 00013_create_notifications_table.sql
│ ├── 00014_create_contents_table.sql
│ ├── 00015_create_menus_table.sql
│ └── 00017_create_lookups_table.sql
└── seeders/
├── 01_roles.sql # Default roles (Super Admin, Admin, User)
├── 02_permissions.sql # All system permissions
├── 03_users.sql # Default admin user
├── 04_role_permissions.sql # Role-permission assignments
├── 05_user_roles.sql # Admin user role assignment
└── 06_translations.sql # Default UI translationsMigration ordering matters
Migrations are executed in numerical order. FORGE uses zero-padded five-digit prefixes (e.g., 00001, 00002) to ensure correct ordering. When adding custom migrations, use the next available number or run forge make:migration to auto-assign.
The forge.yaml File
The project manifest at the root of your project. This file is read by the FORGE CLI for all operations — code generation, migrations, provider configuration, and deployment. See the Configuration page for a complete reference.
Next Steps
Now that you understand the project layout, dive deeper into specific areas:
- Backend Overview — Learn how the Rust API is structured and how to extend it
- Frontend Overview — Explore the Next.js applications in detail
- Contract-First Design — Understand the architecture that makes FORGE extensible
- Template System — Learn how Tera templates generate your project