north-scape/relayboard

Relayboard: accessible team boards with audited actions, dependency maps, and shared web/MCP use cases.

A remix template · 0 remixes · Remix north-scape/relayboard

docs/DESIGN.md

Design notes

One rule boundary

domain/ owns roles and validation. application/ owns visibility, card workflows, dependency graph checks and AI scoping. infrastructure/ supplies DataK3 and Models adapters. doors/web.py and doors/mcp.py do no business-rule duplication. Tests swap the adapters, not the rules.

The Dodil organization/user pool is the workspace boundary. Within it, a board is the ownership and permission aggregate. Only the board owner manages access, including demotion. An email grant can exist before a person first signs in; appid owns account enrollment. There is no custom login or email-delivery system. A viewer may request AI suggestions because they are read-only, but cannot save them or edit any card.

Data and concurrency

All production state is DataK3 SQL. Identifiers are application-generated UUID strings. Labels, blocker ids, and checklist steps are bounded JSON text fields: simple, portable, and easy to remix. No extra vector database or graph service is introduced. Semantic matching embeds only the already-authorized board's cards using Dodil Models and ranks by cosine similarity in-process; vectors are not persisted. This intentionally suits small boards, not unbounded search workloads.

Writes and their audit rows share a transaction. A mutation takes SELECT … FOR UPDATE on the board and increments a common aggregate revision guard so even disjoint dependency edits conflict on optimistic DataK3 deployments. The card is reread after acquiring that guard. This prevents validating a stale card while waiting on another writer. 40001 becomes a retryable conflict response, not an automatic blind replay.

Every client-selected edit of an existing card requires the observed strict-integer expected_revision through web and MCP, including metadata, assignment, checklist replacement, moves and dependency changes. Missing or coercible values are rejected; after authorization and the locked reread, the application independently rejects a nonmatching revision before any change or no-op handling. The UI retains the revision the person saw; conflicts preserve the draft and are not automatically replayed. Clients that previously omitted revisions must upgrade; see the revision contract for compatibility and verification limits. Board/membership operations do not gain caller-supplied concurrency tokens from this change. Create retries still lack durable idempotency keys; the UI suppresses simultaneous submissions, but a lost response can still cause a duplicate if a caller retries. Never claim exactly-once creation.

The audit includes field-level before/after values, actor and UTC timestamp. No-op card changes create no audit noise. All fields are validated before saving. If an audit write fails, the card mutation rolls back with it. Existing starter buckets require the separately provided additive migration; fresh remixes use the full schema.

Authentication and browser safety

The app accepts only the gateway's X-Dodil-User JSON email identity. It does not validate raw bearer tokens itself; appid/gateway owns that. Raw app-port access must remain private. Header-stripping and forwarded-host/protocol behavior are mandatory live checks, not something fake-header tests can prove. Production ships no development identity fallback.

Private data requests have no-store caching, nosniff, same-origin policy, and a CSP excluding third-party scripts, inline execution, framing and base-URL injection. Browser cross-origin mutation requests are refused. The frontend renders data through text nodes, not HTML string interpolation. Dialogs use native semantic elements; moving a card has a keyboard alternative to drag/drop.

AI safety and scope

AI receives only the board already authorized by application rules. It has no executable tool loop. Instructions explicitly classify card content as data, but prompt injection cannot be declared solved: generated text remains an untrusted suggestion. There are no OpenAI/Anthropic API keys. Production calls only Dodil Models with the generated scoped service-account token. In-process tests and the localhost preview use deterministic fake AI and make no paid call.

Reviewed checklists

Each persisted step has a server-generated stable ID, nonempty text (at most 300 characters), and a strict boolean completion flag. A card holds at most 50 steps. Existing IDs must belong to that card and cannot repeat; omission means a new step. A complete replacement is validated before any card write, and shares the existing revision/transaction/audit boundary. Empty replacement explicitly clears the list.

AI returns at most eight bounded text suggestions and the source revision. The browser presents literal-text selections, then adds chosen nonduplicate suggestions only to a local draft. The person can edit/check/remove steps; only Save card persists them with other card changes. Cancel/reopen discards a draft. A viewer can read suggestions but cannot apply or save them. MCP separates suggest_checklist from the destructive replacement action update_checklist, whose instructions require user review.

Checklist, similarity, blocker, and briefing requests are bound to the dialog generation; a late response or error cannot populate a later reopening of the same card. A delayed dependency save also cannot advance the revision of a newer editor. Form submissions freeze controls until the request resolves, and per-operation ownership prevents an old save from unlocking newer requests. Repeated reads are suppressed while in flight; controls created by a late AI result remain locked during saves. These behaviors are covered by simulated-DOM tests, not a claim of live browser verification.

Board summaries include authorized card IDs/references, assignees and checklist completion counts. This lets the model resolve blocker links without receiving unrelated boards or all checklist text. It improves the supplied context, not a guarantee of a correct summary.

Deliberate simplicity

Three fixed lists keep the workflow understandable. Dependency cycles and cross-board links are refused. Completed prerequisites stop blocking. Overdue is computed at read time in UTC, so it requires no cron job and never rewrites cards just because midnight passed. My-week means assigned open work due before UTC today +7 days, plus undated work and overdue items.

Remaining production work

The priority remains external assistant OAuth and a genuine final fresh-org remix. The hosted checklist release has received migration 002 and passed the browser/DataK3 persistence, audit and stale-edit checks recorded in VERIFICATION.md. This does not migrate other existing copies or establish checklist-specific live member/viewer/outsider flows, mobile behavior, or every interrupted-request path. Fresh remixes use the complete schema without migrations. Next hardening work: idempotency keys, ownership transfer, server-side pagination and quota/rate controls, persistent embeddings for larger boards, and broader browser/accessibility coverage. Local tests do not establish a deployment or competition result.