.github/9
ISSUE_TEMPLATE/3bug_report.md config.yml feature_request.md
workflows/3ci.yml clean-clone.yml release.yml
CODEOWNERS dependabot.yml pull_request_template.md
apps/630
api/250
src/243
common/30
__tests__/3authorize.test.ts bigint-serialization.interceptor.test.ts files-limits.test.ts
filters/1all-exceptions.filter.ts
guards/3auth.guard.ts internal-service.guard.ts rate-limit.guard.ts
interceptors/2actor-context.interceptor.ts bigint-serialization.interceptor.ts
middleware/2idempotency.test.ts idempotency.ts
pipes/1zod-validation.pipe.ts
actor-context.ts audit.service.ts cache.test.ts cache.ts cookies.ts core.module.ts deprecation.ts email.service.ts errors.ts event-bus.ts log-scrubber.test.ts log-scrubber.ts logger.ts permission-cache-bridge.ts prisma.service.ts redis.service.ts trace-metadata.ts types.ts
config/1env.ts
lib/11
__tests__/5crypto.test.ts filter-builder.test.ts jwt.test.ts pagination.test.ts positions.test.ts
authorize.ts crypto.ts filter-builder.ts jwt.ts pagination.ts positions.ts
modules/197
ai/28
__tests__/4ai-writing.test.ts database-ai.test.ts generate-executor.test.ts prompts.test.ts
generator/4executor.ts generate.controller.ts generate.dto.ts generate.service.ts
ai-chat.service.ts ai-rate-limit.ts ai-writing.controller.ts ai-writing.dto.ts ai-writing.service.ts ai.controller.ts ai.module.ts ai.service.ts budget-guard.service.ts database-ai.controller.ts database-ai.dto.ts database-ai.service.ts db-prompts.ts dto.ts gateway-provider.ts ledger.service.ts prompts.ts rag.controller.ts rag.dto.ts rag.service.ts
api-keys/3api-keys.controller.ts api-keys.module.ts api-keys.service.ts
audit/2audit-log.controller.ts audit.module.ts
auth/4auth.controller.ts auth.module.ts auth.service.ts dto.ts
automations/5automations.controller.ts automations.module.ts automations.service.ts dto.ts webhook-incoming.controller.ts
blocks/5
__tests__/1batch-version-cas.test.ts
block.service.ts blocks.controller.ts blocks.module.ts dto.ts
comments/4comments.controller.ts comments.module.ts comments.service.ts dto.ts
databases/9
__tests__/3normalize-select-options.test.ts option-id-canonicalization.test.ts record-open-query-shape.test.ts
database.service.ts databases.controller.ts databases.module.ts dto.ts property-cache-schema.ts query.service.ts
docs/2docs.controller.ts docs.module.ts
files/10
__tests__/1quota.test.ts
dto.ts files.controller.ts files.module.ts files.service.ts quota.ts record.ts s3.ts uploads.controller.ts uploads.service.ts
forms/18debug.controller.ts form.dto.ts forms.controller.ts forms.module.ts forms.service.ts markdown.test.ts markdown.ts optional-auth.guard.ts public-forms.controller.ts public-forms.service.ts question.dto.ts questions.service.ts rate-limit.ts recaptcha.ts slug.ts submissions.controller.ts submissions.service.ts submit-schema.ts
health/3health.controller.ts health.module.ts health.service.ts
integrations/3integrations.controller.ts integrations.module.ts integrations.service.ts
internal/12
__tests__/2flush-query-shape.test.ts internal.endpoints.test.ts
ai-test-seam.controller.ts ai-test-seam.dto.ts ai-test-seam.service.ts internal.controller.ts internal.dto.ts internal.module.ts internal.service.ts test-seam.controller.ts test-seam.dto.ts test-seam.service.ts
notifications/3notifications.controller.ts notifications.module.ts notifications.service.ts
oauth/6
__tests__/1oauth.scopes.test.ts
oauth.controller.ts oauth.module.ts oauth.service.ts scopes.ts token-keys.ts
org/15audit.service.ts embed-preview.controller.ts guards.ts members.service.ts org-admin.controller.ts org-policy.service.ts org.module.ts overview.service.ts policy-effective.controller.ts policy.schema.ts policy.test.ts retention.service.ts totp.test.ts totp.ts two-factor.service.ts
orgs/5dto.ts orgs.controller.ts orgs.module.ts orgs.service.ts util.ts
pages/4dto.ts page.service.ts pages.controller.ts pages.module.ts
scim/15
__tests__/3email-mapping.test.ts etag.test.ts filters.test.ts
etag.ts filters.ts groups.service.ts schemas.ts scim-admin.controller.ts scim-admin.service.ts scim-auth.guard.ts scim-auth.service.ts scim-errors.ts scim.controller.ts scim.module.ts users.service.ts
search/4
__tests__/1search.service.test.ts
search.controller.ts search.module.ts search.service.ts
sessions/3sessions.controller.ts sessions.module.ts sessions.service.ts
share/3share.controller.ts share.module.ts share.service.ts
sso/16
__tests__/4enforcement.test.ts oidc.verify.test.ts provisioning.test.ts saml.validate.test.ts
enforcement.ts oidc.controller.ts oidc.service.ts oidc.ts provisioning.service.ts saml.controller.ts saml.ts schemas.ts sso-admin.controller.ts sso-admin.service.ts sso-secrets.ts sso.module.ts
teams/4dto.ts teams.controller.ts teams.module.ts teams.service.ts
users/4dto.ts users.controller.ts users.module.ts users.service.ts
webhooks/3webhooks.controller.ts webhooks.module.ts webhooks.service.ts
workspaces/4dto.ts workspaces.controller.ts workspaces.module.ts workspaces.service.ts
types/1xmldom.d.ts
app.module.ts constants.ts main.ts
_probe_rawbody.cjs .env.example Dockerfile package.json README.md tsconfig.json vitest.config.ts
realtime/33
src/17auth.ts comments.ts config.ts event-source.ts http-store.ts index.ts metrics.ts notifications.ts page-updated-source.ts presence.ts prisma-store.ts protocol.ts rate-limit.ts room-key.ts rooms.ts server.ts update-log.ts
test/11auth.test.ts config.test.ts event-source.test.ts http-store.test.ts metrics-merge.test.ts page-updated-source.test.ts presence.test.ts protocol.test.ts rate-limit.test.ts rooms.test.ts task-0094-builders.test.ts
.env.example Dockerfile package.json README.md tsconfig.json
web/255
src/244
app/45
__tests__/1theme-tokens.test.ts
(app)/26
w/25
[workspace]/25
ask/1page.tsx
databases/1
[id]/1page.tsx
favorites/1page.tsx
files/1page.tsx
notifications/1page.tsx
page/4
[id]/4
[block]/1page.tsx
share/1page.tsx
layout.tsx page.tsx
search/1page.tsx
settings/10
appearance/1page.tsx
automations/3
[id]/1page.tsx
new/1page.tsx
page.tsx
billing/1page.tsx
developers/1page.tsx
members/1page.tsx
permissions/1page.tsx
teams/1page.tsx
page.tsx
shared/1page.tsx
templates/1page.tsx
trash/1page.tsx
layout.tsx page.tsx
layout.tsx
(auth)/4
login/1page.tsx
register/1page.tsx
reset-password/1page.tsx
layout.tsx
api/2
metrics/1route.ts
v1/1
health/1route.ts
f/1
[slug]/1page.tsx
health/1
ready/1route.ts
org/2
[orgId]/2
admin/2
integrations/1page.tsx
page.tsx
share/1
[id]/1page.tsx
error.tsx global-error.tsx globals.css layout.tsx not-found.tsx page.tsx providers.tsx
components/118
admin/10
org-admin/8ApiKeysTab.tsx AuditTab.tsx MembersTab.tsx OverviewTab.tsx PoliciesTab.tsx RetentionTab.tsx WebhooksTab.tsx WorkspacePicker.tsx
ScimCard.tsx SsoTabs.tsx
ai/6ai-panel.tsx ask-ai-submenu.tsx db-ai-dialog.tsx generate-page-dialog.tsx writing-actions-menu.tsx writing-diff.tsx
automations/5action-editor.tsx condition-editor.tsx lib.ts run-history.tsx trigger-editor.tsx
collaboration/6CursorLayer.tsx OfflineBanner.tsx PresenceBar.tsx README.md ReviewFailedDialog.tsx StatusChip.tsx
comments/3comment-panel.tsx comment-thread.tsx mention-input.tsx
database/27
__tests__/2cell-editor.test.tsx cell-renderer.test.tsx
AiExtractDialog.tsx AiFormulaDialog.tsx AiGenerateDialog.tsx board-view.tsx buttons-panel.tsx calendar-view.tsx cell-editor.tsx cell-renderer.tsx chart-view.tsx database-page-view.tsx database-toolbar.tsx database-view-renderer.tsx db-embedded.tsx filter-builder.tsx form-builder-view.tsx formula-editor.tsx gallery-view.tsx group-builder.tsx list-view.tsx property-editor.tsx record-header.tsx record-panel.tsx sort-builder.tsx table-view.tsx timeline-view.tsx
dialogs/7
__tests__/1move-to-dialog.test.tsx
create-dialog.tsx dialog.tsx file-permissions-dialog.tsx invite-dialog.tsx move-to-dialog.tsx share-dialog.tsx
editor/19
__tests__/3code-block-text.test.ts code-block.test.tsx expandable.test.tsx
block-card.tsx block-renderer.tsx block-save-queue.ts block-toolbar.tsx context-menu.tsx expandable.tsx history-popover.tsx inline-editor.tsx insert-dialog.tsx page-canvas.tsx page-spinner.tsx page-view.tsx selection-toolbar.tsx slash-menu.tsx template-dialog.tsx type-menu.tsx
files/4FileBlock.tsx FileBrowser.tsx FilePicker.tsx PreviewModal.tsx
form/4form-field.tsx form-renderer.tsx form-responses-view.tsx form-view.tsx
layout/8
__tests__/1page-tree-icon.test.tsx
command-palette.tsx factory-logo.tsx page-tree-node.tsx sidebar.tsx theme-provider.tsx topbar.tsx workspace-shell.tsx
mentions/3
__tests__/1mention-model.test.ts
mention-model.ts MentionPopup.tsx
search/3ask-ai-search.tsx results-list.tsx search-dialog.tsx
settings/10
api-keys/4ApiKeyCreateDialog.tsx ApiKeyRevealDialog.tsx ApiKeyTable.tsx ScopesBadge.tsx
webhooks/5CurlExamples.tsx DeliveryInspector.tsx EventExplorer.tsx OverviewTab.tsx WebhooksTab.tsx
settings-shell.tsx
ui/3confirm-dialog.tsx form.tsx toaster.tsx
hooks/21
__tests__/4realtime-frame-handler.test.ts use-blocks.test.ts use-database-options.test.ts use-workspace.test.tsx
realtime-frame-handler.ts use-ai-stream.ts use-auth.ts use-blocks.ts use-database.ts use-db-ai-stream.ts use-forms.ts use-members.ts use-mention-sources.ts use-notifications.ts use-offline-status.ts use-pages.ts use-presence-announcer.ts use-presence-toasts.ts use-presence.ts use-realtime.ts use-workspace.ts
lib/50
__tests__/21ai-database.test.ts ai-generate.test.ts ai-sse.test.ts ai-writing.test.ts api-keys.test.ts api-members.test.ts auth-refresh.test.ts auth-store.test.ts batch-queue-drop.test.ts block-content.test.ts clipboard-import.test.ts code-highlight.test.ts offline-status.test.ts presence-announcer.test.ts presence-color.test.ts presence-cursor.test.ts presence-emitter.test.ts realtime-url.test.ts search.test.ts utils.test.ts writing-diff.test.ts
files/7
__tests__/2picker.test.ts upload.test.ts
api.ts picker.ts upload-store.ts upload.ts use-file-uploads.ts
ai-database.ts ai.ts api-keys.ts api.ts auth-store.ts batch-queue.ts block-content.ts clipboard-import.ts code-highlight.ts constants.ts offline-status.ts org-admin.ts presence-announcer.ts presence-color.ts presence-cursor.ts presence-editor-views.ts presence-emitter.ts query-client.ts realtime.ts search.ts types.ts utils.ts
stores/8
__tests__/1block-patch-store.test.ts
block-patch-store.ts comment-pill-store.ts database-store.ts editor-store.ts offlineQueue.ts presence-store.ts ui-store.ts
instrumentation.ts middleware.ts
.env.example Dockerfile next-env.d.ts next.config.mjs package.json postcss.config.mjs README.md tailwind.config.ts tsconfig.json tsconfig.tsbuildinfo vitest.config.ts
worker/92
src/87
__tests__/13ai-embedding.test.ts ai-request.test.ts ai-usage-budget.test.ts audit-export.test.ts email-decision.test.ts encrypt.test.ts health-search-index-lag.test.ts mime.test.ts retention.test.ts s3-sign.test.ts search-index.test.ts smtp.test.ts webhook-sign.test.ts
health/1server.ts
lib/12
__tests__/1clamav.test.ts
clamav.ts encrypt.ts job-otel.ts mime.ts notify.ts prisma.ts redis-stream.ts redis.ts s3.ts sharp.ts smtp.ts
processors/56
automations/28
__tests__/3condition-evaluator.spec.ts executors.spec.ts run-pipeline.spec.ts
executors/17assign-user.ts call-integration.ts change-status.ts classify.ts create-notification.ts create-page.ts email-cap.ts helpers.ts integration-registry.ts permission.ts record-write.ts registry.ts run-ai-action.ts send-email.ts send-webhook.ts types.ts update-record.ts
condition-evaluator.ts dead-letter.ts log.ts matcher.ts pipeline.ts run-state.ts schedule.ts watchdog.ts
files/15
__tests__/4errors.test.ts scan-gate.test.ts status.test.ts temp.test.ts
steps/4finalize.ts metadata.ts scan.ts thumbnails.ts
cleanup.ts errors.ts generateThumbs.ts processor.ts status.ts temp.ts types.ts
search-index/4builders.ts grants.ts index.ts processor.ts
ai-embedding.ts ai.processor.ts audit-export.ts automations.processor.ts email-decision.processor.ts email.processor.ts maintenance.processor.ts retention.ts webhooks.processor.ts
config.ts events.ts index.ts logger.ts queues.ts
.env.example Dockerfile package.json README.md tsconfig.json
docs/73
api/17ai.md authentication.md automations.md blocks.md comments.md databases.md files.md forms.md openapi.yaml org-admin.md pages.md scim.md search.md sso.md versioning.md webhooks.md workspaces.md
architecture/10ai-architecture.md automation.md backend-architecture.md database-architecture.md frontend-architecture.md realtime-architecture.md search-architecture.md security-architecture.md storage.md system-architecture.md
database/2database-architecture.md redis-keys.md
development/8admin-guide.md coding-standards.md deployment.md development-guide.md files-pipeline.md perf-report.md performance.md testing.md
product/4functional-requirements.md non-functional-requirements.md product-requirements.md ux-requirements.md
requirements/1requirements-matrix.md
security/5audit-report.md files.md forms.md license-allowlist.md security-architecture.md
tasks/16phase-00-foundation.md phase-01-authentication.md phase-02-workspace.md phase-03-pages.md phase-04-editor.md phase-05-databases.md phase-06-relations.md phase-07-collaboration.md phase-08-search.md phase-09-files.md phase-10-forms.md phase-11-automation.md phase-12-ai.md phase-13-api.md phase-14-enterprise.md phase-15-production.md
ui/9ai.md automations.md design-system.md developers.md files.md forms.md org-admin.md scim.md sso.md
support-matrix.md
infrastructure/71
caddy/1Caddyfile
docker/6
init/101-extensions.sql
opensearch/1init-indices.json
.env.docker docker-compose.yml opensearch-init.sh README.md
kubernetes/40
observability/20
alertmanager/1alertmanager.yaml
grafana/8
dashboards/6ai.json api-overview.json infra.json realtime.json search.json workers-queues.json
provisioning/2
dashboards/1dashboards.yaml
datasources/1datasource.yaml
prometheus/3alerts.yaml recording-rules.yaml scrape.yaml
scripts/1sync-sources.mjs
alertmanager.yaml grafana.yaml kustomization.yaml namespace.yaml node-exporter.yaml otel-collector.yaml prometheus.yaml
postgres/7configmap.yaml cronjob-backup.yaml cronjob-opensearch-snapshot.yaml pgbouncer.yaml replica.yaml statefulset.yaml walg-iam-policy.yaml
api.yaml configmap.yaml ingress.yaml kustomization.yaml namespace.yaml networkpolicy.yaml pdb.yaml README.md realtime.yaml redis.yaml secret.example.yaml web.yaml worker.yaml
nginx/2nginx.conf README.md
observability/14
alertmanager/1alertmanager.yaml
grafana/8
dashboards/6ai.json api-overview.json infra.json realtime.json search.json workers-queues.json
provisioning/2
dashboards/1dashboards.yaml
datasources/1datasource.yaml
prometheus/3alerts.yaml recording-rules.yaml scrape.yaml
scripts/1dashboard-completeness.mjs
README.md
terraform/8compute.tf data.tf main.tf network.tf outputs.tf README.md security.tf variables.tf
packages/289
ai/24
src/20
providers/7anthropic.ts google.ts http.ts index.ts openai-compatible.ts rag.test.ts writing.test.ts
schemas/2database.ts generate.ts
adapters.test.ts config.test.ts config.ts gateway.test.ts gateway.ts index.ts tools.test.ts tools.ts types.ts usage.test.ts usage.ts
package.json README.md tsconfig.json vitest.config.ts
auth/11
src/7index.ts passwords.test.ts passwords.ts sessions.test.ts sessions.ts tokens.test.ts tokens.ts
package.json README.md tsconfig.json vitest.config.ts
collaboration/17
src/13awareness.ts codec.test.ts codec.ts index.ts lww.test.ts lww.ts mapping.ts offline.ts outbox.test.ts outbox.ts provider.test.ts provider.ts types.ts
package.json README.md tsconfig.json vitest.config.ts
config/7
src/4eslint.base.js index.ts prettier.base.json tsconfig.base.json
package.json README.md tsconfig.json
database-client/5
src/2index.test.ts index.ts
package.json README.md tsconfig.json
database-engine/33
src/29
filter/2filter.test.ts index.ts
formula/8evaluator.ts formula.test.ts functions.ts index.ts lexer.ts parser.ts types.ts validate.ts
query/6group.ts index.ts paginate.ts pivot.ts query.test.ts sort.ts
relations/2index.ts relations.test.ts
rollups/2index.ts rollups.test.ts
values/5dates.ts index.ts registry.ts types.ts values.test.ts
views/3buttons.ts index.ts views.test.ts
index.ts
package.json README.md tsconfig.json vitest.config.ts
editor/25
src/21
marks/1highlight.ts
nodes/2equation.ts mention.ts
autosave.test.ts autosave.ts clipboard.test.ts clipboard.ts codec.test.ts codec.ts context-menu.test.ts context-menu.ts diff.test.ts diff.ts factory.ts history.test.ts history.ts index.ts positions.ts slash.test.ts slash.ts types.ts
package.json README.md tsconfig.json vitest.config.ts
observability/20
src/16
__tests__/8db-redis-metrics.test.ts metrics.test.ts otel.test.ts pino-otel.test.ts prometheus.test.ts resource.test.ts scrubber.test.ts traceparent.test.ts
index.ts metrics.ts otel.ts pino-otel.ts prometheus.ts resource.ts scrubber.ts traceparent.ts
package.json README.md tsconfig.json vitest.config.ts
permissions/11
src/7index.ts levels.test.ts levels.ts resolve.test.ts resolve.ts rules.test.ts rules.ts
package.json README.md tsconfig.json vitest.config.ts
search/22
src/18chunking.test.ts chunking.ts client.test.ts client.ts embeddings.test.ts embeddings.ts hybrid.test.ts hybrid.ts index.ts indexer.test.ts indexer.ts mapping.test.ts mapping.ts queries.test.ts queries.ts rrf.test.ts rrf.ts types.ts
package.json README.md tsconfig.json vitest.config.ts
shared/61
src/57
dto/17ai.dto.ts auth.dto.test.ts auth.dto.ts block.dto.ts browser-safety.test.ts comment.dto.ts database.dto.test.ts database.dto.ts file.dto.ts formula-ast.ts index.ts notification.dto.ts page.dto.ts search.dto.ts share.dto.ts webhook.dto.ts workspace.dto.ts
events/8audit-catalog.test.ts audit-catalog.ts audit-csv.test.ts audit-csv.ts audit-scope.test.ts audit-scope.ts catalog.test.ts catalog.ts
realtime/6comment-events.ts frames.test.ts frames.ts notification-policy.ts notification-prefs.ts task-0094.test.ts
automation.test.ts automation.ts constants.ts crypto.test.ts crypto.ts env.ts errors.ts events.test.ts events.ts forms.test.ts forms.ts index.ts markdown.test.ts markdown.ts mentions.test.ts mentions.ts net.test.ts net.ts positions.test.ts positions.ts presence.test.ts presence.ts security-headers.ts webhook-delivery.test.ts webhook-delivery.ts webhook-events.ts
package.json README.md tsconfig.json vitest.config.ts
storage/16
src/12client.test.ts client.ts index.ts keys.test.ts keys.ts mime.test.ts mime.ts presign.test.ts presign.ts thumbnails.test.ts thumbnails.ts types.ts
package.json README.md tsconfig.json vitest.config.ts
ui/37
src/33
components/19avatar.tsx badge.tsx button.tsx checkbox.tsx command.tsx context-menu.tsx dialog.tsx dropdown-menu.tsx empty-state.tsx index.ts popover.tsx separator.tsx skeleton.tsx slider.tsx spinner.tsx switch.tsx tabs.tsx toast.tsx tooltip.tsx
color.ts command-filter.test.ts command-filter.ts focus.test.ts focus.ts formatters.test.ts formatters.ts index.ts theme.test.ts theme.ts toast-store.test.ts toast-store.ts tokens.test.ts tokens.ts
package.json README.md tsconfig.json vitest.config.ts
prisma/16
migrations/13
20260927000000_init/1migration.sql
20260928000000_search_documents_content_hash/1migration.sql
20260929000000_workspace_usage_storage_bytes/1migration.sql
20260930000000_form_submitted_notification_type/1migration.sql
20261001000000_ai_phase12/1migration.sql
20261002000000_webhooks_secret_encrypted_dlq/1migration.sql
20261002111436_webhook_delivery_latency/1migration.sql
20261002120000_org_admin_2fa_retention_unique/1migration.sql
20261002215124_audit_export/1migration.sql
20261003210000_perf_indexes_hot_paths/1migration.sql
20261004004500_perf_indexes_hot_paths_2/1migration.sql
migration_lock.toml README.md
schema.prisma seed.ts verify.ts
scripts/7backup-health.ts docs-completeness.mjs generate-openapi.mjs minio-init.ts opensearch-reindex.ts storage-orphans.ts verify-clean-clone.sh
tests/169
e2e/63
.auth/1user.json
fixtures/7
files/6clip.mp4 clip.wav clip.webm hero-1400.png note.docx note.txt
realtime.ts
mocks/2oidc-issuer.ts saml-idp.ts
playwright-report/3
data/2a6557bae9c2714a658968d4eb8534195c08ebda8.png e3092d07d00a16063e46385c02a559a9054fa847.webm
index.html
reports/1files-security.json
specs/34ai-database.spec.ts ai-generate.spec.ts ai-rag.spec.ts ai-security.spec.ts ai-writing.spec.ts ai.spec.ts api-keys.spec.ts appearance-theme.spec.ts auth.spec.ts automation.spec.ts collab-two-tab.spec.ts comments.spec.ts databases.spec.ts default-workspace-alias.spec.ts developers.spec.ts editor.spec.ts files.spec.ts final-flow.spec.ts forms.spec.ts oauth.spec.ts org-admin.spec.ts pages.spec.ts performance.spec.ts presence-cursors.spec.ts qa-paste-toggle.spec.ts realtime.spec.ts scim.spec.ts search-index-lag.spec.ts search.spec.ts sharing.spec.ts sso.spec.ts task-0094-comments-notifications.spec.ts webhooks.spec.ts workspace.spec.ts
test-results-final-flow/3
final-flow-Release-v1-0-fi-6c06b-w-state-carries-sequential--chromium-desktop/2test-failed-1.png trace.zip
.last-run.json
utils/4api.ts dnd.ts search-lag.ts wait.ts
.gitignore fixtures.ts global-setup.ts package.json playwright.config.ts playwright.final-flow.config.ts README.md tsconfig.json
fixtures/1
files/1make-sparse.ts
integration/60
ai-capability/2ai-app.capability.test.ts gateway.capability.test.ts
drill/2seed-drill.mjs verify-restore.mjs
fixtures/5
files/5clip.mp4 clip.wav doc.pdf hero-1400.png note.txt
helpers/3api.ts containers.ts seed.ts
realtime/11control-channel.test.ts convergence.test.ts flush-rebase-http.test.ts handshake.test.ts heartbeat-limits.test.ts lifecycle.test.ts presence.test.ts rebase.test.ts resume.test.ts rt-helpers.ts task-0094-fanout.test.ts
ai-chat.integration.test.ts ai-database.integration.test.ts ai-generate.integration.test.ts ai-rag.integration.test.ts ai-writing.integration.test.ts api-keys.integration.test.ts audit-completeness.integration.test.ts audit-export-s3.integration.test.ts auth.integration.test.ts automation-pipeline.integration.test.ts automations.integration.test.ts blocks.integration.test.ts cache-invalidation.integration.test.ts comments.integration.test.ts databases.integration.test.ts files-lifecycle.integration.test.ts files-pipeline.integration.test.ts files-security.integration.test.ts files.integration.test.ts forms-responses.integration.test.ts forms.integration.test.ts oauth.integration.test.ts openapi.contract.test.ts org-admin.integration.test.ts package.json pages.integration.test.ts permissions.integration.test.ts README.md replica-routing.integration.test.ts retention-engine.integration.test.ts scim.integration.test.ts search.integration.test.ts sso.integration.test.ts tsconfig.json vitest.config.ts webhooks.integration.test.ts workspace.integration.test.ts
performance/28
fixtures/1search-100k.ts
helpers/2seed-100k.mjs seed-1k-load.mjs
reports/7api-load-smoke.json database-load-smoke.json editor-local.json realtime-load.json search-full.json search-last.json search-reduced.json
api-load.js api.js archive.tar database-load.js database.js editor-local.mjs extract-100k-env.mjs package.json README.md realtime-1k.js realtime-load.js realtime.js run-realtime-load.sh search-search.k6.js search-summary.json seed-100k.mjs threshold-breach-demo.js verify-zero-op-loss.mjs
security/16
helpers/1app.ts
audit-report.test.ts auth-paths.test.ts deps.test.ts formula-fuzz.test.ts gitleaks-config.test.ts headers.test.ts images.test.ts oracle.ts package.json permission-fuzz.test.ts rate-limits.test.ts README.md tsconfig.json upload-abuse.test.ts vitest.config.ts
README.md
.dockerignore .env .env.bak-task0125 .env.example .eslintrc.json .gitignore .npmrc .prettierignore .prettierrc.json AGENTS.md ARCHITECTURE.md CHANGELOG.md CONTRIBUTING.md gitleaks.toml LICENSE package.json pnpm-lock.yaml pnpm-workspace.yaml PRODUCT-SPEC.md README.md ROADMAP.md SECURITY.md tsconfig.json turbo.json
frontend-architecture.mddocs/architecture/frontend-architecture.md← architecture34,886 B← Back to the app

Frontend Architecture (apps/web)

Next.js 14 (App Router) + React 18 + Tiptap + dnd-kit + TanStack Query + Zustand. Sibling docs: system · realtime · database · security.

The frontend is a presentation + local-state layer only. It never authorizes: every mutation is re-checked server-side, and the UI merely reflects the result.


1. Directory Structure

Per ARCHITECTURE.md §2:

apps/web
├── app/                          # Next.js App Router
│   ├── (auth)/                   # route group: login, register, reset, verify
│   │   ├── login/page.tsx
│   │   ├── register/page.tsx
│   │   ├── reset/[token]/page.tsx
│   │   └── verify/[token]/page.tsx
│   ├── (app)/[workspace]/        # authed workspace shell (sidebar + top bar + content)
│   │   ├── layout.tsx            # shell: sidebar, top bar, command palette, toasts
│   │   ├── page.tsx              # workspace home
│   │   ├── inbox/page.tsx        # notifications (in-app)
│   │   ├── search/page.tsx       # global search results
│   │   ├── favorites/page.tsx
│   │   ├── trash/page.tsx
│   │   ├── settings/             # workspace / members / security / billing / integrations
│   │   ├── teamspaces/[team]/    # teamspace subtree
│   │   └── p/[pageId]/           # the page canvas (editor or database home)
│   │       ├── page.tsx          # resolves page → editor | database | record
│   │       └── ...               # [pageId] also serves /p/[pageId]/[childPageId] nesting
│   ├── share/[token]/            # public shared pages (no auth, rate-limited)
│   ├── forms/[slug]/             # public forms (no auth)
│   └── api/                      # BFF route handlers (server components / edge)
│       ├── auth/refresh/route.ts # cookie → new access token (keeps JWTs out of JS bundle paths)
│       ├── files/[fileId]/route.ts # stream/signed-URL proxy for file blocks
│       └── preview/[kind]/[fileId]/route.ts # image/PDF preview proxy
├── components/                   # app-level composites
│   ├── topbar/                   # workspace switcher, search button, AI button, avatar
│   ├── command-palette/          # Cmd/Ctrl+K (see §4)
│   ├── dialogs/                  # share dialog, settings dialogs, delete confirms
│   └── notifications/            # toasts, inbox list
├── editor/                       # block editor wiring (apps/web side)
│   ├── EditorCanvas.tsx          # mounts @factory/editor on a page
│   ├── slash/                    # slash command menu (searchable, dynamic /database)
│   ├── context-menus/            # block + page right-click menus
│   ├── dnd/                      # dnd-kit sensors/containers (blocks, columns)
│   └── ai/                       # "Ask AI" selection panel, rewrite popover
├── database/                     # view renderers (see §6)
│   ├── DatabaseView.tsx          # router: view type → renderer
│   ├── views/                    # table, list, board, gallery, calendar, timeline,
│   │                             # chart, dashboard, form renderers
│   ├── cells/                    # property cell renderers per PropertyType (22)
│   ├── filter-builder/           # nested AND/OR/NOT UI → packages/database-engine tree
│   └── record-page/              # record's page (properties sidebar + blocks)
├── workspace/                    # sidebar, page tree, teamspaces, settings UI
├── collaboration/                # presence avatars, cursors, Yjs bootstrap, offline badge
├── search/                       # search page, suggestions, filter chips
├── settings/                     # workspace/user/billing/security settings screens
├── hooks/                        # usePage, useBlocks, useDatabase, useRealtime, useOffline,
│                                 # useCommandPalette, usePresence
├── stores/                       # Zustand stores (see §5)
├── lib/                          # api client (fetch + TanStack Query), ws client,
│                                 # formatters, date utils
└── types/                        # frontend-only types (wire DTOs come from @factory/shared)

Dependency rule: app/ → components/ | editor/ | database/ | hooks/ → packages/*. The editor/ and database/ directories never import from app/ (no route awareness); they receive data through props and hooks, keeping them usable from the command palette, dialogs, or public share pages.


2. Routing Map

2.1 Route table

Path Group Auth Purpose
/ — public Redirect to last workspace or onboarding (create workspace)
/login, /register (auth) public Auth forms (React Hook Form + Zod)
/reset/[token], /verify/[token] (auth) public Single-use token flows
/sso/callback (auth) public SAML/OIDC assertion consumer → exchange for session
/[workspace] (app) member Workspace home (pinned/frequent pages)
/[workspace]/inbox (app) member In-app notifications list
/[workspace]/search?q= (app) member Global search (full-text + hybrid toggle)
/[workspace]/favorites (app) member Favorite pages (fractional-position list)
/[workspace]/trash (app) admin+ Trashed pages, restore/purge
/[workspace]/teamspaces/[team] (app) member Teamspace root page
/[workspace]/p/[pageId] (app) per-page Page canvas — a page, database home, or record page
/[workspace]/settings/* (app) admin+ profile, members, security, billing, integrations
/share/[token] public none (share-scoped) Public shared page; respects allowComments, password, expiry
/forms/[slug] public none Public form (see Form.status === PUBLISHED)

2.2 The page canvas (/[workspace]/p/[pageId])

One route serves three shapes, resolved by usePage(pageId):

PageDto.kind:
  • "page"      → EditorCanvas (Tiptap block tree)
  • "database"  → DatabaseView (database home: view tabs + property rows + records)
  • "record"    → RecordPage (properties panel on the left + the record page's blocks on the right)

2.3 Server vs client rendering

2.4 Command palette (Cmd/Ctrl+K)

A single headless component (components/command-palette, no third-party fuzzy lib — custom Levenshtein + subsequence scoring) with a flat command registry:

Group Commands (examples)
Navigation Go to page (fuzzy over recent + all pages via search API), Open settings, Switch workspace
Create New page, New database (table/board/calendar), New team, New form
Actions Invite user, Toggle theme (light/dark/system), Export current page (md/html/pdf), Import, Ask AI…
Search "Search: …" (falls through to POST /v1/search), recent searches

Behavior: single overlay, focus-trapped, role="dialog", arrow keys + Tab between groups, Enter executes, Esc closes. Every command is also reachable from a menu — the palette is a shortcut, never the only path (accessibility requirement, §10).


3. Block Editor Integration

The editor is implemented in packages/editor (Tiptap extensions, slash menu, context menus, DnD, fractional-position engine); apps/web/editor/ is the wiring layer that mounts it on a page, connects it to stores, and hosts the AI selection panel.

3.1 Canonical model

The editor document is a block tree serialized to canonical Block JSON — never raw HTML. One Tiptap node per block, each carrying attrs:

interface BlockNodeAttrs {
  id: string;          // "blk_…" cuid
  position: string;    // fractional, from the positions engine
  content?: unknown;   // type-specific (mirrors Block.content JSONB)
  properties?: unknown; // colors, alignment, widths (mirrors Block.properties JSONB)
  syncedSourceId?: string;
}

3.2 BlockType ↔ Tiptap node mapping

BlockType (schema enum) Tiptap node (packages/editor/src/nodes/*) Notes
PARAGRAPH BlockNode (paragraph) base text node
HEADING_1..3 BlockNode (heading 1–3) single node type, level attr
QUOTE BlockNode (quote) styled, indented
CALLOUT CalloutNode icon + background color in properties
BULLETED_LIST ListBlockNode ProseMirror list item; list blocks nest by parentId
NUMBERED_LIST ListBlockNode (ordered: true) numbering computed per sibling run
TODO TodoBlockNode checkbox in properties.checked; drag handle
TOGGLE ToggleBlockNode collapsible child container (children = blocks with parentId)
IMAGE ImageBlockNode content: {fileId, width, align, caption}; lazy load, loading="lazy"
VIDEO / AUDIO MediaBlockNode content: {fileId, kind}; native player or preview
FILE FileBlockNode card UI: name, size, icon, download button (signed URL via BFF)
BOOKMARK BookmarkBlockNode content: {url, title}; fetches og metadata on create
EMBED EmbedBlockNode content: {url, type} (Loom, Figma, Twitter, YouTube, …)
CODE CodeBlockNode content: {code, language}; Shiki highlight (Web Worker, off main thread)
EQUATION EquationBlockNode content: {latex}; KaTeX (server-side render for SSR, client hydration)
COLUMN ColumnNode child container; width in properties
COLUMN_LIST ColumnListNode container of COLUMN nodes; flex/grid layout
DIVIDER DividerNode atomic, no content
SPACER SpacerNode properties.height px
DATABASE DatabaseBlockNode embeds a full database view inline (see §6); content: {databaseId, viewId}
LINKED_DATABASE LinkedDatabaseBlockNode renders another database's view filtered/linked
TABLE TableBlockNode static table (distinct from database tables); content: {rows, cols}
CHART ChartBlockNode renders charts row config (bar/line/area/pie/donut/number)
FORM FormBlockNode embeds a published form preview
SYNCED_BLOCK SyncedBlockNode read-only mirror of syncedSourceId's content (live-fetched)
CHILD_PAGE ChildPageBlockNode link row → /p/[childId]; content: {pageId, icon, title}
CHILD_DATABASE ChildDatabaseBlockNode link row → a database embedded elsewhere

All block nodes are registered through one factory (packages/editor/src/editor.ts, createFactoryEditor({ pageId, blocks, realtime?, readonly? })) so the same factory is used by the page canvas, record pages, public share pages (readonly), and the slash menu previews.

3.3 Extensions list

Extension Purpose
@tiptap/core + StarterKit subset base document schema (we register our nodes, not StarterKit's paragraphs — one source of truth)
@factory/editor block nodes (table §3.2) the block vocabulary
@tiptap/extension-placeholder empty-block "Type '/' for commands" placeholder
@tiptap/extension-character-count per-page stats (top bar)
@tiptap/extension-dropcursor / Gapcursor atomic-block drop targets, gap between blocks
y-prosemirror (@tiptap/extension-collaboration) CRDT binding when realtime is active; disabled in readonly/share contexts
@factory/collaboration awareness adapter presence + cursor payload (see realtime, §5)
Custom SlashMenu (plugin) / detection, searchable command list, dynamic /database creation
Custom ContextMenus right-click → block menu / page menu (turn into, duplicate, move to, comment, Ask AI, colors…)
Custom MentionExtension @user/@team/@page/@database popup, stored as mention marks with id + label
Custom CommentAnchorExtension text-selection comments (anchor/offset stored in comments.selection)
dnd-kit integration (custom plugin) block drag: handle (⋮⋮), multi-select drag, drop indicators, auto-scroll, cross-column and cross-page drops (§3.5)
Custom FractionalPositionEngine (packages/editor/src/positions) computes position strings on every insert/move (midpoint algorithm, re-balance on overflow)

3.4 How the Yjs codec bridges (offline + realtime)

The Yjs document shape (packages/collaboration/src/doc-model.ts):

Y.Doc
├── yXml: Y.XmlFragment          # ProseMirror document (via y-prosemirror) —
│                                #   the editable tree, one item per block node
├── yMeta: Y.Map<string, ...>    # per-block side data NOT in the PM doc:
│                                #   position (fractional), id, content, properties
│                                #   (so reordering and non-text edits are CRDT-merged)
└── yAwareness                    # presence (ephemeral, not persisted)

Bridge rules (implemented in packages/collaboration/src/codec.ts, round-trip tested):

  1. Encode (Yjs → Block tree): walk yXml; for each block item read id/type from the item attrs, content/properties from yMeta.get(id), and parentId from the tree structure; sibling order is taken from position strings, not array order — so a persisted snapshot and the CRDT always agree on ordering.
  2. Decode (Block tree → Yjs): build yXml items in position order; seed yMeta with content/properties/position. Hydration happens server-side (realtime, §4); the client hydrates the same way offline from its IndexedDB snapshot.
  3. Local-first: every keystroke/drag applies to the local Y.Doc first (< 16 ms), the TanStack Query cache is invalidated lazily, and the sync engine ships the update (online: to the socket; offline: queued in IndexedDB).
  4. No HTML in the wire. Copy/paste into the app parses external HTML/Markdown via the importer into block ops; copy out serializes the selection to Markdown/HTML at the boundary only.

3.5 Drag & drop (dnd-kit)

One DndContext per canvas with a multi-container strategy:


4. State Management

4.1 The split

Layer Tool Owns
Server state TanStack Query (@tanstack/react-query) everything fetched from the API: pages, blocks (initial), databases, records + property values, search, notifications, files, automations, AI conversations, audit. Mutations via useMutation with optimistic updates where UX demands (e.g. comment resolve) and cache invalidation wired to domain-event-style cache keys.
Client-only state Zustand (vanilla + react bindings, devtools enabled in dev) editor caret/selection, UI panels, presence, offline queue, DnD transient state, command palette state
Forms React Hook Form + Zod auth forms, settings forms, form-builder, filter builder (Zod schema from @factory/shared validates both client and server)
URL state useSearchParams / route params workspace slug, page id, search q, view id (?view=), filters (?filter=) — anything shareable via link lives in the URL, never in a store

4.2 TanStack Query conventions

const keys = {
  pages:      (wid: string) => ['workspaces', wid, 'pages'] as const,
  page:       (wid: string, id: string) => ['workspaces', wid, 'pages', id] as const,
  tree:       (wid: string) => ['workspaces', wid, 'pages', 'tree'] as const,
  database:   (wid: string, id: string) => ['workspaces', wid, 'databases', id] as const,
  records:    (wid: string, dbId: string, viewId: string, page: number) =>
              ['workspaces', wid, 'databases', dbId, 'records', viewId, page] as const,
  search:     (query: SearchQuery) => ['search', query] as const,
  comments:   (pageId: string) => ['comments', pageId] as const,
  files:      (fileId: string) => ['files', fileId] as const,
  ai:         (convId?: string) => ['ai', convId ?? 'conversations'] as const,
};

4.3 Zustand stores (names and shape)

Store Purpose Key fields
useEditorStateStore per-page editor session (one instance per open page, keyed by pageId) caret: {blockId, offset}, selection: {fromBlockId, toBlockId, fromOffset, toOffset}, activeBlockId, slashMenu: {open, anchor, query}, readOnly
useUiStateStore app chrome sidebarOpen, sidebarWidth, commandPaletteOpen, activePanel (comments | properties | share | null), toasts: Toast[], theme: 'light'|'dark'|'system'
usePresenceStore per-room presence peers: Map<userId, PresencePeer>, cursors: Map<userId, CursorPayload>, self: {userId, color, name} — populated from Yjs awareness events
useOfflineQueueStore offline sync state status: 'online'|'offline'|'syncing', pendingCount, lastSyncAt — mirrors the IndexedDB queue in @factory/collaboration
useDndStore transient DnD state draggingIds: string[], dragOverContainerId, `dropIndicator: {containerId, index}
usePaletteStore command palette open, query, activeIndex, groups
useRealtimeStore socket lifecycle wsStatus: 'closed'|'connecting'|'open', activeRooms: string[], reconnectAttempt

Persistence: only useUiStateStore (theme, sidebar) uses persist (localStorage). Presence/offline/DnD are never persisted (presence is ephemeral by design; the offline queue lives in IndexedDB, not localStorage — see §7).


5. Data Fetching Hooks

Hook Returns Source
usePage(wid, pageId) PageDto (+ kind discriminator) GET /v1/pages/:id
usePageTree(wid) flat page tree (positions, titles, icons) for sidebar GET /v1/workspaces/:wid/pages/tree (cascades lazily; children loaded per expanded node)
useBlocks(pageId) initial block list (only when realtime is off) GET /v1/pages/:id/blocks
useDatabase(wid, dbId) database + properties + views GET /v1/databases/:id
useRecords(wid, dbId, viewId, cursor) page of records + values (server-side filter/sort/group/paginate) POST /v1/databases/:id/query
useRecordPage(wid, recordId) record + its page + property values GET /v1/databases/:id/records/:rid
useSearch(query) results + facets POST /v1/search
useComments(pageId) threads for the page GET /v1/pages/:id/comments
useRealtime(wid, resourceId) socket handle + doc handle (from @factory/collaboration) WebSocket /realtime
useOffline() {status, pendingCount, flush()} useOfflineQueueStore + queue events

6. Database View Renderer Architecture

database/DatabaseView.tsx is a thin router: it receives DatabaseDto (properties + views), reads ?view= from the URL, and mounts the matching renderer. All renderers share the query pipeline:

view config (filter tree, sort[], group[], pageSize, visible properties)
   │  (Zod-validated view settings from @factory/shared)
   ▼
POST /v1/databases/:id/query   { viewId | adHoc, page: cursor }
   │  server: packages/database-engine applies filter → sort → group → paginate
   │  + eager property values (EAV pivot) + relation counts (for relation cells)
   ▼
RecordsPageDto { records: RecordWithValues[], cursor, total, groups?: GroupMeta[] }
   ▼
renderer (virtualized list/canvas) → row/cell components → cell renderers per PropertyType
View (ViewType) Renderer (database/views/*) Virtualization
TABLE TableView — grid: sticky header, column resize (dnd-kit handles), row density, inline cell editing (double-click → property editor popover) @tanstack/react-virtual rows (overscan 10) + column virtualization for > 50 visible columns
LIST ListView — minimal cards, 1–2 visible properties row virtualization
BOARD BoardView — groups become columns (kanban); cards show cover + first N visible properties column virtualization (horizontal) + per-column card virtualization; row drag between groups = relation/property update op
GALLERY GalleryView — card grid with cover images grid virtualization
CALENDAR CalendarView — month/week; records positioned by date property month-level windowing (render visible month + neighbors only)
TIMELINE TimelineView — Gantt-like rows by date range row virtualization + time-axis zoom
CHART ChartView — renders charts config (bar/line/area/pie/donut/number) data is server-aggregated (query returns aggregate buckets, not rows)
DASHBOARD DashboardView — widget grid from DashboardWidget.layout; each widget embeds a table/board/chart/number/calendar/timeline/text/linked-database source; drag/resize with dnd-kit (grid mode) each embedded widget is virtualized internally
FORM FormView — builder (authed) or public submission page (/forms/[slug]) n/a

Cell renderers (database/cells/*, one per PropertyType enum — 22 total): TitleCell, TextCell, RichTextCell, NumberCell, SelectCell, MultiSelectCell, StatusCell (color pill + progress for PERCENT), DateCell, DateRangeCell, PersonCell (avatar + name, click → profile), EmailCell, PhoneCell, UrlCell, CheckboxCell, FilesCell, CreatedTimeCell, CreatedByCell, LastEditedTimeCell, LastEditedByCell, RelationCell (chips, click → open target record, + to link — mutates RelationLink), RollupCell (read-only computed), FormulaCell (read-only computed), ButtonCell (click executes the button action server-side: POST /v1/databases/:id/buttons/:bid/execute), UniqueIdCell (read-only rec_…).

Interaction model: inline cell edits are optimistic — the local row state updates immediately (Zustand transient map cellOverrides), the mutation is issued, and on failure the override is rolled back with a toast. Bulk ops (board drag, filter-then- update) batch into one POST /v1/databases/:id/records/batch.

Rollups/formulas: the server precomputes rollup and formula values in the query response (event-driven recompute in the worker keeps them fresh — see system, ADR / database §7); the client renders them read-only and never runs the formula engine locally for display (the packages/database-engine evaluator exists for live-preview of formula edits in the property editor only, with the same safe AST — no eval, ever).


7. Offline Sync Flow

Local-first editing works with or without a server connection, built on @factory/collaboration:

┌────────────────────────────────────────────────────────────────────────┐
│ Browser                                                               │
│                                                                        │
│  Tiptap/Yjs local doc (in memory)                                     │
│     │  every op applies locally first (< 16 ms)                       │
│     ▼                                                                  │
│  IndexedDB ("factory-collab")                                          │
│     ├── y-docs/{pageId}     → Y.Doc state vectors + update log        │
│     ├── queue/{pageId}      → outbound updates not yet acknowledged    │
│     └── meta/               → lastServerUpdate, lastAck               │
│     │                                                                  │
│     │  online:   ws.send(update) ──────────────▶ apps/realtime         │
│     │  offline:  queue.append(update) (persisted immediately)          │
│     ▼                                                                  │
│  SyncEngine                                                            │
│     • navigator.onLine + ws heartbeat drive status transitions         │
│     • on reconnect: send full pending log (Yjs merge is idempotent)    │
│     • apply server-ack (state vector) → truncate queue                 │
│     • non-CRDT ops (record property edits, comments, view config)      │
│       are REST mutations kept in the same queue with idempotency keys  │
│       (client-generated UUIDs; server dedupes on the key)              │
└────────────────────────────────────────────────────────────────────────┘

8. Virtualization Strategy

All large collections use @tanstack/react-virtual (or its grid mode); nothing renders more than the viewport + overscan.

Surface Unit Strategy
Sidebar page tree page node render expanded nodes only; children fetched lazily per expansion (one API call per level); fractional-position order from the API
Page canvas (blocks) block row the Yjs doc holds the whole tree in memory (needed for CRDT), but the DOM renders virtualized rows; a 100k-block page keeps ~60 rows mounted; heavy block types (code highlight, KaTeX, charts) render in Web Workers or lazy-IntersectionObserver subtrees
Table view row (100k+) row virtualization, overscan: 10; sticky first column + header; column virtualization beyond 50 visible properties
Board view columns + cards horizontal column virtualization; cards per column virtualized; covers lazy-loaded
Gallery/timeline cards / rows grid / row virtualization
Search results result row virtualized list + cursor pagination ("Load more" appends, keyed by cursor)
Comments panel thread windowed list; replies collapsed until expanded
Inbox/notifications row virtualized + cursor pagination
Dashboard widgets only visible widgets hydrated (each widget self-virtualizes its data)

Rules: (1) virtualization is a renderer concern — data hooks return full pages from the API (cursor-paginated), the virtualizer only controls DOM; (2) measured targets: 100k-record database interaction < 50 ms, reorder < 16 ms (Phase 4/5 exit criteria); (3) requestAnimationFrame-coalesced scroll updates, no layout thrash (transforms only).


9. Theming

Design tokens live in packages/ui as CSS custom properties; no hard-coded colors anywhere (lint rule: no-restricted-syntax against hex literals in apps/web).

Token family Examples
Color --color-bg, --color-bg-elevated, --color-text, --color-text-muted, --color-border, --color-accent, --color-danger, --color-success, --color-warning
Block/content --color-block-quote-bg, --color-callout-{info,warning,success,danger}-bg, --color-todo-check
Database --color-property-{status,select}-* (user-configurable palettes map onto token slots)
Spacing --space-1 … --space-8 (4 px base)
Radius --radius-sm/md/lg/full
Typography --font-sans, --font-mono, --text-xs … --text-2xl (fluid sizes via clamp())
Motion --duration-fast:120ms, --duration-slow:240ms, --ease-out; all reduced to 0 under prefers-reduced-motion
Shadow --shadow-sm/md/lifted (elevation for popovers, dialogs, drag ghosts)

10. Accessibility Approach (WCAG 2.2 AA)

Area Approach
Keyboard every mouse interaction has a keyboard path: slash menu, context menus, palette (native key handling), DnD via KeyboardSensor (space to lift, arrows to move, space to drop, esc to cancel), column resize via handle focus + arrows
Non-drag alternatives "Move to" in every block context menu; sidebar pages reorderable via arrow keys; board cards have a "Move to group" menu item
ARIA semantics editor is a ProseMirror contenteditable with role="textbox" + aria-multiline; block handles are role="button" with aria-label="Move paragraph block"; slash/context menus are role="menu" + roving tabindex; drag ghosts are announced via a live region (role="status", polite)
Focus management focus-trapped dialogs (Radix primitives in packages/ui); focus returns to the trigger on close; canvas navigation restores the block under the caret on reload (aria-labelledby on the active block heading)
Screen readers live regions for: save status ("Saved" / "Offline — queued"), presence changes ("Ana joined"), comment resolution; every icon-only button has aria-label; decorative icons aria-hidden
Vision contrast AA (token test in CI), focus visible (2 px --color-accent outline, never removed), :focus-visible only, text scaling to 200 % without overflow (fluid type + rem everywhere)
Motion prefers-reduced-motion zeroes animations and disables auto-scroll inertia during drag
Forms React Hook Form + Zod errors rendered as aria-live="assertive" text linked via aria-describedby; autocomplete attributes on auth forms
Color independence status is never conveyed by color alone (icons/labels on status pills, todo state)

E2E coverage: Playwright + @axe-core/playwright audit on the page canvas, table view, and share page in the CI contract (Phase 4/5 Definition of Done).


11. Performance Budgets (frontend)

Metric Budget Mechanism
First meaningful paint (page) < 2 s SSR shell + metadata, RSC prefetch, fonts font-display: swap + self-hosted, editor chunk code-split (loaded after metadata renders)
Bundle editor core < 250 KB gzip Tiptap extensions registered per-node; code highlight (Shiki) lazy; KaTeX lazy; dnd-kit tree-shaken
Editor interaction < 50 ms ops apply to Yjs locally; DOM patch via ProseMirror; no React re-render per keystroke (editor state lives in Zustand, not React state)
Local block move < 16 ms single position string recompute + one Yjs op + one virtualizer re-layout
Search response (client perceived) < 500 ms debounce 250 ms, abortable fetch, cached suggestions
Memory 100k-block page < 500 MB Yjs doc in memory is the cost; blocks' heavy content (code text > 50 KB) stored in content but rendered lazily