docs: update for new crate layout

This commit is contained in:
2026-10-25 22:58:46 +01:00
parent b76f5996da
commit 80072eb463
20 changed files with 148 additions and 106 deletions

View File

@@ -47,13 +47,17 @@ Small files with a single concern. If a file grows past ~100-150 lines, it's pro
### Tests
Never in the same file as production code. Use cases keep their tests in a sibling `tests/` module, one file per use case:
Never in the same file as production code. Each crate keeps its tests in `crates/<crate>/tests/`, one file per unit under test, grouped by the same module as the production code. Cargo builds each top-level `tests/<group>.rs` as one integration-test binary; the group file lists its members with `#[path]`:
```
crates/application/src/diary/log_review.rs
crates/application/src/diary/tests/log_review.rs
crates/application/tests/diary.rs # mod support; + #[path] list of the group
crates/application/tests/diary/log_review_test.rs
crates/application/tests/support/ # shared contexts and command builders
```
Adapters follow the same layout (`crates/adapters/sqlite/tests/repositories/diary_repository_test.rs`). The only tests left beside source are small mapper tests in `crates/adapters/http-axum/src/**/tests.rs`, which need crate-private items; their shared fixtures live in `http-axum/src/test_support.rs`. Route smoke, API and handler tests run against the real composition and live in `crates/bootstrap/tests/`.
## Naming
### Conventions
@@ -174,7 +178,7 @@ Errors propagate with `?` and bubble up to a single handler. No scattered panic
## Configuration
Secrets (API keys, JWT secrets) and deployment settings live in environment variables, read once at startup into a typed config struct.
Secrets (API keys, JWT secrets) and deployment settings are read once at startup by the `config` crate into a typed `AppConfig`: built-in defaults, then `config.toml` (or the file named by `CONFIG_FILE`), then environment variables. Malformed values fail startup; empty values count as unset. Only the binaries load configuration; everything else receives typed config values.
Zero magic numbers or strings. Everything named, everything explained by its name.
@@ -207,7 +211,8 @@ When none of those can carry it, a short comment stating the reason (never resta
- Domain crate: zero external dependencies beyond `thiserror`, `serde` and small value-type crates
- Application crate: depends only on domain
- Adapters: free to pull in platform crates (`axum`, `sqlx`, `nats`, etc.)
- Bootstrap: wiring only
- Bootstrap: wiring only; the only crate that names adapters
- Binaries (`server`, `worker`): load config, call `bootstrap`, run — nothing else (`make check-binaries-are-thin`)
## Trait Objects for Ports
@@ -226,7 +231,7 @@ Prefer a closed enum over `dyn` only where exhaustiveness is the point — when
### Test Helpers Are Gated
`domain::testing` (in-memory fakes and noops) compiles only with the `test-helpers` feature, which crates enable in their `[dev-dependencies]`. Production builds must never contain fakes. `application::test_helpers` is `#[cfg(test)]`.
`domain::testing` (factories, the cascading `InMemoryStore`, noops and `Refusing*` fakes) compiles only with the `test-helpers` feature, which crates enable in their `[dev-dependencies]`. Production builds must never contain fakes. Build entities with the `domain::testing` factories instead of repeating struct literals in each test.
### Coverage Targets
@@ -235,7 +240,7 @@ Prefer a closed enum over `dyn` only where exhaustiveness is the point — when
| Domain | TDD (red-green-refactor) | 100% |
| Application | TDD | High coverage |
| Adapters | Integration tests where practical | Best effort |
| Bootstrap | No tests | — |
| Bootstrap | Route smoke, API and handler tests over the real wiring | Every route reachable |
### Fakes Must Not Be Kinder Than Production