One notes module, two callers
This workspace exists to prove one claim: a module whose rules depend on nothing but the framework's core runs unchanged wherever it is needed.
examples/reusable-notes/
├── notes-module/ the capability: model, rules, service, ports
├── apps/api/ an Axum REST application over it
└── apps/report/ a command-line job over it — no web server at all
The module knows nothing about HTTP, HTML, or a database. Applications choose a store and an adapter around it.
What it demonstrates
- The contract is the seam.
Notesand the repository port come from the module; the API and the CLI each depend on the module, never on each other. - Transport in the adapter only. Axum types appear in
apps/apiand nowhere else; the CLI needs no HTTP stack to reuse the same rules. - Validation once.
CreateNoteimplements the framework'sValidatetrait, so REST input and CLI input are checked by the same code.
What to steal
- Put the capability in its own crate with a small port surface, then write callers as thin adapters — the second caller costs almost nothing.
- Keep the store behind a trait so tests run against the in-memory implementation while production picks a real one.