Directory structure
What every file of a new Navree app is for, where generated code goes, and how the framework's own repository is laid out.
On this page
A Navree app is an ordinary Cargo package. navree new gives it a conventional layout: the app root module in src/app.rs, one directory per feature module under src/modules/, settings in config/ and .env, and runtime data in storage/. Nothing in the framework depends on these paths except the configuration files and a few defaults (the maintenance file in storage/, templates in resources/views/), all relative to the working directory; the generators expect the layout, though, and keeping to it makes apps look alike.
A new application
This is what navree new planner writes:
- .envlocal settings and secrets (git-ignored)
- .env.examplethe keys .env needs, committed
- .gitignore
- Cargo.tomlthe package; depends on navree
- README.md
- config/
- app.tomlsettings shared by every environment
- src/
- main.rsthe binary: runs the app with the default config sources
- lib.rsexposes app(), abilities and modules
- app.rsthe root module: every module, configured once
- abilities.rswhat each user may do
- modules/
- mod.rsdeclares the feature modules
- users/an example feature module
- mod.rs
- controller.rs
- service.rs
- entity.rs
- dto.rs
- migrations/
- mod.rs
- m20261026_081033_create_user_profiles_table.rs
- tests/
- mod.rs
- storage/
- .gitignoreignores everything else in storage/
- tests/
- app.rsboots the whole app
The root directory
Cargo.tomlnames the package and its dependencies:navree, plusserde,sea-orm,sea-orm-migrationandgarde, whose derive macros name their own crates, andchrono,uuidandserde_json. It ends with an empty[workspace]table, so the app is a workspace of its own; remove it to make the app a member of an enclosing workspace. The[profile.dev]settings keep debug builds quick to link and compile Argon2 with optimisations, which keeps password hashing bearable in development..envholds this machine's settings and secrets, such asAPP_KEY.navree newcreates it from.env.example, and git ignores it. See Configuration..env.examplelists the keys.envneeds, without secrets. Commit it.config/app.tomlholds the settings every environment shares: the listening address, the database URL, the log level, the mail transport and so on.README.mdlists the everyday commands.
src/
main.rsis the binary. It callsplanner::app(ConfigSources::defaults()).run(), which runs the command on the command line:servewhen there is none, ormigrate,queue:workand the rest. A deployed app needs only this binary and its configuration.lib.rsexposesapp,abilitiesandmodules, so tests intests/can boot exactly whatmainboots.app.rsis the root module. It adds every module the app uses, each configured once:ConfigModule,LoggerModule,CryptoModule,HttpModule,DatabaseModule,CacheModule,EventsModule,ViewModule,MailModule,QueueModule,ValidationModule,AuthModule,AccessModule,ApiModule,ObserveModule, then the feature modules. Remove the platform modules you don't need, and add the others (ScheduleModule,StorageModule,RealtimeModule,NotifyModule,AuditModule, ...) when you do.abilities.rsis the function that builds each user's access rules. It grants the permissions of the user's roles, then the rules of each module's policy. See Authorization.modules/holds the feature modules, one directory each.
Feature modules
A feature module keeps everything about one feature together. navree make:module creates one with this shape:
| File | What it holds |
|---|---|
mod.rs | The module struct and its #[module(...)] declaration: imports, providers, controllers, exports, and a wire method for registrations the attribute has no key for, such as migrations |
controller.rs | The controller: HTTP routes with their access attributes |
service.rs | The business logic, as an injectable service |
entity.rs | The SeaORM entity of the module's table |
dto.rs | Request and response bodies, with validation rules |
migrations/ | The module's migration set; each module owns its tables |
tests/ | Tests that boot the module alone on a fresh database |
The example users module serves GET and PUT /api/v1/profile, a profile for each signed-in user. Accounts themselves come from AuthModule, which owns the users table and the /api/auth/* routes. Keep users as a model or delete it, along with its line in app.rs and modules/mod.rs and the profile test in tests/app.rs.
The make:<kind> generators add files in a directory per kind, inside the module:
| Command | Writes |
|---|---|
navree make:controller tasks admin | controllers/admin.rs |
navree make:service tasks pricing | services/pricing.rs |
navree make:entity tasks draft | entities/draft.rs |
navree make:migration tasks add_due_date | migrations/m<timestamp>_add_due_date.rs |
navree make:job tasks send_digest | jobs/send_digest.rs |
navree make:event tasks task_completed | events/task_completed.rs |
navree make:listener tasks notify_owner --event task_completed | listeners/notify_owner.rs |
navree make:mail tasks digest | mail/digest.rs, mail/digest.html, mail/digest.txt |
navree make:notification tasks task_due | notifications/task_due.rs |
navree make:policy tasks task | policies/task.rs |
navree make:command tasks prune_done | commands/prune_done.rs |
navree make:test tasks completing | tests/completing.rs |
Every generator also declares the new file's module and, where the item must be registered, adds the registration. Console commands and the CLI covers each one.
Generator markers
The generators never overwrite a file. To register what they create, they edit existing files only at marker comments:
| Marker | In | What the generators add above it |
|---|---|---|
// navree:modules | src/app.rs | .module(...) for each new feature module |
// navree:wire | each module's mod.rs | registrations of controllers, services, jobs, listeners, mail templates, commands and new migration sets |
// navree:policies | src/abilities.rs | the call to each new policy |
Leave the markers in place. If one is missing, the generator prints the line to add by hand, prefixed with next.
storage/
storage/ holds data the app writes at runtime, and its .gitignore keeps it out of git:
- the SQLite database,
storage/<app>.dbby default, with its-waland-shmfiles; storage/framework/down, which exists while the app is in maintenance mode;- log files and local disks, when you configure them (
log.file, File storage).
tests/
tests/app.rs boots the whole app on a temporary database and checks that the module graph is valid, /health/live answers and the profile route needs a signed-in user. Add your own end-to-end tests next to it; module tests live in each module's tests/ directory. See Testing.
Other directories
These appear as you use more of Navree:
resources/views/is whereViewModulelooks for template files (view.dirs). Templates generated bymake:mailare embedded in the binary instead.target/is Cargo's build output.
With a front end
navree new planner --ui next adds a Next.js app in web/:
- package.jsonnext, react, react-dom; dev, build, start, typecheck
- tsconfig.json
- next.config.ts
- .env.exampleNAVREE_API_URL, where the API listens
- README.md
- lib/
- bff.tscalls the API and keeps the tokens in httpOnly cookies
- app/
- layout.tsx
- page.tsx
- login/
- page.tsx
- api/
- auth/
- login/
- route.tssigns in through the API, sets the cookies
- logout/
- route.ts
- login/
- [...path]/
- route.tsforwards every other /api call with the bearer token
- auth/
The browser only talks to the Next.js server, which talks to the API. The tokens stay in httpOnly cookies on that server, and the browser never sees them. navree dev starts the front end's dev server too.
The framework repository
Navree is developed in one repository, NavreeHQ/navree: the framework's crates, the CLI, a reference application, the benchmark and this website.
- Cargo.tomlthe workspace: crates/*, apps/crm-api, apps/crm-api/crates/*
- Cargo.lock
- rustfmt.toml
- .cargo/
- config.tomlsccache as the compiler wrapper
- crates/
- navree/the facade; dependency-graph and full-stack tests
- navree-kernel/one crate per module...
- navree-http/
- navree-db/
- ...
- navree-cli/the navree binary and its templates
- apps/
- crm-api/the reference CRM API, a Navree app
- src/
- crates/crm-core, crm-companies, crm-deals, crm-activities, crm-users, crm-testkit
- tests/
- crm-web/the CRM front end (Next.js), Vitest and Playwright
- website/navree.com and these docs
- bench/the benchmark: SPEC.md, implementations, results
- docs/product requirements, build design, plans, notes
- assets/the logo
- deploy/scripts that deploy navree.com
Each framework crate has the usual src/, and most keep their integration tests in one binary under tests/<name>/, such as crates/navree-config/tests/config/main.rs. crates/navree-cli/templates/ holds the templates behind navree new and the generators, so it is the reference for what a new app contains.
The crates form eight layers, from the kernel up to the facade and the CLI, and a test checks every dependency between them against the allowed edges. The crate hierarchy explains them, and Contributing explains how to build and test the repository.