Conventions for anyone (human or AI) modifying this codebase.
Before any commit, the build must pass:
pwsh -NoProfile -File build.ps1This runs CMake configure + Ninja build + windeployqt. Incremental builds
take ~5–10s; full clean builds take longer. Do not commit if it fails.
Read CONTEXT.md before naming anything. New modules should
be named after domain concepts from that file, not after Qt classes or
implementation details. If you introduce a new domain term, add it to
CONTEXT.md in the same commit.
- Seams are abstract. Production code holds pointers/references to abstract interfaces, not concrete adapters. The compiler enforces this.
- Two adapters per seam. A seam with only one adapter is hypothetical and tends to leak. If you add a new abstraction, ship at least two implementations (production + test, or two production formats).
- The interface is the test surface. Tests call the abstract API. They
never
friendinto a concrete class or poke at its privates. - No
QSqlDatabaseoutside thedatabasemodule. If a caller needs to run SQL, it goes through the seam. The seam owns query construction. - No widget pointers in non-GUI modules. A module that takes a
QWidget*is a presenter, not a domain module. Presenters are thin. - No SQL string concatenation in non-database modules.
dbquery.hsplitting-by-;lives in the database module, not inmainwindow.cppor the CLI.
component, service, API, boundary, manager (as a suffix on a
domain word — SessionManager survives because it's a name, not a pattern
to extend). Use module, adapter, seam, presenter, executor,
orchestrator.
- One logical change per commit.
- Build must pass before each commit.
- Commit message: short subject line (<=72 chars), imperative mood. Body only when the why isn't obvious from the diff.
- Don't commit: build outputs,
.envfiles, secrets, generated files.