FEATURE_GAP_ANALYSIS.md — Confluence-Class Feature Matrix (Phase 0)
Source spec:
Confluence-new-feature.md(workspace root, outside the repo). Classification per spec §3: R = already implemented, production-ready · P = implemented, incomplete · F = implemented, requires refactoring · N = not implemented · E = not applicable / external-integration dependent.Existing evidence = files / tables / endpoints / tests verified in the tree.
Domain A — Spaces & content hierarchy
| Capability | Class | Existing implementation | Proposed change |
|---|---|---|---|
| Create/update/delete spaces | R | Workspace model, workspaces module CRUD, E2E workspace.spec.ts |
Add archive/restore (below) |
| Space key, title, description, icon | P | slug (unique key), name, description, iconUrl exist |
No new fields needed; surface key in UI as "space key" |
| Space archive/restore | N | deletedAt (soft) + isPersonal only |
Add archivedAt/restore + endpoint + UI |
| Space types (team/project/KB/custom) | N | settings JSON only |
Add type column (enum-ish string, default team), directory filter |
| Space membership/roles/permissions | R | WorkspaceMember + RBAC + Permission grants, E2E |
— |
| Space directory (filter/sort/search) | N | Sidebar lists teams/pages only | New /spaces route + GET /workspaces listing (member-scoped, permission-aware) |
| Space-level content statistics | N | usageStorageBytes only (files) |
GET workspaces/:id/stats (pages, blocks, records, comments, members, storage) |
| Unlimited nesting, expand/collapse tree | R | Page.parentId, virtualized sidebar tree |
— |
| Drag-and-drop reordering/moving | R | dnd-kit sidebar + API move with cycle guard | — |
| Move between spaces (with authz) | P | Move is within workspace; cross-workspace page move absent | Cross-workspace move endpoint with permission checks + reindex + audit (P1) |
| Breadcrumbs, parent relationships | R | page view shows parent chain | — |
| Duplicate/archive/restore/delete | P | archive (trashedAt), restore, permanent delete exist; duplicate missing | POST pages/:id/duplicate (recursive, new positions/ids, page.duplicated event) |
| Bulk actions (confirm, partial failure) | N | none | POST pages/bulk {ids, action} → per-id result list, all-or-nothing per op, audit |
| Backlinks & related-page discovery | N | pageMentionIds on comments only |
GET pages/:id/backlinks (scan child_page/synced_block/linked_database/comment pageMentionIds); "Related pages" panel; index maintained via events |
| Cycle prevention | R | page.service.ts L419 descendant check + test |
— |
| Pagination/virtualization of large trees | R | @tanstack/react-virtual in sidebar |
— |
| Lifecycle states (draft/published/archived/deleted) | P | archivedAt, deletedAt, trashedAt |
Review workflow adds draft/in_review/approved/published/changes_requested (Domain J) |
| Soft delete + trash + retention | R | trashedAt/restore/permanent purge + retention policies | — |
Domain B — Advanced page editor
| Capability | Class | Existing | Proposed change |
|---|---|---|---|
| Rich text + structured blocks | R | Tiptap, ~30 block types | — |
| Headings/paragraphs/lists/nested/checklists/quotes | R | extensions in packages/editor |
— |
| Tables with row/column operations | P | table block (rows × cols strings) |
Add row/column add/remove/move ops (editor + BLOCK_CONTENT_SCHEMAS.table unchanged; UI ops only) |
| Images/attachments/media embeds | R | media blocks + files pipeline + previews | — |
| Code blocks + syntax highlighting | R | code block w/ language, highlighting (recent commits) |
— |
| Callout variants (info/warning/tip/error) | P | callout textContent only |
Add variant to callout content schema + UI |
| Status labels, dates, inline elements | N | none | Inline Tiptap nodes: date, status, label (rendered from block text spans) |
| Mentions + inline formatting | R | @ popup in editor + composer, mentionIds stable refs |
— |
| Slash-command menu | R | slash-menu.tsx |
— |
| DnD block reordering | R | dnd-kit, fractional positions | — |
| Table of contents + heading anchors | N | none | toc block (generated from headings, anchor links) + heading anchor slugs |
| Expandable sections | R | toggle block |
— |
| Page & block embeds | R | child_page, synced_block, linked_database |
— |
| Reusable/synchronized blocks | R | synced_block (sourceBlockId) |
— |
| Template insertion | P | template dialog + POST templates/:id/apply |
Extend with variables (Domain C) |
| Keyboard shortcuts, a11y, undo/redo | R | shortcut set, WAI-ARIA, Tiptap history | — |
| Autosave + save-state + recovery | R | 500 ms debounce flush + offline outbox + LWW | — |
| Version-aware editing + conflicts | R | Page.version optimistic concurrency + 409 LWW consent + CRDT (Yjs) |
— |
| Stable document schema + migration | R | canonical Block JSON, Zod schemas in packages/shared |
New block content fields are additive (Zod .optional()), old docs unchanged |
Domain C — Templates & blueprints
| Capability | Class | Existing | Proposed change |
|---|---|---|---|
| Global templates | P | Template (type workspace/page/database/team), isBuiltin |
Surface "global" = built-in |
| Space-specific templates | R | workspaceId scoping |
— |
| User-created templates | R | POST pages/:id/templates |
— |
| Categories & descriptions | N | none | Add category, description columns |
| Search & previews | N | /templates page lists only |
Search input + preview (render snapshot read-only) |
| Template variables + form-based generation | N | none | variables: Json (typed list); instantiation dialog with React Hook Form; substitution engine |
| Template version history | N | updatedAt only |
TemplateVersion snapshots; restore + list |
| Permissions for template management | P | workspace role gate exists | Refine: Full Access manages; Viewer can use |
| Default templates for new pages | N | none | settings.templates.default per workspace + type |
| 15 initial templates (meeting notes, PRD, ADR, postmortem, …) | N | seed has none | Seed as real block content (isBuiltin, snapshot JSON), idempotent seed |
| Templates produce editable content | R | apply instantiates blocks |
— |
Domain D — Comments, mentions, collaboration
| Capability | Class | Existing | Proposed change |
|---|---|---|---|
| Page-level comments | R | Comment + threads + E2E |
— |
| Inline comments on selections | P | Comment.blockId + selection Json anchor |
Define + test anchor survival: anchor by block + text prefix/suffix; on deleted text keep comment on block with "original text" badge (P1 hardening) |
| Threaded replies | R | CommentReply |
— |
| Edit/delete permissions | R | author-only edit (PATCH :id), delete authz + audit |
— |
| Resolve/reopen | R | resolvedAt, status |
— |
| Reactions | R | CommentReaction |
— |
| Deep links to page/comment | P | …/page/[id]/[block] route exists |
Verify comment anchor param + scroll/highlight (E2E) |
| Notifications for participants | R | mention fan-out, TASK-0094 | — |
| Group mentions | P | user mentions + Team model exists |
Team mention type (notify all members, capped) |
| Real-time concurrent editing | R | Yjs rooms, presence, cursors, convergence, resume, offline | — |
| Session authz + cleanup | R | WS handshake auth + heartbeat prune | — |
Domain E — Version history & recovery
| Capability | Class | Existing | Proposed change |
|---|---|---|---|
| Revision record (id, number, author, ts, snapshot) | R | PageVersion (+ BlockVersion for block-level) |
— |
| Change summary | P | note on manual versions only |
Auto-version on significant edits with optional summary; capture actor + note |
| View history | R | GET pages/:id/versions |
UI history panel (list) |
| Inspect historical version | P | snapshot stored; no read-only viewer UI | Version preview (read-only render of snapshot) |
| Compare revisions | N | none | GET pages/:id/versions/compare?from&to → block-tree diff (added/removed/changed, LCS over block ids + content hash) + diff UI |
| Restore prior revision | R | POST …/restore |
— |
| Restore recorded as new revision | P | verify service behavior; must create new PageVersion |
Enforce + test (restore never overwrites history) |
| Authorization + audit | R | permission guard + audit events | — |
| Retention policy | N | none | Config: max versions + min interval; pruned by worker (documented overhead) |
Domain F — Enterprise permissions & identity
| Capability | Class | Existing | Proposed change |
|---|---|---|---|
| Org/space/page/action scopes | R | RBAC + Permission (None/View/Comment/Edit/Full) at all levels |
— |
| Roles (admin/manager/collaborator/viewer/guest) | R | Owner/Admin/Member/Guest | — |
| Custom roles | N (deferred) | not built | Deferred by decision A-003 — recorded non-goal for this expansion |
| User/group assignments | R | WorkspaceMember, Team/TeamMember, SCIM groups |
— |
| Separate create/edit/delete/comment/export/perm caps | R | permission levels + endpoint-specific checks | — |
| Parent-child visibility inheritance | R | permission engine inheritance | — |
| Permission-aware search/navigation | R | search grant snapshots; fail-closed | — |
| Attachment/export/API/webhook/job authz | R | signed URLs, API keys, webhook scopes, worker checks | — |
| Safe revocation | R | session revoke, key revoke, share revoke, TTL cache bust | — |
| Admin audit logs | R | AuditLog + viewer + export |
— |
| Anonymous read-only sharing + expiry/revocation | R | Share (token, password, expiry, scope) |
— |
Centralized canView/canEdit/… service |
R | packages/permissions |
New features must call it (invariant) |
Domain G — Search & discovery
| Capability | Class | Existing | Proposed change |
|---|---|---|---|
| Global search (titles/content/spaces/comments/attachments) | R | OpenSearch index incl. file + comment docs | Extend index with label/lifecycle metadata (new fields) |
| Search-as-you-type | R | ⌘K debounce suggestions | — |
| Filters (space, owner, type, label, date) | P | type/workspace/team/date/creator | Add label + lifecycle filters |
| Sorting (relevance/created/updated) | P | relevance default | Add date sorts |
| Recently viewed / updated | N | none | UserRecentItem (per user, capped list) updated on page open; "Recent" tab in ⌘K |
| Favorites / saved searches | P / N | page favorites exist | Saved searches: SavedSearch (query JSON + name) + UI |
| Snippets + highlights | R | OpenSearch highlights | — |
| Backlinks / related in results | N | none | Related-pages section (reuse Domain A backlinks) |
| Indexing + reindexing/recovery tools | P | event-driven indexer + reconcile backstop | Admin "Reindex now" endpoint (idempotent full rescan) |
| No stale/leaky results after perm change/delete | R | grant snapshots + delete events + reconcile | Keep; add test for new entity types (tasks, whiteboards) |
Domain H — Structured databases
| Capability | Class | Existing | Proposed change |
|---|---|---|---|
| Schemas + custom properties | R | DatabaseProperty typed (22 types) |
— |
| Field types (text/number/date/checkbox/select/multi/person/url/relation) | R | all present | — |
| CRUD + duplicate records | R | record CRUD; duplicate via database button | — |
| Table/board/calendar/card views | R | 8 view types | — |
| Filtering/sorting/grouping/saved views | P | query engine + DatabaseView |
Saved-view management UI (rename, default, visibility) |
| Relations | R | Relation + RelationLink + rollups |
— |
| Record ↔ page links | R | record = page 1:1 | — |
| CSV import | N | export exists | POST databases/:id/import/csv (header → property mapping, dry-run preview, row errors) |
| Schema changes without corruption | R | additive property model, JSONB values | — |
| Pagination/perf controls | R | virtualization, cursor queries | Expose explicit pagination (limit/offset cursor) in UI |
| Permission-aware records | R | record-level grants | — |
Domain I — Whiteboards
| Capability | Class | Existing | Proposed change |
|---|---|---|---|
| All whiteboard features | N | none | New whiteboards content type: versioned canvas JSON (schemaVersion, objects array), custom SVG renderer in packages/whiteboard (no new deps — DECISION A-001), pan/zoom, sticky notes, text, shapes, connectors/arrows, freehand, grouping, selection/resize/delete, undo/redo, save/restore, comments via existing Comment (blockRef → whiteboard), links to pages/external, "convert selection → page". Realtime = single-user first (A-004). |
Domain J — Tasks, calendars, workflows
| Capability | Class | Existing | Proposed change |
|---|---|---|---|
| Tasks (assign, due, status, checklists) | N | NotificationType.TASK_ASSIGNED placeholder only |
Task model (title, pageRef, assigneeIds, dueAt, status, checklist blocks), TasksModule, personal inbox route, filters |
| Task references in pages | N | none | task block + linked from review workflow |
| Personal inbox + filters | N | notifications page only | /inbox route (assigned, due, overdue, done tabs) |
| Reminders | N | none | Worker scheduled jobs on dueAt (existing BullMQ delay) → notification |
| Review workflow (draft/in review/approved/published/changes requested/archived) | N | archive/trash only | Page reviewState + Review model (reviewers, comments, deadlines, decision) + transition validation + notifications + audit |
| Configurable reviewers/approvals | N | none | as above (one-or-more approvers, all-must-approve default) |
| Automation rule engine | R | Automations* models + matchers + executors + DLQ |
Reuse for review deadlines/staleness rules; no new engine |
| Calendar view (tasks/due dates) | N | database calendar view exists (dates) | Task calendar tab in inbox (due dates) |
Domain K — Notifications & activity
| Capability | Class | Existing | Proposed change |
|---|---|---|---|
| Unified notification service | R | Notification + in-app/email/webhook channels, dedup, retry |
Extend types: REVIEW_REQUESTED, APPROVAL_DECISION, WATCH_UPDATE |
| Notification center | R | bell + /notifications |
— |
| Read/unread | R | readAt |
— |
| Preferences | R | per-type email prefs | Extend to in-app granularity (same table) |
| Email delivery + retry/dedup | R | worker + idempotency | — |
| Deep links | R | link Json |
— |
| Watchlist | N | none | PageWatch (user × page) + watch actions + WATCH_UPDATE fan-out |
| User activity feed | N | AuditLog exists (admin view) |
Public per-user feed endpoint over domain events (recent activity of pages you're involved in) |
| Space activity feed | N | none | GET workspaces/:id/activity (recent create/edit/comment/review events, permission-scoped) |
| Durable delivery (no loss after tx commit) | R | event bus after-commit pattern | — |
Domain L — AI knowledge assistant
| Capability | Class | Existing | Proposed change |
|---|---|---|---|
| Summarize pages | R | TASK-0123 page AI | — |
| Draft from templates | R | TASK-0126 structured generation | — |
| Q&A across authorized sources (RAG) | R | TASK-0125 hybrid retrieval + citations | — |
| Extract action items from meeting notes | N | none | POST ai/extract-actions → create tasks (via TasksModule, requester permissions) |
| Generate FAQs from documentation | N | none | POST ai/generate-faqs → draft page (Q/A callout structure) |
| Find related content / duplicates | N | RAG similarity exists | POST ai/duplicates → scored pairs (title embedding + content) + UI list |
| Identify stale/contradictory pages | N | none | POST ai/stale (last-updated heuristic + AI contradiction check) → report |
| Suggest owner/tags/review dates | N | none | POST ai/suggest-metadata → suggestion panel (apply = normal API calls) |
| Permission-filtered retrieval + recheck on cache | R | RAG service checks requester grants per chunk | Extend to new capabilities (same service, invariant L-1) |
| Citations + no fabrication | R | enforced in RAG answer shape | Extend tool schema for new capabilities |
| Provider config + credential security | R | gateway, per-workspace config, env secrets | — |
| AI op logging | R | model/tokens/latency logs | — |
Domain M — Administration, audit, governance
| Capability | Class | Existing | Proposed change |
|---|---|---|---|
| Users/groups, space settings, roles, templates admin | R | admin console tabs | Templates admin (manage built-ins, defaults) |
| Lifecycle & retention | R | retention policies | + version-retention config (Domain E) |
| Attachment storage settings | R | quotas | — |
| Search/index health | P | index exists; no health surface | Admin: doc count, lag, last reconcile, reindex button |
| Notification delivery health | P | emailSentAt flags; no surface | Admin: recent sends, failures, queue depth |
| Integration config | R | integrations tab (surface) | — |
| API tokens + webhook subscriptions | R | developer hub | — |
| Audit search/export | R | viewer + S3 export | — |
| Background job status/failures | N | BullMQ queues unmanaged | Admin: queue depth, failed job list (BullMQ API), dead-letter view |
| Audit retention/redaction/access rules | R | retention policies + export access | — |
Domain N — Integrations & extensibility
| Capability | Class | Existing | Proposed change |
|---|---|---|---|
| REST API (spaces/pages/versions/comments/tasks/search/attachments/users/webhooks) | P | most endpoints exist | Extend API for new domains: tasks, reviews, whiteboards, saved searches, backlinks, stats (versioned /api/v1) |
| API versioning/auth/scoped authz/validation/pagination/rate limits/errors/idempotency | R | TASK-0127/0128 envelope, keys, OAuth, rate limits, idempotency | Apply same envelope to new endpoints |
| Webhooks + signatures + retry | R | 13-event catalog | Add new event types (task.assigned, review.approved, whiteboard.created) to the single catalog |
| API docs + examples | R | OpenAPI + docs surface | Regenerate; keep contract test green (SPEC ⊆ LIVE ⊆ SPEC) |
| External connectors (issues/SCM/chat/calendar) | E (deferred) | Integration model + surface |
Deferred by decision A-002 — surface + docs only; no third-party connectors this expansion |
Coverage summary
- Production-ready (R): ~55 capabilities (core content, collab, permissions, search, AI core, API, enterprise).
- Incomplete (P): ~18 — mostly "exists, needs a surface or field".
- Not implemented (N): ~30 — the expansion work: whiteboards, tasks, reviews, template enrichment, version compare, backlinks, bulk/duplicate, saved searches/recent, activity feeds, AI capabilities, admin health.
- Deferred/external (E): custom roles (A-003), external connectors (A-002), realtime whiteboard (A-004).
No capability requires replacing an existing module. Every change above is additive on the current architecture.