Design notes
One set of use cases, two thin doors. application/use_cases.py is the only place that
changes the board. doors/web.py and doors/mcp.py translate HTTP / MCP into calls and errors
(NotFound 404, Forbidden 403, Invalid 422 or a tool error). A rule written once holds for
the page and for Claude alike, and the tests drive both doors to prove it.
Rules live in the domain. domain/model.py is plain Python: who may view / edit / manage
people, that an assignee must be on the board and not a viewer, that the last list is the
"done" list, what "overdue" means, and how a change is described for the log. No I/O, so the
tests are instant.
Visibility is enforced by lookup, not by checks sprinkled around. Every board and card is
resolved through resolve_board / resolve_card, which only search the boards the person is
on. A board you are not on answers "no such board" (not "forbidden"), so an assistant can't
even learn it exists.
People's words, not ids. Assistants say "the Ops board" and "card 12". Boards resolve by id or (unique) title; cards carry a per-board number. If #12 exists on two of your boards the tool says so and asks for the board instead of guessing.
History by diff. Before a change the card is snapshotted; afterwards
describe_changes writes one activity row per changed field (assignee: none -> bo@acme.io).
Moves, reorders, deletions, list and people changes are logged too.
Data. DataK3 over the Postgres wire, one bucket per remix. Keys are chosen by the app (no
sequences): uuids, board_id:email for memberships, MAX(number)+1 for card numbers. Writes
are idempotent upserts. Labels and blockers are small comma-separated columns, which keeps the
schema to five tables. Positions are floats so a drop between two cards needs one write.
AI is optional and honest. Checklist suggestions change nothing until applied (applying is a normal, logged edit and needs edit rights). Similar cards use Dodil Models embeddings over the cards the person can see. The daily summary is generated only from the board's own cards and recent history.
Sign-in is the platform's. The Ignite gateway signs people in through the app's appid pool
and passes X-Dodil-User; /mcp answers 401 with RFC 9728 metadata so Claude / ChatGPT can
start the same sign-in. The app has no login code.