.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.controller.tsapps/api/src/modules/pages/pages.controller.tsraw← pages12,821 B← Back to the app
1import { Inject, Body, Controller, Delete, Get, Param, Patch, Post, Put, Query, Req, Res } from "@nestjs/common";
2import type { Request, Response } from "express";
3import { PageService } from "./page.service.js";
4import { ReviewService } from "./review.service.js";
5import { ZodValidate } from "../../common/pipes/zod-validation.pipe.js";
6import { requireActor } from "../../common/types.js";
7import { ReviewActionDto, type ReviewActionInput } from "./review.dto.js";
8import { ApiError } from "../../common/errors.js";
9import {
10  ApplyTemplateDto,
11  type ApplyTemplateInput,
12  BulkPagesDto,
13  type BulkPagesInput,
14  CreatePageDto,
15  type CreatePageInput,
16  ConvertSelectionDto,
17  type ConvertSelectionInput,
18  CompareVersionsQuery,
19  type CompareVersionsInput,
20  CreateTemplateDto,
21  type CreateTemplateInput,
22  DuplicatePageDto,
23  type DuplicatePageInput,
24  ListPagesQuery,
25  type ListPagesInput,
26  MovePageDto,
27  type MovePageInput,
28  UpdatePageDto,
29  type UpdatePageInput
30} from "./dto.js";
31 
32@Controller()
33export class PagesController {
34  constructor(
35    @Inject(PageService) private readonly pages: PageService,
36    @Inject(ReviewService) private readonly reviews: ReviewService
37  ) {}
38 
39  // ---------- workspace-scoped ----------
40 
41  @Get("workspaces/:workspaceId/pages")
42  list(
43    @Param("workspaceId") workspaceId: string,
44    @Query(ZodValidate(ListPagesQuery)) query: ListPagesInput,
45    @Req() req: Request
46  ) {
47    return this.pages.list(workspaceId, requireActor(req), query);
48  }
49 
50  @Post("workspaces/:workspaceId/pages")
51  create(
52    @Param("workspaceId") workspaceId: string,
53    @Body(ZodValidate(CreatePageDto)) body: CreatePageInput,
54    @Req() req: Request
55  ) {
56    // Zod allows `parentId: null` (wire); the service takes `parentId?: string`
57    // (null ≡ top level — coalesce, same as `?? null` on the service side).
58    return this.pages.create(workspaceId, requireActor(req), { ...body, parentId: body.parentId ?? undefined }, req);
59  }
60 
61  // ---------- page-scoped ----------
62 
63  @Get("pages/:id")
64  get(@Param("id") id: string, @Req() req: Request) {
65    return this.pages.get(id, requireActor(req));
66  }
67 
68  // ---------- T-180: content export (Phase 8) ----------
69 
70  /**
71   * `GET /pages/:id/export/markdown` — download the page (and, with
72   * `?includeChildren=1`, its sub-pages) as Markdown. VIEW-gated server-side
73   * (same level as `GET /pages/:id`); the export is AUDITED (`page.exported`).
74   * The service renders the markdown; the controller only sets the download
75   * headers and sends the body (mirrors the database CSV export route).
76   */
77  @Get("pages/:id/export/markdown")
78  async exportMarkdown(
79    @Param("id") id: string,
80    @Query("includeChildren") includeChildren: string | undefined,
81    @Req() req: Request,
82    @Res() res: Response
83  ) {
84    const { markdown, filename } = await this.pages.exportMarkdown(
85      id,
86      requireActor(req),
87      { includeChildren: includeChildren === "1" || includeChildren === "true" },
88      req
89    );
90    res.setHeader("Content-Type", "text/markdown; charset=utf-8");
91    res.setHeader("Content-Disposition", `attachment; filename="${filename}"`);
92    res.send(markdown);
93  }
94 
95  // ---------- T-162/T-163: review workflow (banner state + actions) ----------
96 
97  @Get("pages/:id/review")
98  reviewState(@Param("id") id: string, @Req() req: Request) {
99    return this.reviews.reviewState(id, requireActor(req));
100  }
101 
102  @Post("pages/:id/review")
103  reviewAct(
104    @Param("id") id: string,
105    @Body(ZodValidate(ReviewActionDto)) body: ReviewActionInput,
106    @Req() req: Request
107  ) {
108    return this.reviews.act(id, requireActor(req), body, req);
109  }
110 
111  @Patch("pages/:id")
112  update(
113    @Param("id") id: string,
114    @Body(ZodValidate(UpdatePageDto)) body: UpdatePageInput,
115    @Req() req: Request
116  ) {
117    return this.pages.update(id, requireActor(req), body, req);
118  }
119 
120  // ---------- T-167: whiteboard canvas (page kind) ----------
121  //
122  // The canvas document is validated by the zero-dep `@factory/whiteboard`
123  // schema (a plain object — no Zod DTO: `validateCanvas` already returns a
124  // field-level error list the service turns into a 400 envelope). The save
125  // body may exceed the global 256 KB JSON cap — it is buffered by the
126  // route-scoped `whiteboard-body.ts` parser (2 MB, 413 past it).
127 
128  @Get("pages/:id/whiteboard")
129  getCanvas(@Param("id") id: string, @Req() req: Request) {
130    return this.pages.getCanvas(id, requireActor(req));
131  }
132 
133  @Put("pages/:id/whiteboard")
134  saveCanvas(
135    @Param("id") id: string,
136    @Body() canvas: unknown,
137    @Req() req: Request
138  ) {
139    return this.pages.saveCanvas(id, requireActor(req), canvas, req);
140  }
141 
142  // T-171: convert a whiteboard selection into a real page (or task page).
143  @Post("pages/:id/whiteboard/convert")
144  convertSelection(
145    @Param("id") id: string,
146    @Body(ZodValidate(ConvertSelectionDto)) body: ConvertSelectionInput,
147    @Req() req: Request
148  ) {
149    return this.pages.convertSelection(id, requireActor(req), body, req);
150  }
151 
152  @Delete("pages/:id")
153  trash(@Param("id") id: string, @Req() req: Request) {
154    return this.pages.trash(id, requireActor(req), req);
155  }
156 
157  @Delete("pages/:id/permanent")
158  deletePermanent(@Param("id") id: string, @Req() req: Request) {
159    return this.pages.deletePermanent(id, requireActor(req), req).then(() => ({ deleted: true }));
160  }
161 
162  @Post("pages/:id/restore")
163  restore(@Param("id") id: string, @Req() req: Request) {
164    return this.pages.restore(id, requireActor(req), req);
165  }
166 
167  // ---------- T-138: duplicate ----------
168 
169  @Post("pages/:id/duplicate")
170  duplicate(
171    @Param("id") id: string,
172    @Body(ZodValidate(DuplicatePageDto)) body: DuplicatePageInput,
173    @Req() req: Request
174  ) {
175    return this.pages.duplicate(id, requireActor(req), { parentId: body.parentId ?? undefined, title: body.title }, req);
176  }
177 
178  // ---------- T-139: bulk ----------
179 
180  @Post("pages/bulk")
181  bulk(
182    @Body(ZodValidate(BulkPagesDto)) body: BulkPagesInput,
183    @Req() req: Request
184  ) {
185    const workspaceId = req.headers["x-factory-workspace"];
186    if (typeof workspaceId !== "string" || !workspaceId) {
187      throw ApiError.validation("workspaceId is required (X-Factory-Workspace header).", [
188        { field: "workspaceId", issue: "required" }
189      ]);
190    }
191    return this.pages.bulk(workspaceId, requireActor(req), body, req);
192  }
193 
194  // ---------- T-140: backlinks ----------
195 
196  @Get("pages/:id/backlinks")
197  backlinks(@Param("id") id: string, @Req() req: Request) {
198    return this.pages.backlinks(id, requireActor(req));
199  }
200 
201  // ---------- T-149: cross-workspace move ----------
202 
203  @Post("pages/:id/move")
204  move(
205    @Param("id") id: string,
206    @Body(ZodValidate(MovePageDto)) body: MovePageInput,
207    @Req() req: Request
208  ) {
209    return this.pages.moveCrossWorkspace(id, requireActor(req), { toWorkspaceId: body.toWorkspaceId, toParentId: body.toParentId ?? undefined }, req);
210  }
211 
212  // ---------- versions ----------
213 
214  @Get("pages/:id/versions")
215  versions(@Param("id") id: string, @Req() req: Request) {
216    return this.pages.listVersions(id, requireActor(req));
217  }
218 
219  // T-150: declared BEFORE `:versionId` — Nest matches routes in order and
220  // the literal segment must win.
221  @Get("pages/:id/versions/compare")
222  compareVersions(
223    @Param("id") id: string,
224    @Query(ZodValidate(CompareVersionsQuery)) query: CompareVersionsInput,
225    @Req() req: Request
226  ) {
227    return this.pages.compareVersions(id, query.from, query.to, requireActor(req));
228  }
229 
230  @Post("pages/:id/versions")
231  createVersion(@Param("id") id: string, @Body() body: { note?: string } | undefined, @Req() req: Request) {
232    return this.pages.createVersion(id, requireActor(req), body?.note);
233  }
234 
235  // T-151: read-only preview of one version's snapshot.
236  @Get("pages/:id/versions/:versionId")
237  getVersionPreview(@Param("id") id: string, @Param("versionId") versionId: string, @Req() req: Request) {
238    return this.pages.getVersionPreview(id, versionId, requireActor(req));
239  }
240 
241  @Post("pages/:id/versions/:versionId/restore")
242  restoreVersion(
243    @Param("id") id: string,
244    @Param("versionId") versionId: string,
245    @Req() req: Request
246  ) {
247    return this.pages.restoreVersion(id, versionId, requireActor(req), req);
248  }
249 
250  // ---------- T-157: watchlist ----------
251 
252  @Get("pages/:id/watch")
253  isWatching(@Param("id") id: string, @Req() req: Request) {
254    return this.pages.isWatching(id, requireActor(req));
255  }
256 
257  @Post("pages/:id/watch")
258  watch(@Param("id") id: string, @Req() req: Request) {
259    return this.pages.watch(id, requireActor(req));
260  }
261 
262  @Delete("pages/:id/watch")
263  unwatch(@Param("id") id: string, @Req() req: Request) {
264    return this.pages.unwatch(id, requireActor(req));
265  }
266 
267  // ---------- favorites ----------
268 
269  @Get("pages/:id/favorite")
270  favorite(@Param("id") id: string, @Req() req: Request) {
271    return this.pages.isFavorite(id, requireActor(req));
272  }
273 
274  @Post("pages/:id/favorite")
275  addFavorite(@Param("id") id: string, @Req() req: Request) {
276    return this.pages.favorite(id, requireActor(req));
277  }
278 
279  @Delete("pages/:id/favorite")
280  removeFavorite(@Param("id") id: string, @Req() req: Request) {
281    return this.pages.unfavorite(id, requireActor(req));
282  }
283 
284  // ---------- templates ----------
285 
286  @Post("pages/:id/templates")
287  createTemplate(
288    @Param("id") id: string,
289    @Body(ZodValidate(CreateTemplateDto)) body: CreateTemplateInput,
290    @Req() req: Request
291  ) {
292    return this.pages.createTemplate(id, requireActor(req), body, req);
293  }
294 
295  @Get("workspaces/:workspaceId/templates")
296  templates(
297    @Param("workspaceId") workspaceId: string,
298    @Query("type") type: string | undefined,
299    @Query("category") category: string | undefined,
300    @Query("search") search: string | undefined,
301    @Req() req: Request
302  ) {
303    // T-141: additive directory filters (no params = previous behavior).
304    return this.pages.listTemplates(workspaceId, requireActor(req), type, { category, search });
305  }
306 
307  @Post("templates/:id/apply")
308  applyTemplate(
309    @Param("id") id: string,
310    @Body(ZodValidate(ApplyTemplateDto)) body: ApplyTemplateInput,
311    @Req() req: Request
312  ) {
313    const workspaceId = body.workspaceId ?? req.headers["x-factory-workspace"];
314    if (typeof workspaceId !== "string" || !workspaceId) {
315      throw ApiError.validation("workspaceId is required (body or X-Factory-Workspace header).", [
316        { field: "workspaceId", issue: "required" }
317      ]);
318    }
319    // Zod allows `parentId: null` (wire); the service takes `parentId?: string`
320    // (null ≡ top level — coalesce, same as `?? null` on the service side).
321    return this.pages.applyTemplate(workspaceId, requireActor(req), id, { parentId: body.parentId ?? undefined, title: body.title, values: body.values }, req);
322  }
323 
324  /** T-141: read-only preview of the template's CURRENT snapshot. ID-scoped
325   *  (no workspace header): the directory is a cross-workspace union whose
326   *  rows carry no workspaceId — the service authorizes against the
327   *  template's OWN workspace membership. */
328  @Get("templates/:id/preview")
329  previewTemplate(@Param("id") id: string, @Req() req: Request) {
330    return this.pages.previewTemplate(id, requireActor(req));
331  }
332 
333  // ---------- T-145: template version history ----------
334 
335  @Post("templates/:id/versions")
336  createTemplateVersion(
337    @Param("id") id: string,
338    @Body() body: { note?: string } | undefined,
339    @Req() req: Request
340  ) {
341    const workspaceId = req.headers["x-factory-workspace"];
342    if (typeof workspaceId !== "string" || !workspaceId) {
343      throw ApiError.validation("workspaceId is required (X-Factory-Workspace header).", [{ field: "workspaceId", issue: "required" }]);
344    }
345    return this.pages.createTemplateVersion(id, workspaceId, requireActor(req), body?.note, req);
346  }
347 
348  @Get("templates/:id/versions")
349  listTemplateVersions(@Param("id") id: string, @Req() req: Request) {
350    const workspaceId = req.headers["x-factory-workspace"];
351    if (typeof workspaceId !== "string" || !workspaceId) {
352      throw ApiError.validation("workspaceId is required (X-Factory-Workspace header).", [{ field: "workspaceId", issue: "required" }]);
353    }
354    return this.pages.listTemplateVersions(id, workspaceId, requireActor(req));
355  }
356 
357  @Post("templates/:id/versions/:versionId/restore")
358  restoreTemplateVersion(
359    @Param("id") id: string,
360    @Param("versionId") versionId: string,
361    @Req() req: Request
362  ) {
363    const workspaceId = req.headers["x-factory-workspace"];
364    if (typeof workspaceId !== "string" || !workspaceId) {
365      throw ApiError.validation("workspaceId is required (X-Factory-Workspace header).", [{ field: "workspaceId", issue: "required" }]);
366    }
367    return this.pages.restoreTemplateVersion(id, versionId, workspaceId, requireActor(req), req);
368  }
369}
370