Product Requirements — AI Software Factory
Canonical requirement registry. Every requirement in this product has a stable ID (
PR-xxx). This file is the authoritative ID source: if any other document, task file, or test references aPR-xxxID, the definition lives here.requirements-matrix.mdtraces each ID to its task file, phase, and verification tests.Priority legend
Priority Meaning P0 MVP — must ship in the first production milestone (Phases 0–9 partial, see §MVP Boundary) P1 Post-MVP production features (Phases 10–13) P2 Enterprise / hardening (Phases 14–15) Phase column references
ROADMAP.mdphase numbers (0–15). Verified by lists the task file (indocs/tasks/) and the test layer(s) that prove the requirement: unit (Vitest/Jest), integration (Testcontainers,tests/integration), e2e (Playwright,tests/e2e), perf (k6/Artillery,tests/performance), manual/ops (runbook-verified). Detailed functional text lives infunctional-requirements.md; UI behavior inux-requirements.md; measurable targets innon-functional-requirements.md.
1. Vision
AI Software Factory is a modern, self-hostable, multi-tenant collaborative workspace platform inspired by Notion — a production-grade SaaS platform, not a prototype. One deployment serves unlimited workspaces; every workspace is an isolated tenant with its own members, permissions, content, billing plan, and limits.
The platform combines, in one coherent surface:
- Knowledge: pages, nested page trees, wiki, knowledge base, templates.
- Authoring: a block-based editor (28+ block types) with drag & drop, slash commands, context menus, and full keyboard control.
- Structure: databases with 22+ typed properties, 9 view types, nested filters, relations, rollups, a safe formula engine, and database buttons.
- Coordination: real-time collaboration (Yjs CRDT), presence, comments, mentions, notifications.
- Automation & AI: event-driven automations (BullMQ), forms, dashboards, charts, an AI gateway with RAG workspace search.
- Openness: full REST API v1, webhooks, public sharing, import/export.
- Enterprise: SSO (SAML/OIDC), SCIM, audit logs, retention policies, org policies, admin console.
1.1 Non-negotiable product principles
| # | Principle | Consequence |
|---|---|---|
| 1 | Self-hostable | One docker compose brings up everything; no mandatory SaaS dependency (email, AI, storage all pluggable). |
| 2 | Multi-tenant from day one | Every query is tenant-scoped; no feature may leak across workspaces. |
| 3 | Server-side authorization | The frontend is a convenience layer; every operation re-validates in packages/permissions. |
| 4 | Records are pages | Every database row is also a full page — structure and prose never diverge. |
| 5 | Fractional ordering | Block/page/record ordering is LexoRank-style strings; array indexes are never persisted. |
| 6 | Safe computation | Formulas run in a bounded AST evaluator; AI page generation uses structured tool calls, never raw SQL. |
| 7 | Events for side effects | Writes stay fast; search indexing, webhooks, automations, and notifications consume domain events. |
| 8 | Accessible by default | WCAG 2.2 AA is a requirement, not a polish step (see ux-requirements §12). |
2. Personas
Five personas anchor the requirements. Each maps to the roles and flows the platform must serve.
| Persona | Who | Primary goals | Key features relied on |
|---|---|---|---|
| P-A: Individual knowledge worker ("Ana, PM at a startup") | Solo or small-team user in her personal workspace or a shared one | Capture notes fast; organize projects as pages + databases; search her own knowledge | Editor, slash commands, databases (table/board/calendar), templates, search, favorites, offline editing |
| P-B: Team lead ("Ben, engineering lead") | Runs a team workspace with ~10 members | Coordinate work via boards/timelines; assign via mentions; track status with rollups and dashboards; keep docs current | Databases with relations/rollups, buttons, boards/timeline/calendar, comments/mentions, notifications, dashboards & charts, automations (status changes → notify) |
| P-C: Workspace admin ("Carol, head of ops") | Manages one workspace (not the org) | Control who sees what; keep content organized (teams, templates, trash hygiene); publish forms; share public pages | RBAC + resource permissions, sharing scopes, invitations, teams, templates, forms, public sharing, file management, API keys |
| P-D: Developer / integrator ("Dan, platform engineer") | Integrates the workspace with internal tools | Automate with API + webhooks; build on typed REST endpoints; receive signed events | REST API v1, API keys (scoped), OAuth2, webhooks (HMAC), OpenAPI docs, automation via API, import/export |
| P-E: Enterprise IT ("Eva, CISO/IT director") | Procures and governs a self-hosted deployment | Prove security: SSO, provisioning, auditability, retention, isolation | SAML/OIDC SSO, SCIM, audit log viewer/export, retention policies, org policies, admin console, security headers, ASVS L2 posture, backup/DR |
Persona coverage rule: for every P0 requirement, at least one of {P-A, P-B, P-C} benefits directly; P-D requirements land in Phase 13 and P-E requirements in Phase 14 unless a security property (audit, rate limiting) protects all personas from Phase 1 onward.
3. Scope & requirement registry
This section is the complete registry. Feature areas mirror
PRODUCT-SPEC.mdsection numbers, cited asPS§n. Sub-requirements (e.g.PR-012a) inherit the parent's priority and phase unless stated otherwise.
3.1 Authentication & identity (PS§2.1, PS§24)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-001 | Users can register with email + password; email format and password strength (≥10 chars, mixed classes) validated server-side and client-side | P0 | 1 | phase-01-authentication.md · unit + integration + e2e |
| PR-002 | New accounts require email verification (token link, 24 h expiry, single-use); unverified users get a limited session that prompts verification | P0 | 1 | phase-01-authentication.md · integration + e2e |
| PR-003 | Login issues an access JWT (15 min) + rotating opaque refresh token (30 d, hashed at rest, single-use per rotation) | P0 | 1 | phase-01-authentication.md · unit + integration + e2e |
| PR-004 | Refresh token rotation: using a previously-rotated token revokes the entire token family (replay detection) | P0 | 1 | phase-01-authentication.md · integration |
| PR-005 | Logout revokes the current session; sessions can be listed and individually revoked from security settings | P0 | 1 | phase-01-authentication.md · integration + e2e |
| PR-006 | Password reset: emailed token, 1 h expiry, single-use, revokes all sessions on use | P0 | 1 | phase-01-authentication.md · integration + e2e |
| PR-007 | Passwords hashed with bcrypt (cost 12); comparison timing-safe; no plaintext ever logged | P0 | 1 | phase-01-authentication.md · unit |
| PR-008 | Users can view/update profile: name, display name, avatar, locale, timezone, theme | P0 | 1 | phase-01-authentication.md · integration + e2e |
| PR-009 | Registration and login endpoints are rate-limited per IP + per email (see security-architecture §10) | P0 | 1 | phase-01-authentication.md · integration |
| PR-010 | Every login, failed login, logout, and reset emits a mandatory audit event (actor, IP, UA) | P0 | 1 | phase-01-authentication.md · integration |
| PR-011 | Enterprise SSO via OIDC (auth code + PKCE) and SAML 2.0 per organization, with enforce mode that disables password login |
P2 | 14 | phase-14-enterprise.md · integration + e2e |
| PR-012 | SSO identity linking: sso_identities maps (provider, externalId) → user; first SSO login for a known email auto-links, else creates INVITED user |
P2 | 14 | phase-14-enterprise.md · integration |
3.2 Workspaces & tenancy (PS§1, PS§2.1)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-013 | Every registered user automatically gets a personal workspace (owner = user, isPersonal = true) |
P0 | 2 | phase-02-workspace.md · integration + e2e |
| PR-014 | Users can create additional workspaces (name, slug, icon); slug unique platform-wide | P0 | 2 | phase-02-workspace.md · integration + e2e |
| PR-015 | Workspaces can be renamed, re-iconed, and (owner only) deleted with a confirmation cascade preview | P0 | 2 | phase-02-workspace.md · e2e |
| PR-016 | Workspace membership with four roles: Owner, Admin, Member, Guest (RBAC matrix in §4) | P0 | 2 | phase-02-workspace.md · unit + integration |
| PR-017 | Role changes are owner/admin-only; demoting the last Owner is rejected; all changes audited | P0 | 2 | phase-02-workspace.md · integration |
| PR-018 | Email invitations: invite (role, expiry ≤30 d), accept (creates/links user), decline, revoke; one pending invitation per (workspace, email, role) | P0 | 2 | phase-02-workspace.md · integration + e2e |
| PR-019 | Teams (teamspaces): name, slug, color, icon, ordered by fractional position; team membership; pages can live in a team | P0 | 2 | phase-02-workspace.md · integration + e2e |
| PR-020 | Sidebar navigation: Home, Inbox, Search, Favorites, Teamspaces, Private, Shared, Trash — rendered from API, with expand/collapse and page-tree drill-down | P0 | 2 | phase-02-workspace.md · e2e |
| PR-021 | Workspace settings pages: profile, members, teams, security, (billing placeholder, integrations placeholder) | P0 | 2 | phase-02-workspace.md · e2e |
| PR-022 | Organization object groups workspaces; org membership with roles; org-level policies stored as JSON | P2 | 14 | phase-14-enterprise.md · integration |
| PR-023 | SCIM 2.0 user & group provisioning endpoint (create/update/deactivate) for enterprise SSO | P2 | 14 | phase-14-enterprise.md · integration |
| PR-024 | Per-workspace usage limits (JSON: members, storage MB, AI tokens, API rps) enforced at write boundaries | P2 | 14 | phase-14-enterprise.md · integration |
3.3 Pages & page tree (PS§3)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-025 | Page CRUD: create, read, update (title/icon/cover/description), soft delete; title default "" | P0 | 3 | phase-03-pages.md · integration + e2e |
| PR-026 | Pages nest to arbitrary depth via parentId; tree queries use fractional position for sibling order |
P0 | 3 | phase-03-pages.md · unit + integration |
| PR-027 | A page supports: icon (emoji or file id), cover, title, description, properties, blocks, comments, relations, permissions, history, child pages | P0 | 3 | phase-03-pages.md · e2e |
| PR-028 | Trash: soft delete sets trashedAt; restore round-trips parent/position; purge is owner-only and removes blocks/comments/files references |
P0 | 3 | phase-03-pages.md · integration + e2e |
| PR-029 | Archives (archivedAt) separate from trash: archived pages hidden from default views, recoverable without "restore" semantics |
P0 | 3 | phase-03-pages.md · integration |
| PR-030 | Favorites: per-user, ordered (fractional), visible in sidebar; page can be favorited by any viewer with VIEW+ | P0 | 3 | phase-03-pages.md · e2e |
| PR-031 | Page version history: snapshot per significant revision (title, structure, blocks) with author + note; restore to a version creates a new version | P0 | 3 | phase-03-pages.md · integration |
| PR-032 | Private pages (isPrivate) hidden from all but the owner and explicit grants |
P0 | 3 | phase-03-pages.md · integration |
| PR-033 | Page tree loads virtualized: 100k-block workspace tree renders in < 2 s (target NFR-NF1) | P0 | 3 | phase-03-pages.md · perf + e2e |
3.4 Block editor (PS§4, PS§5)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-034 | Editor stores a block tree (stable ids, fractional position, content JSON, properties JSON) — never one HTML document |
P0 | 4 | phase-04-editor.md · unit (codec) + integration |
| PR-035 | Text blocks: paragraph, heading_1, heading_2, heading_3, quote, callout (icon + background color) |
P0 | 4 | phase-04-editor.md · unit + e2e |
| PR-036 | List blocks: bulleted_list, numbered_list (numbering continues across siblings), todo (checkbox state), toggle (collapsed children) |
P0 | 4 | phase-04-editor.md · unit + e2e |
| PR-037 | Media blocks: image (upload, caption, width resize), video (upload or URL), audio (upload, player), file (upload, download card), bookmark (URL preview card), embed (provider iframe) |
P0 (image, file) / P1 (video, audio, bookmark, embed) | 4 / 9 | phase-04-editor.md, phase-09-files.md · e2e |
| PR-038 | Code & equation blocks: code (language select, line numbers, syntax highlight, copy) and equation (KaTeX/MathJax rendering) |
P0 (code) / P1 (equation) | 4 | phase-04-editor.md · e2e |
| PR-039 | Layout blocks: divider, spacer (height), column_list + column (2–4 columns, resizable widths, drag between columns) |
P0 (divider) / P1 (spacer, columns) | 4 | phase-04-editor.md · e2e |
| PR-040 | Advanced blocks: table (static, cell editing), synced_block (master + linked copies), child_page / child_database (sidebar-style row), linked_database (query on another database) |
P0 (table, synced_block) / P1 (child_page, child_database, linked_database) | 4 / 5 | phase-04-editor.md, phase-05-databases.md · e2e |
| PR-041 | Editor keyboard model: Enter (new block), Shift+Enter (soft break), Backspace (merge/delete), Tab/Shift+Tab (indent/unindent), arrows (navigation & caret), Cmd/Ctrl+A (select block then all), C/X/V/Z/Shift+Z, Cmd/Ctrl+B/I/U, Cmd/Ctrl+K (palette) | P0 | 4 | phase-04-editor.md · e2e |
| PR-042 | Mouse interactions: hover controls (drag handle, add-below), select & multi-select (shift/box), context menu, resize (columns/images) | P0 | 4 | phase-04-editor.md · e2e |
| PR-043 | Undo/redo history (in-memory + block versions) survives reload for the session; copy/paste internal (JSON) and external (markdown + HTML) both directions | P0 | 4 | phase-04-editor.md · unit + e2e |
| PR-044 | Every mouse operation has a keyboard/ARIA equivalent (accessibility invariant) | P0 | 4 | phase-04-editor.md · e2e + manual a11y audit |
3.5 Slash commands & context menus (PS§6, PS§7)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-045 | Typing / opens a searchable command menu; commands: /text, /heading 1–3, /quote, /callout, /todo, /bullet, /number, /toggle, /divider, /image, /video, /file, /code, /table, /database, /board, /calendar, /timeline, /chart, /form |
P0 | 4 | phase-04-editor.md · e2e |
| PR-046 | Slash commands create blocks at the caret position, replacing the query; results are grouped (Text, Lists, Media, Data, Layout) and keyboard-navigable | P0 | 4 | phase-04-editor.md · e2e |
| PR-047 | /database (and /board, /calendar, …) opens a property picker and dynamically creates a database block with default properties |
P0 | 4–5 | phase-04-editor.md, phase-05-databases.md · e2e |
| PR-048 | Block context menu: Turn into · Duplicate · Copy · Copy link · Move to · Delete · Comment · Ask AI · Color · Background · Convert to (heading/quote/callout/todo) · More | P0 | 4 | phase-04-editor.md · e2e |
| PR-049 | Page context menu (sidebar + top bar): Open · Open in new tab · Duplicate · Rename · Move · Copy link · Favorite · Archive · Delete · Export · Share · Permissions | P0 | 4–3 | phase-03-pages.md, phase-04-editor.md · e2e |
3.6 Drag & drop (PS§8)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-050 | Block dragging within a page: reorder, nest as child, un-nest; drop indicator (line/box); auto-scroll at viewport edges | P0 | 4 | phase-04-editor.md · e2e + perf (NFR-NF3: < 16 ms local move) |
| PR-051 | Multi-block drag (shift-click range) moves as a unit; relative ordering preserved | P0 | 4 | phase-04-editor.md · e2e |
| PR-052 | Cross-page drag: drop a block onto a sidebar page (or into a child_page/child_database block) to move it; drag between columns |
P0 | 4 | phase-04-editor.md · e2e |
| PR-053 | Database row dragging: reorder rows (table), move cards across board columns (status change = property update) | P0 | 5 | phase-05-databases.md · e2e |
| PR-054 | Sidebar page dragging: reorder + reparent pages in the tree | P0 | 4–3 | phase-04-editor.md · e2e |
| PR-055 | File/image drop from OS into editor or database property cell creates a file block / files property value | P0 | 9 | phase-09-files.md · e2e |
| PR-056 | All DnD uses dnd-kit with drop animations and non-drag keyboard alternative ("Move to" in context menus, arrow-key move in tables/boards) | P0 | 4 | phase-04-editor.md · e2e |
3.7 Databases (PS§9)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-057 | Database = named container with typed properties, records, views; embedded in pages via database block or standalone |
P0 | 5 | phase-05-databases.md · integration + e2e |
| PR-058 | 24 property types: Title, Text, Rich Text, Number, Select, Multi Select, Status, Date, Date Range, Person, Email, Phone, URL, Checkbox, Files, Created Time, Created By, Last Edited Time, Last Edited By, Relation, Rollup, Formula, Button, Unique ID | P0 (core 15: Title, Text, Rich Text, Number, Select, Multi Select, Status, Date, Date Range, Person, Checkbox, Files, Unique ID, Created/Last-Edited ×4) / P1 (Email, Phone, URL, Relation*, Rollup*, Formula*, Button*) — *land in Phase 6 | 5 / 6 | phase-05-databases.md, phase-06-relations.md · unit + integration |
| PR-059 | Exactly one TITLE property per database; renaming/deleting the title property is blocked | P0 | 5 | phase-05-databases.md · unit |
| PR-060 | Records: each record is 1:1 with a page (database_records.pageId); the record page shows all properties above its block content |
P0 | 5 | phase-05-databases.md · integration + e2e |
| PR-061 | Record create (inline row, "Add new", from form, from API), update (inline cell edit), archive (soft), duplicate | P0 | 5 | phase-05-databases.md · integration + e2e |
| PR-062 | Table view: virtualized 100k+ rows; inline editing per type; row height; column width + visibility; row hover actions; multi-select rows | P0 | 5 | phase-05-databases.md · e2e + perf (NFR-NF1) |
| PR-063 | List view: minimal rows (title + 2 properties), fast scan | P1 | 5 | phase-05-databases.md · e2e |
| PR-064 | Board view: group-by one property (required, default status); kanban columns; card shows selected properties; add/edit/reorder cards; WIP optional | P0 | 5 | phase-05-databases.md · e2e |
| PR-065 | Calendar view: day/week/month; date or date-range properties; multi-day bars; click-day → new record | P1 | 5 | phase-05-databases.md · e2e |
| PR-066 | Gallery view: card grid with cover/icon, title, selected properties; card layout config (cover on/off, size, property rows) | P1 | 5 | phase-05-databases.md · e2e |
| PR-067 | Timeline view: Gantt-style bars from date-range (or date + duration); zoom levels; today marker | P1 | 5 | phase-05-databases.md · e2e |
| PR-068 | Chart view + Dashboard view as first-class view types composing widgets/charts | P1 | 5 / 12 | phase-05-databases.md, phase-12-ai.md (adjacent) · e2e |
| PR-069 | Form view: published form over the database (see Forms §) | P1 | 10 | phase-10-forms.md · e2e |
| PR-070 | Per-view settings: filters, sort, group, visible properties, column widths, card layout, color, density, page size | P0 | 5 | phase-05-databases.md · e2e |
| PR-071 | Filters: nested boolean tree — AND / OR / NOT groups with conditions (property, operator, value); 20+ operators per type (e.g. contains, before, is empty, is within) |
P0 | 5 | phase-05-databases.md · unit (golden datasets) + integration |
| PR-072 | Sort: multi-key (property, direction ASC/DESC); nulls first/last | P0 | 5 | phase-05-databases.md · unit |
| PR-073 | Group: multi-level grouping by property; collapsible groups; group counts | P0 | 5 | phase-05-databases.md · unit |
| PR-074 | Database property management: add/rename/reorder (fractional)/hide/delete properties; delete keeps values until records gone; type change with lossless conversions only | P0 | 5 | phase-05-databases.md · integration |
3.8 Relations, rollups, formulas, buttons (PS§9.4–9.7)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-075 | Relations between databases: ONE_TO_ONE, ONE_TO_MANY, MANY_TO_MANY; bidirectional with named reverse property; link/unlink records from either side | P0 | 6 | phase-06-relations.md · unit + integration + e2e |
| PR-076 | Relation cells show linked record titles (multi-select popover, search); reverse side updates automatically | P0 | 6 | phase-06-relations.md · e2e |
| PR-077 | Rollups: COUNT, SUM, AVERAGE, MIN, MAX, PERCENT, UNIQUE over a relation's target property, with optional filter | P1 | 6 | phase-06-relations.md · unit (golden) + integration (event-driven recompute) |
| PR-078 | Rollup values recompute on relation/link/property change via domain events (no polling) | P1 | 6 | phase-06-relations.md · integration |
| PR-079 | Formula engine: safe parser → AST → evaluator; never arbitrary JavaScript/eval |
P1 | 6 | phase-06-relations.md · unit (100% function coverage, fuzzing) |
| PR-080 | Formula functions: if, and, or, not, sum, average, min, max, dateAdd, dateBetween, now, concat, replace, contains, length, plus prop("Name") accessor and literals (string/number/bool/date) |
P1 | 6 | phase-06-relations.md · unit |
| PR-081 | Formulas declare dependencies (property ids); recomputed when any dependency changes; inferred return type (number/text/bool/date/array) |
P1 | 6 | phase-06-relations.md · unit + integration |
| PR-082 | Database buttons: run an action sequence — set property, create page, update page, archive page, duplicate page, send webhook, trigger automation | P1 | 6 | phase-06-relations.md · integration + e2e |
| PR-083 | Button config validated server-side; actions execute with the invoking user's permissions; execution logged | P1 | 6 | phase-06-relations.md · integration |
3.9 Collaboration, realtime (PS§13, PS§25)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-084 | Realtime WebSocket server: rooms per (workspace, page/database); token auth; heartbeat 30 s; stale peer pruning; per-connection rate limits | P1 | 7 | phase-07-collaboration.md · integration + e2e |
| PR-085 | Yjs CRDT sync of the block tree: multi-user concurrent edits, server-authoritative doc hydrated from Postgres, debounced persistence | P1 | 7 | phase-07-collaboration.md · unit (codec) + integration + e2e |
| PR-086 | Presence: avatars in top bar, "who is here", live cursors with name + color, awareness via Yjs protocol | P1 | 7 | phase-07-collaboration.md · e2e |
| PR-087 | Realtime propagation latency < 200 ms p95 (local deployment) — target NFR-NF6 | P1 | 7 | phase-07-collaboration.md · perf |
| PR-088 | Realtime comments: comment threads update participants live over the socket | P1 | 7 | phase-07-collaboration.md · e2e |
| PR-089 | Reconnection with Yjs update resume (Redis update log, truncated after persistence); backpressure on slow clients | P1 | 7 | phase-07-collaboration.md · integration |
| PR-090 | Offline mode: edits buffered in IndexedDB (Yjs local-first), queue synced on reconnect, CRDT conflict resolution, offline indicator | P1 | 7 | phase-07-collaboration.md · e2e |
3.10 Comments, mentions, notifications (PS§14)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-091 | Comments attach to: page, block, text selection (anchor/offset), database record | P0 | 3 (page/block) / 5 (record) / 7 (selection) | phase-03-pages.md, phase-05-databases.md, phase-07-collaboration.md · integration + e2e |
| PR-092 | Comment threads: create, reply, resolve, reopen, edit (own), delete (own or admin); status open/resolved/reopened | P0 | 3 | phase-03-pages.md · integration + e2e |
| PR-093 | Comment reactions: emoji on comments and replies, one per (target, user, emoji) | P0 | 3 | phase-03-pages.md · e2e |
| PR-094 | Mentions: @user, @team, @page, @database with searchable popup; mention notifies the target |
P0 | 7 | phase-07-collaboration.md · integration + e2e |
| PR-095 | Notifications (in-app, email, webhook channels) for: mention, comment, assignment, page shared, task assigned, database change, automation, integration | P0 (in-app mention/comment) / P1 (email + full set) | 7 | phase-07-collaboration.md · integration + e2e |
| PR-096 | Inbox: unread list, mark read (single/all), deep links, notification preferences per type + quiet hours | P0 | 7 | phase-07-collaboration.md · e2e |
| PR-097 | Mention notifications track read state independently (mention_notifications) |
P0 | 7 | phase-07-collaboration.md · integration |
3.11 Search (PS§15)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-098 | Search everything in a workspace: pages, blocks, databases, records, comments, files, users | P0 | 8 | phase-08-search.md · integration + e2e |
| PR-099 | Full-text (BM25) + prefix + fuzzy matching via OpenSearch analyzers/queries | P0 | 8 | phase-08-search.md · integration |
| PR-100 | Search filters: type, workspace/team, updated date, creator; result snippets with highlighted matches | P0 | 8 | phase-08-search.md · e2e |
| PR-101 | Recent searches + suggestions (typeahead) in search UI and command palette | P0 | 8 | phase-08-search.md · e2e |
| PR-102 | Index pipeline: domain events → indexer worker → OpenSearch; index lag < 30 s; periodic reconciliation job | P0 | 8 | phase-08-search.md · integration + perf |
| PR-103 | Search results are permission-filtered at query time (visibility snapshot per document) | P0 | 8 | phase-08-search.md · integration |
| PR-104 | Search response < 500 ms p95 — target NFR-NF4 | P0 | 8 | phase-08-search.md · perf |
3.12 Files (PS§16)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-105 | S3-compatible storage (MinIO in dev); private buckets; presigned upload (multipart for large files) and short-lived signed download URLs | P0 | 9 | phase-09-files.md · integration + e2e |
| PR-106 | File pipeline: upload → virus scan (ClamAV) → metadata extraction (mime, dimensions, duration, page count, hashes) → thumbnail/preview → DB metadata; status machine UPLOADING→SCANNING→READY/FAILED | P0 | 9 | phase-09-files.md · integration |
| PR-107 | Supported kinds: images, PDF, documents (docx/xlsx/pptx/md/txt), video, audio, archives, attachments; previews per kind | P0 (image, pdf, doc, txt) / P1 (video, audio, xlsx, archives) | 9 | phase-09-files.md · e2e |
| PR-108 | Virus-detected files quarantined (VIRUS_DETECTED), never served; admin sees scan report |
P0 | 9 | phase-09-files.md · integration |
| PR-109 | File metadata: name, size, mime, uploader, versions (file_versions), trash, per-file permission overrides |
P0 | 9 | phase-09-files.md · integration + e2e |
| PR-110 | Files usable in editor (image/file blocks), database (Files property), and form answers |
P0 | 9 | phase-09-files.md · e2e |
| PR-111 | 500 MB file upload works (multipart); per-plan size quotas enforced | P0 | 9 | phase-09-files.md · integration + perf |
3.13 Permissions & sharing (PS§17, PS§18)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-112 | RBAC workspace roles (Owner/Admin/Member/Guest) define base capability; see §4 | P0 | 2 | phase-02-workspace.md, phase-03-pages.md · unit (permission engine) |
| PR-113 | Resource-level permissions: None / View / Comment / Edit / Full Access at workspace, teamspace, page, database, record, file | P0 | 3 | phase-03-pages.md · unit (decision matrix) + integration |
| PR-114 | Effective level = max(role_base, explicit grants), computed by walking up the page tree (child inherits parent grants unless a nearer explicit grant overrides) | P0 | 3 | phase-03-pages.md · unit (engine property tests) |
| PR-115 | Every backend operation re-validates server-side; frontend checks are UX-only | P0 | 2 | all phases · integration (unauthorized-access suite) |
| PR-116 | Grant management UI: share dialog (scope picker), granular "Can edit / Can view / …", inherit indicators, remove grant | P0 | 3 | phase-03-pages.md · e2e |
| PR-117 | Share scopes: private, workspace, team, specific users, public — one Share row per token |
P0 | 3 | phase-03-pages.md · integration |
| PR-118 | Public pages: https://<host>/share/<token>; options: allow comments, allow duplicate, allow search indexing, password, expiration |
P0 | 3 | phase-03-pages.md · e2e |
| PR-119 | Permission + share changes audited (permission.changed, page.shared) |
P0 | 3 | phase-03-pages.md · integration |
| PR-120 | Advanced permission policy expressions (enterprise) + guest restrictions (no export, no share) | P2 | 14 | phase-14-enterprise.md · unit + integration |
3.14 Templates (PS§19)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-121 | Template types: workspace, database, page, team; built-in + user templates; frozen snapshot at creation | P1 | 10 | phase-10-forms.md (adjacent) / phase-05-databases.md · integration + e2e |
| PR-122 | "New from template" materializes a new page/database (new ids, relations intact) without touching the source | P1 | 10 | phase-05-databases.md · integration |
| PR-123 | Template browser in page/database creation flows (slash menu, sidebar "+") | P1 | 10 | phase-05-databases.md · e2e |
3.15 Import / export (PS§20)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-124 | Import: Markdown, HTML, CSV, JSON, Notion export (zip); pipeline upload → parser → normalizer → block/db conversion → validation → import | P1 | 10 | phase-10-forms.md (adjacent) · unit (parsers) + integration |
| PR-125 | Export: Markdown, HTML, PDF, CSV (database), JSON (page/database) — per page, database, or team | P1 | 10 | phase-10-forms.md (adjacent) · integration + e2e |
| PR-126 | Imports are permission-checked and audited; large imports run as jobs with progress | P1 | 10 | phase-10-forms.md (adjacent) · integration |
3.16 Forms (PS§11)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-127 | Form builder: questions (SHORT_TEXT, LONG_TEXT, NUMBER, EMAIL, DATE, CHECKBOX, SINGLE_SELECT, MULTI_SELECT, RATING, FILE), required flag, validation config, property mapping | P1 | 10 | phase-10-forms.md · e2e |
| PR-128 | Public form pages (unique slug, branding/intro/success message, closed state); submission works without authentication | P1 | 10 | phase-10-forms.md · e2e |
| PR-129 | Submission creates a database record + FormSubmission row; fires form.submitted event (drives automations/webhooks) |
P1 | 10 | phase-10-forms.md · integration |
| PR-130 | Form responses view: table of submissions, view as record, delete | P1 | 10 | phase-10-forms.md · e2e |
3.17 Dashboards & charts (PS§12)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-131 | Charts: bar, line, area, pie, donut, number; config: x-axis, y-axis, group by, filter, aggregation, color, legend; bound to a database | P1 | 10 | phase-10-forms.md (adjacent) · e2e |
| PR-132 | Dashboards: widget grid (table, board, chart, number, calendar, timeline, text, linked database); widgets resizable, draggable, configurable, filterable | P1 | 10 | phase-10-forms.md (adjacent) · e2e |
| PR-133 | Dashboard can be published as a public read-only page | P1 | 10 | phase-10-forms.md (adjacent) · e2e |
3.18 Automation (PS§10)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-134 | Automation = trigger(s) → conditions → action(s), executed via BullMQ workers; statuses DRAFT/ACTIVE/PAUSED/ARCHIVED | P1 | 11 | phase-11-automation.md · integration + e2e |
| PR-135 | Triggers: RECORD_CREATED, RECORD_UPDATED, PROPERTY_CHANGED, PAGE_CREATED, FORM_SUBMITTED, SCHEDULE (cron), WEBHOOK, MANUAL | P1 | 11 | phase-11-automation.md · integration |
| PR-136 | Actions: UPDATE_RECORD, CREATE_PAGE, SEND_EMAIL, SEND_WEBHOOK, CREATE_NOTIFICATION, ASSIGN_USER, CHANGE_STATUS, CALL_INTEGRATION, RUN_AI_ACTION | P1 | 11 | phase-11-automation.md · integration |
| PR-137 | Execution: retries with exponential backoff (max 8), dead-letter queue, per-action timeout (default 30 s) | P1 | 11 | phase-11-automation.md · integration |
| PR-138 | Every run recorded (automation_runs + automation_logs: status, input, output, error, timing) with history UI |
P1 | 11 | phase-11-automation.md · e2e |
| PR-139 | Trigger matcher + condition evaluator are pure, unit-tested functions; automation runs carry the actor's permissions | P1 | 11 | phase-11-automation.md · unit + integration |
| PR-140 | Automation execution audit event (automation.executed) |
P1 | 11 | phase-11-automation.md · integration |
3.19 AI (PS§21)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-141 | AI gateway with provider abstraction: OpenAI, Anthropic, Google, OSS (vLLM/Ollama), custom OpenAI-compatible; unified chat/embed/tools API; provider swap changes zero app code | P1 | 12 | phase-12-ai.md · unit + integration |
| PR-142 | Ask AI (chat) with workspace context; conversation history persisted | P1 | 12 | phase-12-ai.md · e2e |
| PR-143 | Page AI: summarize, rewrite, improve writing, translate (selection or block level) | P1 | 12 | phase-12-ai.md · e2e |
| PR-144 | Database AI: generate database from description, extract data into records, generate formula | P1 | 12 | phase-12-ai.md · integration |
| PR-145 | RAG workspace search: content chunker → embeddings → vector store → hybrid (BM25 + semantic + metadata) → LLM answer with source citations | P1 | 12 | phase-12-ai.md · integration + e2e |
| PR-146 | AI generation (page, database, template, tasks) via structured tool calls — never raw SQL or raw block mutation; generated output validated against Zod schemas | P1 | 12 | phase-12-ai.md · integration |
| PR-147 | All AI calls logged (provider, model, tokens in/out, latency); per-workspace token budgets enforced | P1 | 12 | phase-12-ai.md · integration |
3.20 Public API & webhooks (PS§22)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-148 | REST API v1: pages CRUD, databases (GET /databases/:id, POST /databases/:id/query, POST /databases/:id/records), search (POST /search), files (POST /files), records, comments, workspaces |
P1 | 13 | phase-13-api.md · integration + e2e |
| PR-149 | API keys: workspace-scoped, scopes READ/WRITE/ADMIN, hashed at rest (raw key shown once), per-key rate limit, expiry, revocation | P1 | 13 | phase-13-api.md · integration + e2e |
| PR-150 | OAuth2 (authorization code) for third-party apps | P1 | 13 | phase-13-api.md · integration |
| PR-151 | Webhooks: subscribe to `page.created | updated | deleted, database.created |
updated, record.created |
| PR-152 | OpenAPI 3 spec generated and CI-checked against live endpoints; interactive docs at /docs |
P1 | 13 | phase-13-api.md · CI contract test |
| PR-153 | API errors use the standard ApiError envelope with stable codes; API-key auth E2E-tested |
P1 | 13 | phase-13-api.md · e2e |
3.21 Enterprise (PS§2.3)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-154 | Audit log: mandatory event catalog (actor type/id, workspace, resource, action, timestamp, IP, UA, metadata); viewer with filters + export (CSV/JSON) | P2 | 14 | phase-14-enterprise.md · integration + e2e |
| PR-155 | Organization policies: enforced security settings (password policy, SSO enforce, public-sharing toggle) | P2 | 14 | phase-14-enterprise.md · integration |
| PR-156 | Data retention policies: PURGE / HOLD per scope (comments, trash, audit_logs, files) with retainDays; nightly retention job |
P2 | 14 | phase-14-enterprise.md · integration |
| PR-157 | Admin console: org overview, usage, members, policies, SSO config | P2 | 14 | phase-14-enterprise.md · e2e |
3.22 Platform & hardening (PS§24, PS§26, PS§27)
| ID | Requirement | Priority | Phase | Verified by |
|---|---|---|---|---|
| PR-158 | Security baseline: security headers (CSP, HSTS, X-Frame-Options), secure cookies (HttpOnly/SameSite=Lax), CSRF protection, CORS allow-list, rate limiting tiers — see security-architecture | P0 | 1 (core) / 15 (full audit) | phase-01-authentication.md, phase-15-production.md · integration + security scan |
| PR-159 | Performance: initial page load < 2 s, editor interaction < 50 ms, local block move < 16 ms, search < 500 ms, API p95 < 300 ms, realtime update < 200 ms; 100k-record databases without full render | P0 | 3/4/5 (targets) / 15 (load proof) | phase-15-production.md · perf |
| PR-160 | Scalability: 10k concurrent WS editors, 1k rps API, 100k-record queries within NFR budgets | P1 | 15 | phase-15-production.md · perf |
| PR-161 | Reliability: 99.9% API availability SLO; graceful degradation — realtime down ⇒ polling fallback + banner; search down ⇒ "search unavailable" empty state, app keeps working | P1 | 15 | phase-15-production.md · manual/ops + integration (chaos) |
| PR-162 | Observability: OpenTelemetry traces/metrics, Prometheus + Grafana dashboards, Loki logs, alerting (latency, queue depth, WS count, error rate) | P2 | 15 | phase-15-production.md · manual/ops |
| PR-163 | Backup/DR: Postgres PITR + S3 versioning + OpenSearch snapshots; RPO ≤ 5 min, RTO ≤ 1 h; restore drill documented and executed | P2 | 15 | phase-15-production.md · manual/ops (runbook) |
| PR-164 | Theming: light / dark / system via design tokens (CSS variables); no hard-coded colors in app code | P0 | 0 | phase-00-foundation.md · manual/ops + e2e (visual smoke) |
| PR-165 | Accessibility: WCAG 2.2 AA — keyboard navigation, ARIA, focus management, reduced motion, high contrast, accessible menus/dialogs, non-drag DnD alternatives | P0 | 4 (editor) / ongoing | phase-04-editor.md · e2e + manual a11y audit (axe) |
| PR-166 | Internationalization readiness: all user-facing strings extractable (i18n keys), date/number formatting via user locale + timezone, no hard-coded English in code paths | P2 | 15 | phase-15-production.md · lint rule + manual/ops |
| PR-167 | Browser support: latest 2 major versions of Chrome, Edge, Firefox, Safari (desktop) + responsive behavior on tablet/mobile | P0 | 0 | phase-00-foundation.md · e2e (Playwright matrix) |
4. Role capability matrix
Workspace RBAC baseline (before resource-level grants; resource grants can raise a level above the baseline, never silently grant what a role withholds at the workspace root).
| Capability | Owner | Admin | Member | Guest |
|---|---|---|---|---|
| Manage workspace (rename, settings, delete) | ✅ | ✅ | — | — |
| Manage members & roles | ✅ | ✅ | — | — |
| Invite members (any role) | ✅ | ✅ (≤ Member) | — | — |
| Manage teams | ✅ | ✅ | — | — |
| Create/edit pages in own spaces | ✅ | ✅ | ✅ | — (only where granted) |
| Create/edit pages anywhere in workspace | ✅ | ✅ | ✅ | — |
| Comment on pages | ✅ | ✅ | ✅ | ✅ (where ≥ Comment) |
| View pages | ✅ | ✅ | ✅ (non-private) | only where granted |
| Delete pages | ✅ | ✅ | own pages | — |
| Manage permissions/sharing of a page | ✅ | ✅ | page creator/editors (Full Access) | — |
| Manage databases (properties, views) | ✅ | ✅ | ✅ | — |
| Create API keys | ✅ | ✅ | — | — |
| Manage webhooks & integrations | ✅ | ✅ | — | — |
| View audit log | ✅ | ✅ (workspace events) | — | — |
| Purge trash | ✅ | ✅ (30-day-old items) | own items | — |
| Export workspace | ✅ | ✅ | — | — |
| View AI usage / set budgets | ✅ | ✅ | — | — |
Inheritance rule (mirrors PR-114): effective access to a resource =
max(role_base(level), explicit_grants along the page-tree path from root to resource). ANoneexplicit grant is an override that wins over inheritance (it is not the same as "no grant"). The full algorithm is in security-architecture §4.
5. MVP boundary
First production milestone = Phases 0–9 (partial), per ROADMAP.md:
5.1 In the MVP (all P0 above)
| Area | Included |
|---|---|
| Auth | Register, verify, login, logout, refresh rotation, password reset, profile, sessions (PR-001…PR-010) |
| Workspace | Personal + team workspaces, members/roles, invitations, teams, sidebar, settings (PR-013…PR-021) |
| Pages | CRUD, nesting, tree, trash/restore, archives, favorites, versions, permissions, sharing incl. public (PR-025…PR-033, PR-112…PR-119) |
| Editor | All P0 block types, drag & drop, slash menu, context menus, keyboard shortcuts, undo/redo, copy/paste (PR-034…PR-056) |
| Databases | Core 15 property types, records-as-pages, table view + board view, filters/sort/group, per-view settings (PR-057…PR-064, PR-070…PR-074) |
| Relations | Bidirectional relations + relation links (PR-075, PR-076) |
| Search | Indexer + full-text/prefix/fuzzy + filters + UI + permission filtering (PR-098…PR-104) |
| Files | S3 pipeline, upload/download, previews, versions, permissions (PR-105…PR-111) |
| Collaboration (basic) | Comments + mentions + in-app notifications; realtime CRDT arrives Phase 7 (PR-091…PR-097 P0 parts) |
| Platform | Security baseline, theming, a11y, browser support, perf budgets (PR-158, PR-159, PR-164…PR-167) |
5.2 After the MVP (explicitly not in the first release)
Calendar / Timeline / Gallery / List views, rollups, formulas, database buttons, dashboards & charts (full), forms, automation, realtime collaboration (Yjs presence/cursors/offline), AI gateway + RAG, public API + webhooks, import/export, templates (full), enterprise (SSO/SCIM/audit viewer/ retention/admin console), production hardening suite (load, DR, observability dashboards).
5.3 Out of scope (not planned for v1)
| Item | Reason / deferral |
|---|---|
| Mobile native apps (iOS/Android) | Responsive web is v1; native is post-v1 |
| Offline sync for non-editor data (databases) beyond CRDT edits | v1 offline = editor + local Yjs docs; full offline DB sync is v2 |
| Email-in (inbox → page) | Post-v1 integration |
| Marketplace for community templates | Post-v1 |
| In-editor whiteboard / canvas mode | Post-v1 |
| Multi-language UI translations (beyond i18n readiness) | PR-166 makes it cheap; actual translation catalogs post-v1 |
| Fine-grained row-level API scoping (API key per database) | v2 API refinement |
| On-prem Windows deployment | Self-host target is Linux containers |
6. Cross-document map
| Document | Owns |
|---|---|
PRODUCT-SPEC.md (root) |
Authoritative summary; section numbers cited here as PS§n |
| functional-requirements.md | Exhaustive per-domain FR text, all IDs expanded |
| ux-requirements.md | Layout, interactions, states, shortcuts, a11y |
| non-functional-requirements.md | Measurable targets (NFR-NF1…) with methods |
| ../security/security-architecture.md | Authn/authz/transport/file/audit deep design |
| ../database/database-architecture.md | Authoritative schema reference |
| ../requirements/requirements-matrix.md | PR → task/phase/status traceability |
| ../ui/design-system.md | Tokens, components, visual specs |