.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
pages.mddocs/api/pages.md← api27,468 B← Back to the app

Pages API

Pages are the fundamental content container: a titled, icon- and cover-decorated document that holds blocks (see blocks.md), child pages, comments, permissions, and version history. Every database record is also a page (see databases.md).

Shared conventions (auth, error model, pagination, rate limits): authentication.md.

Permission note: all page operations are validated server-side against the RBAC role and resource-level permissions (NONE/VIEW/COMMENT/EDIT/FULL_ACCESS) with inheritance from the workspace → team → parent-page chain. Minimum levels per operation:

Operation Minimum permission
Read page / list tree / versions VIEW
Create child page EDIT on parent (or EDIT on workspace/team root)
Update / move / duplicate / trash EDIT
Purge, restore, change permissions, export EDIT (purge requires FULL_ACCESS or workspace Admin/Owner)

Guests with VIEW-only access get 403 FORBIDDEN on writes; pages outside their visible subtree are 404 NOT_FOUND (existence is not leaked).

Concurrency: PATCH accepts If-Match: "<version>" (see authentication.md §9); a stale version yields 409 CONFLICT with the actual version.


1. Page Resource

{
  "id": "pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9",
  "workspaceId": "wks_01J9ZKP5C9H7J9K1L3M5N7P9Q1",
  "teamId": "tm_01J9ZKP8G5I7J9L1M3N5P7Q9R1",
  "parentId": null,
  "position": "a0",
  "title": "Product Launch Plan",
  "icon": "🚀",
  "coverUrl": "https://factory.example.com/files/fil_01J9ZKP…/cover.jpg",
  "description": "Q2 launch — objectives, requirements, tasks, risks.",
  "isPrivate": false,
  "isFavorite": false,
  "archivedAt": null,
  "trashedAt": null,
  "version": 7,
  "createdBy": "usr_01J9ZKQX4V2M8N3P5R7T9W1Y3A",
  "updatedBy": "usr_01J9ZKQ2V4W6X8Y0Z2A4B6C8D0",
  "createdAt": "2025-01-02T09:15:00.000Z",
  "updatedAt": "2025-01-02T14:41:00.000Z",
  "childCount": 3,
  "blockCount": 48
}

2. Create a Page

POST /pages

Create a page, optionally as a child of another page or under a team root. Creating a page never creates blocks — add them via the blocks API.

Request:

{
  "parentId": "pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9",
  "teamId": "tm_01J9ZKP8G5I7J9L1M3N5P7Q9R1",
  "title": "Q2 Launch Checklist",
  "icon": "✅",
  "description": "Everything that must be true at launch day.",
  "position": "a0V",
  "isPrivate": false
}
Field Type Required Notes
parentId string | null no Parent page (same workspace). null/omitted = root of the workspace or team.
teamId string | null no Assign to a team (root-level placement). Ignored when parentId is set to a non-root page.
title string (0–2000) no Empty allowed (page shows as "Untitled" in UI).
icon string no Emoji or a file id (fil_…) from files.
coverUrl string (url) no Must point to a workspace file URL.
description string (≤ 2000) no
position string (fractional) no Insertion point among siblings; default = append. See §9 Position Semantics.
isPrivate boolean no Default false; private pages are hidden from the sidebar of non-editors.
properties object no Free-form page properties (e.g. {"status": "draft"}) — shown in the page info panel.

Exactly one of parentId / teamId may be set (or neither → workspace root). Setting both → 400 VALIDATION_ERROR.

201 Created

{
  "data": {
    "id": "pg_01J9ZKQ8G2H4I6J8L0M2N4P6Q8",
    "workspaceId": "wks_01J9ZKP5C9H7J9K1L3M5N7P9Q1",
    "teamId": "tm_01J9ZKP8G5I7J9L1M3N5P7Q9R1",
    "parentId": "pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9",
    "position": "a0V",
    "title": "Q2 Launch Checklist",
    "icon": "✅",
    "coverUrl": null,
    "description": "Everything that must be true at launch day.",
    "isPrivate": false,
    "isFavorite": false,
    "archivedAt": null,
    "trashedAt": null,
    "version": 1,
    "createdBy": "usr_01J9ZKQX4V2M8N3P5R7T9W1Y3A",
    "createdAt": "2025-01-02T15:00:00.000Z"
  }
}

Errors

Status Code When
400 VALIDATION_ERROR Bad icon file id, both parent+team set, field constraints.
403 FORBIDDEN No EDIT on the parent / team root.
404 NOT_FOUND Parent or team not visible to caller.
422 UNPROCESSABLE_ENTITY Would create a cycle (parent is a descendant of itself — impossible for new pages but reported uniformly) or nesting depth > 50 (details: [{issue: "max_depth"}]).

Events emitted: page.created. The page is queued for search indexing.


3. Read a Page

GET /pages/:pageId

Query params:

Param Type Notes
include comma-separated list blocks — full block tree; children — direct child pages (1 page each); versions — last 10 version ids; shares — active share links. Multiple: ?include=blocks,children.
depth int (1–10, default 1) With include=children, how many levels of children to expand.

200 OK (with ?include=blocks,children)

{
  "data": {
    "id": "pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9",
    "workspaceId": "wks_01J9ZKP5C9H7J9K1L3M5N7P9Q1",
    "teamId": "tm_01J9ZKP8G5I7J9L1M3N5P7Q9R1",
    "parentId": null,
    "position": "a0",
    "title": "Product Launch Plan",
    "icon": "🚀",
    "coverUrl": "https://factory.example.com/files/fil_01J9ZKP…/cover.jpg",
    "description": "Q2 launch — objectives, requirements, tasks, risks.",
    "isPrivate": false,
    "isFavorite": false,
    "version": 7,
    "createdBy": "usr_01J9ZKQX4V2M8N3P5R7T9W1Y3A",
    "updatedBy": "usr_01J9ZKQ2V4W6X8Y0Z2A4B6C8D0",
    "createdAt": "2025-01-02T09:15:00.000Z",
    "updatedAt": "2025-01-02T14:41:00.000Z",
    "blocks": [
      {
        "id": "blk_01J9ZKQ6A9B2C4D6E8F0A2B4C6",
        "type": "heading_1",
        "parentId": null,
        "position": "a0",
        "properties": {},
        "content": { "text": "Objectives", "marks": [] },
        "isSynced": false
      },
      {
        "id": "blk_01J9ZKQ6B1C3D5E7F9A1B3C5D7",
        "type": "paragraph",
        "parentId": null,
        "position": "a1",
        "properties": {},
        "content": { "text": "Reach GA for the new database engine by 2025-04-30.", "marks": [] },
        "isSynced": false
      },
      {
        "id": "blk_01J9ZKQ6C2D4E6F8A0B2C4D6E8",
        "type": "todo",
        "parentId": null,
        "position": "a2",
        "properties": { "checked": false },
        "content": { "text": "Ship board view", "marks": [] },
        "isSynced": false
      },
      {
        "id": "blk_01J9ZKQ6D3E5F7A9B1C3D5E7F9",
        "type": "database",
        "parentId": null,
        "position": "a3",
        "properties": {},
        "content": { "databaseId": "db_01J9ZKQ7E4F6A8B0C2D4E6F8A0" },
        "isSynced": false
      }
    ],
    "children": [
      {
        "id": "pg_01J9ZKQ8G2H4I6J8L0M2N4P6Q8",
        "title": "Q2 Launch Checklist",
        "icon": "✅",
        "position": "a0",
        "childCount": 0,
        "updatedAt": "2025-01-02T15:00:00.000Z"
      },
      {
        "id": "pg_01J9ZKQ8H3I5J7L9M1N3P5Q7R9",
        "title": "Risks & Mitigations",
        "icon": "⚠️",
        "position": "a1",
        "childCount": 1,
        "updatedAt": "2025-01-02T11:20:00.000Z"
      }
    ]
  }
}

Errors: 401 UNAUTHORIZED, 403 FORBIDDEN (page exists but you lack VIEW on this page and an explicit deny was granted), 404 NOT_FOUND (invisible page or different workspace).


GET /pages — List & Tree

List the pages the caller can see at a given level.

Query params:

Param Type Default Notes
parentId string – Siblings of this parent. Omit (or null) for workspace roots.
teamId string – Root pages of a team (mutually exclusive with parentId).
favorites boolean false Only the caller's favorite pages.
trashed boolean false Include (only) pages in the trash (workspace Admin/Owner only).
q string – Title substring filter.
include list – children (one more level).
cursor, limit – 50 / max 200 base64url (position[, tiebreak]) cursor.

Ordering: position ASC (fractional order). The two filter flags are mutually exclusive — sending both is a 400 VALIDATION_ERROR.

200 OK — { data: [ <page objects> ], nextCursor } (same page object as above, without blocks/children unless include=children). Every row also carries favorite (the caller's star state) and databaseId (the seeded Database row's id — non-null ⇔ the page is a database; the Page model has no type field).

trashed=true specifics (Admin/Owner only, 403 FORBIDDEN details: [{reason: "trash_requires_admin"}] otherwise):

favorites=true specifics:

Events emitted: none (read).


4. Update a Page

PATCH /pages/:pageId

Merge-patch of page metadata. Blocks are not edited here — use the blocks API. Moving a page to a new parent and/or reordering among new siblings happens via parentId + position.

Request (any subset):

{
  "title": "Product Launch Plan v2",
  "icon": "🚀",
  "coverUrl": "https://factory.example.com/files/fil_01J9ZKP…/cover-2.jpg",
  "description": "Q2 launch, revised.",
  "isPrivate": true,
  "parentId": null,
  "teamId": null,
  "position": "a0M",
  "archived": false,
  "If-Match": "7"
}
Field Notes
title, icon, coverUrl, description, isPrivate, properties Metadata updates.
parentId + position Move. parentId: null moves to root. Moving under a page requires EDIT on the destination parent and must not create a cycle (422 UNPROCESSABLE_ENTITY, details: [{issue: "cycle_detected"}]).
archived true = archive (hide from sidebar, keep accessible); false = unarchive.
version / If-Match Optimistic concurrency; stale → 409 CONFLICT.

200 OK — updated page object (with new version).

Errors: 400 VALIDATION_ERROR, 403 FORBIDDEN, 404 NOT_FOUND, 409 CONFLICT (stale version), 422 UNPROCESSABLE_ENTITY (cycle, depth > 50, destination not writable).

Events emitted: page.updated; when the move crosses a permission boundary (different parent team) additionally page.shared (the new visible set is computed and members gain/lose access) and permission.changed (audit).


5. Trash, Restore, Purge

Deleting a page moves it to the trash (trashedAt set) — soft delete. Trash keeps the page (with subtree) for the workspace's trashRetentionDays (default 30), after which a worker purges it.

DELETE /pages/:pageId

202 Accepted

{
  "data": {
    "id": "pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9",
    "trashedAt": "2025-01-02T16:00:00.000Z",
    "scheduledPurgeAt": "2025-02-01T16:00:00.000Z",
    "subtreePageCount": 4,
    "subtreeBlockCount": 152
  }
}

Errors: 403 FORBIDDEN, 404 NOT_FOUND, 409 CONFLICT (already trashed → details: [{issue: "already_trashed"}]).

Events emitted: page.deleted (trash, not hard delete). Search index marks the document hidden; child pages keep their trashedAt via the subtree.


POST /pages/:pageId/restore

Restore a trashed page (with its whole subtree) to its previous parent and position. If the previous parent was itself deleted, the page is restored to the nearest still-existing ancestor.

200 OK

{
  "data": {
    "id": "pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9",
    "trashedAt": null,
    "restoredAt": "2025-01-02T17:30:00.000Z",
    "parentId": null,
    "position": "a0",
    "subtreeRestoredPageCount": 4
  }
}

Errors: 404 NOT_FOUND (not in trash / already purged), 409 CONFLICT (not trashed), 403 FORBIDDEN.

Events emitted: page.restored.


POST /pages/:pageId/purge

Hard delete immediately (bypasses retention): page, subtree, blocks, comments, versions, and search documents are removed. The object-storage files are orphaned and reclaimed by the storage worker.

Request (confirmation):

{ "confirm": "pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9" }

The body confirm must equal the page id (typo protection).

202 Accepted

{ "data": { "id": "pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9", "status": "purging" } }

Errors: 400 VALIDATION_ERROR (bad confirm), 403 FORBIDDEN, 404 NOT_FOUND.

Events emitted: page.purged (audit, subtree stats recorded).


6. Favorites

Favorites are per-user and per-workspace; the sidebar "Favorites" section lists them in the user-chosen order (fractional position).

POST /pages/:pageId/favorite

Request (optional):

{ "position": "a0" }

201 Created

{
  "data": {
    "id": "fav_01J9ZKQ9J5L7M9N1P3Q5R7S9T1",
    "workspaceId": "wks_01J9ZKP5C9H7J9K1L3M5N7P9Q1",
    "userId": "usr_01J9ZKQX4V2M8N3P5R7T9W1Y3A",
    "pageId": "pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9",
    "position": "a0",
    "createdAt": "2025-01-02T16:05:00.000Z"
  }
}

Errors: 403 FORBIDDEN (API key / no VIEW), 404 NOT_FOUND, 409 CONFLICT (already favorited).

Events emitted: page.favorited.

DELETE /pages/:pageId/favorite

204 No Content (idempotent).

Events emitted: page.unfavorited.

GET /favorites

List the caller's favorites across the workspace, in position order. Query: cursor, limit. Returns favorite objects with an embedded page preview (id, title, icon, updatedAt). pageIds whose page the user no longer can see are omitted, and nextCursor reflects the filtered page.


7. Versions (Page History)

Every significant page mutation (title/metadata edit, structural block change, move, trash/restore) snapshots the page + block tree into page_versions. Snapshots are retained per plan (default: 90 days, 500 versions).

GET /pages/:pageId/versions

Query: cursor, limit (default 20, max 100), ordered newest first.

200 OK

{
  "data": [
    {
      "id": "pvn_01J9ZKQA0B2C4D6E8F0A2B4C6",
      "pageId": "pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9",
      "version": 7,
      "note": "Renamed to 'Product Launch Plan v2'",
      "createdBy": "usr_01J9ZKQ2V4W6X8Y0Z2A4B6C8D0",
      "createdAt": "2025-01-02T14:41:00.000Z",
      "sizeBytes": 48213
    },
    {
      "id": "pvn_01J9ZKQ9Z1A3B5C7D9E1F3A5B7",
      "pageId": "pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9",
      "version": 6,
      "note": null,
      "createdBy": "usr_01J9ZKQX4V2M8N3P5R7T9W1Y3A",
      "createdAt": "2025-01-02T12:10:00.000Z",
      "sizeBytes": 47102
    }
  ],
  "nextCursor": "cHVuXzAxSlpaS1E5WjFBM0I1QzdEOUUxRjNBNUI3"
}

Errors: 401 UNAUTHORIZED, 403 FORBIDDEN, 404 NOT_FOUND.


GET /pages/:pageId/versions/:version

Fetch one snapshot: the full page object plus the complete block tree as of that version (read-only; blocks use the same shape as GET /pages/:id?include=blocks).

200 OK

{
  "data": {
    "id": "pvn_01J9ZKQ9Z1A3B5C7D9E1F3A5B7",
    "page": { "id": "pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9", "title": "Product Launch Plan", "version": 6, "…": "…" },
    "blocks": [ { "id": "blk_…", "type": "heading_1", "content": { "text": "Objectives" }, "…": "…" } ],
    "createdAt": "2025-01-02T12:10:00.000Z"
  }
}

Errors: 404 NOT_FOUND (version pruned), 403 FORBIDDEN.


POST /pages/:pageId/versions/:version/restore

Replace the page's current content (metadata + block tree) with the snapshot. This is a new mutation: it creates a new current version whose note is "Restored from version N", so the restore itself is also restorable.

200 OK

{
  "data": {
    "id": "pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9",
    "version": 8,
    "restoredFromVersion": 6,
    "updatedAt": "2025-01-02T18:00:00.000Z"
  }
}

Errors: 403 FORBIDDEN, 404 NOT_FOUND (version pruned or page), 409 CONFLICT (page trashed — restore it first).

Events emitted: page.updated, page.version_restored.


POST /pages/:pageId/versions

Create a named manual snapshot (UI "Save version"). Useful before risky edits; also the only way for API clients to pin a point in time.

Request: { "note": "Before restructure" } → 201 Created with the version object.

Errors: 400 VALIDATION_ERROR, 403 FORBIDDEN, 404 NOT_FOUND, 409 CONFLICT (version cap reached for this plan).

Events emitted: page.version_created.


8. Duplicate

POST /pages/:pageId/duplicate

Deep-copy a page: metadata (icon/cover kept), the full block tree (new block ids), and all child pages. File references are shared (not re-uploaded); databases embedded via database blocks are not cloned — the clone links the same database. Comments are not copied.

Request:

{
  "parentId": "pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9",
  "position": "a0M",
  "title": "Product Launch Plan (Copy)",
  "includeChildren": true
}
Field Required Notes
parentId no Destination; default = source's parent.
position no Default appends after the source.
title no Default "<source title> (Copy)".
includeChildren no Default true.

201 Created

{
  "data": {
    "id": "pg_01J9ZKQB1C3D5E7F9A1B3C5D7",
    "sourceId": "pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9",
    "title": "Product Launch Plan (Copy)",
    "parentId": "pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9",
    "position": "a0M",
    "copiedBlockCount": 48,
    "copiedPageCount": 3,
    "createdAt": "2025-01-02T18:20:00.000Z"
  }
}

Errors: 403 FORBIDDEN, 404 NOT_FOUND, 409 CONFLICT (source trashed), 422 UNPROCESSABLE_ENTITY (destination cycle), 413 PAYLOAD_TOO_LARGE (subtree exceeds 20 000 blocks → details: [{maxBlocks: 20000}]).

Events emitted: page.duplicated.


9. Position Semantics (Fractional Ordering)

Pages (and blocks, properties, records, teams) are never ordered by array index. Order is a fractional string (position) comparable lexicographically, using a base-64 alphabet ("0"…"9", "a"…"z", "A"…"Z" → keys like a0, a0V, a0M, a1). This is a LexoRank-style scheme: inserting between two items only changes the inserted row, never its neighbors.

Siblings in order:        position
  "Product Launch Plan"   a0
  "Q2 Launch Checklist"   a0V
  "Risks & Mitigations"   a1

Rules:


10. Export

POST /pages/:pageId/export

Export a page (optionally its subtree) as a file. Export is an async job: the response returns a job id; poll it or subscribe to export.completed via webhooks. Formats: markdown, html, pdf.

Request:

{
  "format": "markdown",
  "includeChildren": true,
  "includeFiles": false
}
Field Notes
format markdown | html | pdf.
includeChildren Default true — nested pages become files in the archive.
includeFiles Default false — when true, embedded files are included in a .zip (multi-page exports are always zipped; single-page exports return the raw file).

202 Accepted

{
  "data": {
    "jobId": "job_01J9ZKQC2D4E6F8A0B2C4D6E8A",
    "pageId": "pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9",
    "format": "markdown",
    "status": "PENDING",
    "createdAt": "2025-01-02T18:30:00.000Z"
  }
}

Errors: 403 FORBIDDEN, 404 NOT_FOUND, 409 CONFLICT (page trashed — restore first), 422 UNPROCESSABLE_ENTITY (unknown format).


GET /pages/:pageId/export/:jobId

Poll the export job.

200 OK (when done)

{
  "data": {
    "jobId": "job_01J9ZKQC2D4E6F8A0B2C4D6E8A",
    "status": "COMPLETED",
    "downloadUrl": "https://factory.example.com/api/v1/jobs/job_01J9ZKQC2D4E6F8A0B2C4D6E8A/download",
    "fileName": "Product-Launch-Plan.zip",
    "sizeBytes": 182440,
    "expiresAt": "2025-01-09T18:30:00.000Z",
    "fileCount": 4,
    "createdAt": "2025-01-02T18:30:00.000Z",
    "finishedAt": "2025-01-02T18:30:04.211Z"
  }
}

While running: status: "PENDING" | "RUNNING" (no downloadUrl). On failure: status: "FAILED", error: {code, message} (same error model). Downloads from downloadUrl are signed, single-link, 7-day expiry.

Events emitted: page.export_completed (on completion; webhooks can subscribe) — the job itself is not a domain event.


11. curl Examples

# Create a page under a parent
curl -s -X POST https://factory.example.com/api/v1/pages \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"parentId":"pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9","title":"Q2 Launch Checklist","icon":"✅","position":"a0V"}'

# Fetch page with blocks + children
curl -s "https://factory.example.com/api/v1/pages/pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9?include=blocks,children" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

# Move + rename (optimistic concurrency)
curl -s -X PATCH https://factory.example.com/api/v1/pages/pg_01J9ZKQ8H3I5J7L9M1N3P5Q7R9 \
  -H "Authorization: Bearer $ACCESS_TOKEN" -H 'Content-Type: application/json' -H 'If-Match: "4"' \
  -d '{"title":"Risks","parentId":null,"position":"a0"}'

# Trash, then restore
curl -s -X DELETE https://factory.example.com/api/v1/pages/pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9 \
  -H "Authorization: Bearer $ACCESS_TOKEN"
curl -s -X POST https://factory.example.com/api/v1/pages/pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9/restore \
  -H "Authorization: Bearer $ACCESS_TOKEN"

# Favorite
curl -s -X POST https://factory.example.com/api/v1/pages/pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9/favorite \
  -H "Authorization: Bearer $ACCESS_TOKEN"

# Restore an old version
curl -s -X POST https://factory.example.com/api/v1/pages/pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9/versions/6/restore \
  -H "Authorization: Bearer $ACCESS_TOKEN"

# Export to PDF, async
curl -s -X POST https://factory.example.com/api/v1/pages/pg_01J9ZKQ4F8H5I7J9L1M3N5P7Q9/export \
  -H "Authorization: Bearer $ACCESS_TOKEN" -H 'Content-Type: application/json' \
  -d '{"format":"pdf","includeChildren":true}'

12. Recorded conflicts (AGENTS.md rule 29)

  1. POST /templates/:id/apply requires a workspace — the implementation (pages.controller.ts) takes the destination workspace from body. workspaceId or the X-Factory-Workspace header and returns 400 VALIDATION_ERROR when neither is present. Neither docs/api/ openapi.yaml (no body, no header parameter on the operation) nor docs/product/functional-requirements.md §templates (names the route POST /templates/:id/instantiate {targetParentId}) documents this. The web app always sends workspaceId in the body (its fetch layer never sets X-Factory-Workspace). Resolution: the implementation is authoritative (it is the enforced contract and the web is aligned to it); aligning the docs — and deciding apply vs instantiate naming — is a separate documentation task. Recorded, not resolved here.
  2. Members list wire shape (flat) vs docs/api/workspaces.md §3.1 (nested) — full note in docs/tasks/phase-02-workspace.md (task "Recorded conflict"). The web normalizes at its API boundary; the API stays flat until the e2e + integration suites are updated together.

13. Events Summary

Operation Domain event(s)
Create page page.created
Update/move/archive page page.updated (+ page.shared when visibility set changes, permission.changed audit)
Trash page page.deleted
Restore from trash page.restored
Purge page page.purged (audit)
Favorite / unfavorite page.favorited / page.unfavorited
List versions — (read)
Read one version — (read)
Restore version page.updated, page.version_restored
Manual snapshot page.version_created
Duplicate page page.duplicated
Export finished page.export_completed