DECISIONS.md — Architecture & Scope Decisions (Confluence expansion)
Decision records: context → decision → consequences. Numbers are stable references (A-00x) used in the other Phase-0 docs and the feature tracker.
A-001 — Whiteboard is a page kind with a hand-rolled SVG renderer
Context. Spec §12 requires a whiteboard content type and says to evaluate OSS canvas libraries and licenses before selecting one. The existing app integrates content types as page kinds (databases are pages + sidecar data).
Decision.
- A whiteboard is a
Pagewithkind='whiteboard'plus awhiteboardssidecar table (canvas JSON,schemaVersion). It inherits the page tree, permissions, comments, versions, trash, and search without new code. - Rendering uses a hand-rolled SVG renderer (
packages/whiteboardfor schema + pure geometry/undo, renderer inapps/web). Evaluation of the OSS candidates (tldraw, Excalidraw, fabric, konva): each is either a full application framework (tldraw/Excalidraw — their UI/UX would not fit the existing design system and they assume their own persistence), or a low-level canvas library (fabric/konva — adds a dependency for which the spec's required feature set — sticky notes, shapes, orthogonal connectors, freehand, grouping — is a subset of what we'd end up writing ourselves on top of it). At ~1.5k LoC of owned SVG code, no new dependency, no license surface, and full control over the versioned schema, in-house wins.
Consequences. No dependency/license risk; we own the schema migration story; we must write the geometry code (connector routing, grouping bounds, hit-testing) — scoped in TASK spec. Follow-up option unchanged: if multi-user whiteboard realtime (A-004) lands, the SVG renderer stays compatible (render-from-canvas is decoupled from the sync protocol).
A-002 — No external third-party connectors this round
Context. Spec §17 asks to evaluate connectors for issue trackers, SCM,
chat, calendars, and to not introduce integrations that cannot be maintained.
The app already has: public REST API v1, API keys, OAuth2, signed webhooks
(13-event catalog), an Integration config model + admin surface.
Decision. Defer all third-party connectors. This round: (a) extend the
webhook event catalog with the new domain events so external systems can
already react to tasks/reviews/whiteboards; (b) document the connector
evaluation (candidates, risks, maintenance burden) in the API docs; (c) keep
the Integration surface as the future mounting point.
Consequences. No new external dependency/maintenance surface; webhook consumers get first-class events for the new domains immediately.
A-003 — No custom roles this round
Context. The roadmap's Phase 14 already records "advanced permissions (policy expressions, guest restrictions)" as a future task with no TASK id. Spec §9 asks for custom roles "when compatible".
Decision. Keep the existing 4-role RBAC + resource-level grants (None/View/Comment/Edit/Full). Custom roles deferred.
Consequences. Review workflow uses the existing Full-Access/Member roles
for reviewer assignment (reviewers are explicit user lists, not a role).
Future custom-role work can map onto reviews.reviewerIds without rework.
A-004 — Whiteboard is single-user first; no realtime canvas sync
Context. Spec §12: "concurrent editing if technically feasible"; also "do not prioritize whiteboards ahead of core content integrity".
Decision. v1 whiteboards are single-user: edits autosave the whole canvas (debounced) + create a PageVersion snapshot on explicit save; concurrent openers see a "X is editing" presence chip (existing presence infra) and last save wins on the canvas (documented LWW). A CRDT whiteboard (Yjs map of objects) is a recorded follow-up.
Consequences. Simpler v1, no canvas-level conflict logic; presence reuse gives users a safety signal; the canvas JSON + schemaVersion are designed so a future per-object CRDT can layer on without a rewrite (objects are id-keyed — CRDT-friendly).
A-005 — Built-in templates are seeded per workspace
Context. Template.workspaceId is a required FK; there is no org-level
template table. Spec §6 wants "global templates".
Decision. "Global" = isBuiltin templates seeded into each workspace
by an idempotent seed hook (on workspace creation + on seed run for existing
workspaces). Users cannot edit/delete builtins (server-enforced); they can
duplicate them into editable copies.
Consequences. No schema change for scoping; existing permission model untouched; cost is N×15 template rows (trivial: 15 small JSON snapshots).
A-006 — Tasks are page-backed (sidecar table, not records-in-a-database)
Context. Spec §J wants tasks with assignees/due/status/checklists +
references in pages. Alternatives: (a) a seeded "Tasks" database (records),
(b) a first-class Task entity, (c) page-backed with a queryable sidecar.
The user chose "first-class task entity" during plan review.
Decision. A task is a Page (kind='task') + a tasks sidecar row
(assigneeIds, status, dueAt — the columns needing indexed queries). The page
carries the title/description/checklist blocks, comments, permissions, search
indexing, and backlinks for free; the sidecar powers the inbox queries,
due-date filters, and reminder jobs. A task block type renders a read-only
card linking to the task page.
Consequences. No parallel content store; inbox = one indexed query; checklist = existing todo blocks (no new checklist model). Limitation: cross-workspace task assignment is out (tasks are workspace-scoped like pages).
A-007 — Activity feeds project from the audit log; no new event store
Context. Spec §K wants user + space activity feeds. The app already
persists every security-relevant and most domain actions to audit_logs
(actor, workspace, resource, action, time, metadata) with hot-path indexes.
Decision. Feeds are permission-scoped, time-ordered queries over
audit_logs (public-safe subset of actions: create/edit/comment/review/
share/watch) — not a new pipeline or table.
Consequences. Zero new write path; feed freshness = audit freshness (same transaction). The audit export/redaction rules already defined for admin views are reused. Limitation: non-audited cosmetic actions (e.g., favorite toggle) do not appear in feeds.
A-008 — Backlinks: computed + cached, no table (with an upgrade trigger)
Context. Spec §A wants backlinks and related-page discovery.
Decision. GET /pages/:id/backlinks scans referencing block types +
comment page-mentions, filters by canView on sources, cached with a
version-key bust on reference-changing events.
Consequences. Simple, always consistent with the live data. Upgrade
trigger (recorded): if the 100k-profile load test shows backlinks p95 >
100 ms, add a maintained page_backlinks table updated by the existing event
pipeline. (Ponytail: don't build the index before measuring the need.)
A-009 — One migration, all additive
Context. 7 new tables + 5 new columns + enum additions.
Decision. A single additive Prisma migration
(20261011000000_confluence_expansion) + seed extension + OpenSearch mapping
update. Feature defaults preserve legacy behavior, so no runtime feature flag
is required.
Consequences. Simple upgrade path; rollback = drop additive objects (documented in DATABASE_IMPACT.md §4).
A-010 — AI capabilities extend the existing gateway with five tools
Context. Spec §L lists assistant capabilities; the AI gateway, RAG retrieval, structured tool calls, budget guard, and logging all exist.
Decision. Five new tools (extract-actions, generate-faqs,
find-duplicates, find-stale, suggest-metadata) implemented as services
in apps/api/src/modules/ai on the existing gateway + RAG + permissions
stack; writes always go through normal domain services as the requesting
user. No new provider, vector store, or conversation surface.
Consequences. All spec §15 security requirements (permission-filtered retrieval, recheck on cached results, citations, no fabricated refs, secure credentials, logging) are inherited from the existing, already-tested RAG stack; each new capability gets a security negative test (SECURITY_REVIEW §4.8).
Conflict log (rule 29)
No conflicts between ARCHITECTURE.md, PRODUCT-SPEC.md, and
Confluence-new-feature.md were found that require resolution. The spec's
"evaluate CRDT/OT" (D), "evaluate OSS canvas libraries" (I), and "evaluate
connectors individually" (N) are evaluation mandates — satisfied by
decisions A-001, A-002, and the existing Yjs CRDT (realtime docs).