.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
phase-00-foundation.mddocs/tasks/phase-00-foundation.md← tasks46,885 B← Back to the app

Phase 0 — Foundation: Task Specifications

Purpose: Bring the scaffold to the point where a clean clone can pnpm install, spin up the dev stack (postgres, redis, minio, opensearch), apply the first Prisma migration + seed, boot all four apps, and pass a green CI pipeline. No feature work. Tasks run strictly in order, TASK-0001 → TASK-0012. Phase exit criteria (verbatim from ROADMAP.md): pnpm install && pnpm docker:up && pnpm db:migrate && pnpm dev works from a clean clone; CI is green; all apps/packages build and typecheck.

Task Table

ID Title Est.
TASK-0001 Monorepo init (pnpm workspaces + Turborepo) S
TASK-0002 TypeScript strict setup (packages/config base tsconfig) S
TASK-0003 ESLint + Prettier (root + per-app overrides) M
TASK-0004 Docker compose dev environment (infrastructure/docker) M
TASK-0005 Env validation (zod env schemas + .env.example) M
TASK-0006 Prisma init migration + seed M
TASK-0007 CI pipeline (GitHub Actions ci.yml + release.yml) M
TASK-0008 Testing bootstrap (Vitest, Playwright, Testcontainers, k6) M
TASK-0009 Health endpoints for all 4 apps S
TASK-0010 Observability baseline (pino, requestId, OTEL stub off) M
TASK-0011 Seed data verification S
TASK-0012 Clean-clone verification runbook test M

Phase Completion Checklist

TASK-0001

Title

Monorepo initialization (pnpm workspaces + Turborepo)

Objective

Make the repo one scriptable pnpm workspace with a Turborepo pipeline so root commands (pnpm dev|build|lint|typecheck|test|docker:*|db:*) work everywhere and are cached.

Background

Scaffold already has pnpm-workspace.yaml, turbo.json, root package.json, apps/{web, api,worker, realtime} and 10 packages/*; verify/complete the wiring, do not create new architecture.

Requirements

  1. pnpm-workspace.yaml lists exactly apps/* and packages/*; packageManager pinned; engines node >=20 <23, pnpm >=9; .npmrc engine-strict.
  2. Root scripts: dev, build, lint, lint:fix, format, format:check, typecheck, test, test:integration, test:e2e, test:perf, docker:up, docker:down, docker:logs, db:migrate, db:deploy, db:seed, db:verify, db:studio, check (delegate to turbo / pnpm -r / docker compose / prisma).
  3. turbo.json: dev (persistent, uncached), build (dependsOn ^build, outputs dist/**), lint, typecheck, test (dependsOn ^build), test:integration, test:e2e; global env NODE_ENV, PORT, DATABASE_URL, REDIS_URL, LOG_LEVEL.
  4. Git baseline (AGENTS.md): main + develop; husky pre-commit (eslint --fix + prettier --write on staged, typecheck on changed workspace) + conventional-commit check.
  5. .gitignore: node_modules, dist, .next, .turbo, coverage, .env, test-results, playwright-report; .env.example tracked, .env never committed.

Acceptance Criteria

  1. Fresh clone: pnpm install && pnpm build succeeds in every workspace.
  2. pnpm typecheck fails root-level on any workspace type error; passes when clean (both directions verified).
  3. Second pnpm build shows Turborepo cache hit for unchanged workspaces.
  4. docker:up, db:migrate, db:seed, dev exist and wire to TASK-0004/0006 commands.
  5. A commit containing a lint error is blocked by the pre-commit hook.

Backend Changes

Frontend Changes

Database Changes

None

API Changes

None

Tests

Security

Documentation

Dependencies

None (first task of the phase).

Definition of Done

All criteria verified on a clean clone; pre-commit hook demonstrated; pnpm check green.

TASK-0002

Title

TypeScript strict setup (packages/config base tsconfig)

Objective

One shared strict tsconfig extended by every app and package, so pnpm typecheck is a single trustworthy gate with identical strictness.

Background

packages/config is the designated shared-config home and is currently empty; workspaces use ad-hoc or missing tsconfigs. Centralize without breaking existing sources.

Requirements

  1. packages/config/tsconfig.base.json: strict, noUncheckedIndexedAccess, noImplicitOverride, noFallthroughCasesInSwitch, forceConsistentCasingInFileNames true; target ES2022, lib [ES2022], module ESNext, moduleResolution Bundler, skipLibCheck, resolveJsonModule, declaration, sourceMap, isolatedModules.
  2. Every workspace tsconfig.json extends @factory/config/tsconfig.base.json, overriding only include, outDir, jsx (web), types.
  3. packages/config/src/index.ts exports the base tsconfig typed + tsconfigFor("node"|"web"); package exports map exposes the JSON file.
  4. apps/web adds .tsx + jsx: "preserve" + Next.js generated types; api/worker/realtime add types: ["node"] (NestJS moduleResolution choice documented).
  5. Root pnpm typecheck = tsc --noEmit in every workspace via turbo.

Acceptance Criteria

  1. pnpm typecheck passes in every workspace with no source changes beyond tsconfigs.
  2. Deliberate const x: number = "s" in any workspace fails with the workspace name visible (verified, reverted).
  3. No workspace tsconfig disables strict (enforced by config test).
  4. Unguarded indexed array access fails typecheck (noUncheckedIndexedAccess active).

Backend Changes

Frontend Changes

Database Changes

None

API Changes

None

Tests

Security

None

Documentation

Dependencies

Definition of Done

Base tsconfig shipped; all workspaces extend it; typecheck green; config test passing.

TASK-0003

Title

ESLint + Prettier (root + per-app overrides)

Objective

One flat ESLint config with per-app overrides + one root Prettier config, so pnpm lint / pnpm format:check enforce style and catch real bugs monorepo-wide.

Background

No lint config exists. Next.js' own setup would duplicate rules; the root owns the config and apps/web only contributes the next/core-web-vitals override.

Requirements

  1. Root eslint.config.mjs (flat): typescript-eslint recommended-type-checked for **/*.ts; react + react-hooks for apps/web/**/*.{ts, tsx}; no-explicit-any warn globally, error in packages/permissions|shared|auth; no-eval: error everywhere (formula-safety invariant).
  2. apps/web override: next/core-web-vitals; ignore .next/, next-env.d.ts. apps/api + apps/worker override: no Next rules; no-console warn (apps use the pino logger from TASK-0010).
  3. Root .prettierrc.json (singleQuote, semi, trailingComma all, printWidth 100) + .prettierignore for generated dirs.
  4. Root scripts lint, lint:fix, format, format:check; eslint cache git-ignored; lint on the scaffold tree < 60 s.

Acceptance Criteria

  1. pnpm lint passes on the scaffold with zero errors after this task.
  2. A console.log in apps/api/src (warn) and a : any cast in packages/shared/src (error) are both flagged; reverted afterwards.
  3. pnpm format:check fails on an unformatted file; pnpm format fixes it.
  4. No rule is defined in two places (single flat config).

Backend Changes

Frontend Changes

Database Changes

None

API Changes

None

Tests

Security

Documentation

Dependencies

Definition of Done

Single config + Prettier in place; lint/format commands pass; demo violations caught.

TASK-0004

Title

Docker compose dev environment (infrastructure/docker)

Objective

Implement/verify the dev infrastructure per infrastructure/docker/docker-compose.yml: postgres, redis, minio, opensearch (default profile) + Dockerfiles for the 4 apps (apps profile), so pnpm docker:up yields a healthy, port-stable environment.

Background

infrastructure/docker/ is an empty directory; this task creates the compose file (source of truth for dev infra) and the four dev Dockerfiles. Ports/credentials interpolate from the root .env (TASK-0005). k8s/terraform stay out of scope.

Requirements

  1. infrastructure/docker/docker-compose.yml, default profile — postgres: postgres:16-alpine, db/user/pass from env, port ${POSTGRES_PORT:-5432}, volume pgdata, healthcheck pg_isready — redis: redis:7-alpine, ${REDIS_PORT:-6379}, volume, healthcheck redis-cli ping — minio: pinned tag, S3 ${MINIO_PORT:-9000} + console ${MINIO_CONSOLE_PORT:-9001}, volume, healthcheck /minio/health/live, plus minio-init sidecar (mc alias + mb -p buckets factory-files, factory-avatars) — opensearch: opensearchproject/opensearch:2.17.1 single-node (security plugin disabled, dev), ${OPENSEARCH_PORT:-9200}, volume, healthcheck _cluster/health.
  2. apps profile: web, api, worker, realtime from apps/<app>/Dockerfile — multi-stage dev images (node:20-alpine + corepack pnpm, source volume-mounted, pnpm dev, watch). Ports: web 3000, api 4000, worker 4003, realtime 4001 (WS on same port).
  3. Named volume per stateful service; one network factory-dev; no bare latest for postgres/redis/opensearch; minio tag pinned with "pin weekly" comment.
  4. All credentials/ports via env interpolation with dev-only defaults; nothing in the file is production-correct.
  5. docker compose config validates; pnpm docker:up = default profile up -d; pnpm docker:up:apps adds --profile apps.

Acceptance Criteria

  1. pnpm docker:up on a clean machine brings all 4 dependency services to healthy in < 120 s (docker compose ps).
  2. psql, redis-cli, mc, and OpenSearch _cluster/health all succeed using only .env.example values.
  3. pnpm docker:up:apps boots all 4 apps; curl http://localhost:4000 responds.
  4. pnpm docker:down leaves no orphaned containers/networks; volumes survive down, removed by down -v (documented).
  5. Changing POSTGRES_PORT in .env changes the published port without editing compose.

Backend Changes

Frontend Changes

Database Changes

None (reachability only; migration is TASK-0006).

API Changes

None

Tests

Security

Documentation

Dependencies

Definition of Done

Compose + 4 Dockerfiles done; all 5 criteria verified on a clean machine; config test green.

TASK-0005

Title

Environment validation (zod env schemas + .env.example)

Objective

Every app fails fast with a readable error on missing/malformed env; .env.example is the single source of truth; zod schemas in packages/config are the single validator.

Background

Apps currently read process.env ad hoc. AGENTS.md requires all secrets from env variables documented in .env.example. packages/config (TASK-0002) hosts the schemas.

Requirements

  1. packages/config/src/env.ts (zod): appEnvSchema (NODE_ENV, APP_NAME, LOG_LEVEL default info, PORT); postgresEnvSchema (DATABASE_URL prefix postgresql://); redisEnvSchema (REDIS_URL prefix redis://); storageEnvSchema (S3_ENDPOINT, S3_REGION, S3_BUCKET_FILES, S3_BUCKET_AVATARS, S3_ACCESS_KEY, S3_SECRET_KEY, optional S3_PUBLIC_BASE_URL); apiEnvSchema (adds JWT_ACCESS_SECRET min 32, JWT_ACCESS_TTL_SECONDS 900, REFRESH_TTL_DAYS 30, BCRYPT_ROUNDS 12 (10–15), CORS_ORIGINS, optional SMTP vars, SMTP_FROM, FRONTEND_URL); workerEnvSchema; realtimeEnvSchema (+WS_ALLOWED_ORIGINS); webEnvSchema (NEXT_PUBLIC_API_URL, NEXT_PUBLIC_REALTIME_URL); helper loadEnv(schema, env, context) prints {key, expected, received} and exits 64.
  2. apps/api/src/config/env.ts exports frozen typed env via loadEnv(apiEnvSchema, process.env, "api"); equivalents in apps/worker|realtime/src/config/env.ts; apps/web/src/config/env.ts (server-side; NEXT_PUBLIC_* build-time reads = only documented exception).
  3. Root .env.example documents every variable (grouped, commented, dev defaults matching TASK-0004); a test enforces 100% two-way key coverage vs the schemas.
  4. Lint rule: no process.env outside src/config dirs in any app; error output names the app, variable, expected shape, and points at .env.example.

Acceptance Criteria

  1. api boot with JWT_ACCESS_SECRET unset exits 64 naming the variable (unit + manual).
  2. Malformed REDIS_URL (wrong prefix) fails fast in every app that needs it.
  3. Coverage test passes, and fails when a key exists in .env.example but not any schema (and vice versa).
  4. Zero process.env. hits outside config dirs (grep audit recorded in commit).

Backend Changes

Frontend Changes

Database Changes

None

API Changes

None

Tests

Security

Documentation

Dependencies

Definition of Done

Schemas + loadEnv shipped; all 4 apps boot through it; coverage test green; fail-fast demonstrated.

TASK-0006

Title

Prisma init migration + seed

Objective

Generate the first Prisma migration from prisma/schema.prisma and an idempotent seed, so pnpm db:migrate && pnpm db:seed works from a clean clone with known demo data.

Background

The schema already defines the full domain (User, Session, RefreshToken, EmailVerification, PasswordReset, Workspace, WorkspaceMember, Invitation, Team, TeamMember, Page, PageFavorite, PageVersion, Block, Database, DatabaseProperty, DatabaseView, DatabaseRecord, RecordProperty, Comment, Share, Permission, AuditLog, …); no migration exists yet and prisma/seed.ts must be created.

Requirements

  1. pnpm db:migrate = prisma migrate dev --name init → creates prisma/migrations/<timestamp>_init/ + applies; pnpm db:deploy = migrate deploy (non-interactive, CI path); prisma/package.json postinstall: prisma generate; root package.json prisma block (schema, seed: tsx prisma/seed.ts).
  2. prisma/seed.ts — idempotent (upserts on natural keys) — creates: 2 users (demo@factory.local/DemoPassw0rd!, admin@factory.local/AdminPassw0rd!, bcrypt 12, VERIFIED); demo workspace "Demo Workspace" (slug demo, owned by demo user) + personal workspaces for demo & admin (slugs personal-<4 random>); 2 teams in demo ws ("Product", "Engineering", positions a0, a1 from @factory/shared/positions); 6 pages (root "Getting started" in Product with 2 direct children, 1 under Engineering, 2 root private; positions unique per parent, emoji icons); 1 database "Tasks" (5 properties: title, 2× select, date, people; 3 records with non-empty titles) + 1 TABLE view; 1 comment on "Getting started" by admin; 1 favorite (demo → "Getting started").
  3. Seed prints a per-model count summary + demo credentials (non-production only) and refuses NODE_ENV=production (exit 65).

Acceptance Criteria

  1. Fresh postgres: pnpm db:migrate creates exactly one *_init migration; prisma migrate status up to date.
  2. pnpm db:seed succeeds; psql confirms: 2 users, 5 workspaces (3 + 2 personal), demo slug demo owned by demo user, 2 teams, 6 pages, 1 database / 5 properties / 3 records, 1 comment, 1 favorite.
  3. Second pnpm db:seed leaves all counts identical (idempotent).
  4. Every seeded page position is unique per parent and orders correctly with the shared fractional comparator (checked by the seed summary script).
  5. pnpm db:deploy applies the migration on an empty database non-interactively.

Backend Changes

Frontend Changes

None

Database Changes

API Changes

None

Tests

Security

Documentation

Dependencies

Definition of Done

*_init migration applied; seed idempotent and Testcontainers-proven; db:deploy non-interactive; docs written.

TASK-0007

Title

CI pipeline (GitHub Actions ci.yml + release.yml)

Objective

Implement the AGENTS.md CI/CD contract: every PR runs install → lint → typecheck → unit → integration → build → security scan → E2E; tagged releases build images + draft a release. CI green is a Phase 0 exit criterion.

Background

No workflows exist. Integration tests use Testcontainers (TASK-0008); E2E uses the compose dev stack with migrated + seeded database (TASK-0004/0006).

Requirements

  1. .github/workflows/ci.yml (push + PR to main/develop), one job per stage: install (pnpm frozen lockfile, lockfile cache) → lint → typecheck → unit (pnpm test) → integration (Docker service, pnpm test:integration) → build (pnpm build) → security (pnpm audit --prod --audit-level=high with allowlist scripts/security/audit-allowlist.json — entries need reason + expiry; gitleaks on diff range) → e2e (compose --profile apps up -d, wait on health endpoints, migrate deploy + db:seed, pnpm test:e2e, upload playwright-report on failure). Concurrency: cancel superseded runs per branch.
  2. .github/workflows/release.yml (tag v*): tag/version match check, pnpm build, image builds for all 4 apps (tags sha + tag), push to REGISTRY secret (skipped gracefully here), draft GitHub release from the tag range.
  3. Pinned action versions/SHAs; secrets only from the secrets store; no continue-on-error anywhere; E2E is the only job needing the full stack; integration job < 15 min on default runners.

Acceptance Criteria

  1. A docs-only branch passes every ci.yml stage (run URL recorded in commit body).
  2. Deliberate unit failure, type error, lint violation each fail CI at the correct stage (throwaway branch, reverted).
  3. Security stage fails on a high-severity advisory dep; allowlist entry without expiry is rejected.
  4. v0.0.0-test tag: images build, push skipped, draft release created.
  5. Failing E2E run attaches the Playwright report artifact.

Backend Changes

Frontend Changes

None

Database Changes

None (E2E setup uses migrate deploy + db:seed against the compose postgres).

API Changes

None

Tests

Security

Documentation

Dependencies

Definition of Done

Both workflows implemented; green/red demonstrated exactly per contract; E2E artifact on failure; "CI is green" exit criterion met on the branch.

TASK-0008

Title

Testing bootstrap (Vitest, Playwright, Testcontainers, k6)

Objective

Stand up all four test layers, each with a passing smoke spec, so later phases only add specs: Vitest (packages + apps/api), Playwright (tests/e2e), Testcontainers (tests/integration), k6 (tests/performance).

Background

AGENTS.md lists "Vitest (packages) / Jest (api)"; this project standardizes on Vitest for both (one runner/coverage/config format). Per the conflict rule the deviation is recorded here and AGENTS.md updated in Documentation.

Requirements

  1. Vitest: vitest.config.ts in all test-bearing packages/* + apps/api|worker|realtime; root pnpm test = vitest run across workspaces; @vitest/coverage-v8 thresholds: packages/shared (positions, dto) + packages/permissions ≥ 80% lines/branches, other packages ≥ 60%.
  2. Playwright: tests/e2e/playwright.config.ts — chromium, testIdAttribute: "data-testid", baseURL from E2E_BASE_URL (default http://localhost:3000), 1 retry on CI, trace: "on-first-retry", screenshot: "only-on-failure", html + list reporters; globalSetup asserts all 4 health endpoints (TASK-0009) before any test; helpers tests/e2e/helpers/api.ts (typed fetch + token storage) and tests/e2e/helpers/db.ts (Prisma client for assertions, e.g. audit rows); smoke tests/e2e/smoke.spec.ts (api health 200 + web root renders data-testid="app-shell").
  3. Testcontainers: tests/integration/helpers/testcontainers.ts — startTestInfra() (postgres 16 + redis 7, shared per file, afterAll teardown), createTestApp() (Nest app from apps/api against container env, migrate deploy + seed once per container); smoke tests/integration/smoke.test.ts boots the app + calls its health endpoint.
  4. k6: tests/performance/k6/health-check.js (constant VU on all 4 apps' /api/v1/health + /health/ready; thresholds 5xx < 0.1%, p95 < 200 ms) + tests/performance/README.md (targets defined in Phase 15); pnpm test:perf.
  5. Root scripts test, test:integration, test:e2e, test:coverage, test:perf documented in docs/development/testing.md.

Acceptance Criteria

  1. pnpm test passes with ≥ 1 test per workspace; a deliberately failing test in packages/shared fails the root command (verified, reverted).
  2. pnpm test:integration boots Testcontainers + the api app, smoke passes, containers torn down (no orphans).
  3. pnpm test:e2e green with the dev stack up; with the stack down, globalSetup fails fast naming the unhealthy endpoint.
  4. pnpm test:perf completes in < 2 min locally.
  5. A package below its coverage threshold makes the command exit non-zero.

Backend Changes

Frontend Changes

Database Changes

None (harness applies the existing schema via migrate deploy).

API Changes

None (smoke consumes only TASK-0009 health endpoints).

Tests

Security

Documentation

Dependencies

Definition of Done

All four layers configured + smoke green; thresholds enforced; AGENTS.md updated; all root test commands pass.

TASK-0009

Title

Health endpoints for all 4 apps

Objective

Give every app liveness (/api/v1/health), readiness (/health/ready), and (realtime) /metrics, so compose, CI E2E and the runbook can verify a dependency-aware healthy stack.

Background

Compose healthchecks (TASK-0004) test containers; the apps must additionally expose their own dependency-aware health. api is the reference; worker/realtime/web follow the same contract.

Requirements

  1. Contract (JSON): GET /api/v1/health → 200 { status: "ok", app, version (package.json), uptimeSeconds, timestamp }; GET /health/ready → 200 { status: "ready", checks: {dep: "ok"} } or 503 { status: "not_ready", checks: {dep: "error"} } naming the failing dep.
  2. Checks: api → postgres (SELECT 1) + redis (PING); worker → redis + its BullMQ queue; realtime → redis + ws server bound; web → api liveness over HTTP; each check has a 1 s timeout (hung dep → 503 in < 2 s; liveness stays 200).
  3. api: apps/api/src/modules/health/{health.module.ts, health.controller.ts, dependency-check.service.ts} (checks = independent services so later deps — opensearch, minio — register cleanly); registered in app.module.ts.
  4. worker: minimal HTTP server (no NestJS) on 4003 (apps/worker/src/health/server.ts); realtime: both routes on 4001 + GET /metrics (Prometheus text: uptime_seconds, connected_clients, events_processed_total, ws_handshake_failures_total); web: apps/web/src/app/api/v1/health/route.ts + apps/web/src/app/health/ready/route.ts.
  5. Health routes are unauthenticated by design (documented exception to the Phase 1 global guard); they expose no data beyond app name/version.

Acceptance Criteria

  1. Full stack up: all 4 apps return 200 liveness + 200 readiness, all checks ok (recorded in the runbook, TASK-0012).
  2. docker compose stop postgres → api readiness 503 naming postgres within 3 s, liveness still 200; restore → 200.
  3. docker compose stop redis → worker + realtime readiness 503 naming redis.
  4. /metrics parses (prom-client parser test) and contains all 4 metric names.
  5. Readiness with a dead dependency answers < 2 s (measured by the runbook script).

Backend Changes

Frontend Changes

Database Changes

None

API Changes

Tests

Security

Documentation

Dependencies

Definition of Done

Endpoints live in all 4 apps; dependency-down 503 demonstrated for postgres + redis; valid Prometheus metrics; docs written.

Recorded notes (conflicts/adjustments, per AGENTS.md rule 29 — recorded at scaffold time, before Phase 0 execution):

  1. Realtime health port 4002, not 4001. Item 4 names "both routes on 4001"; the gateway binds WebSocket on 4001 and a dedicated health server on 4002 (HEALTH_PORT, default 4002 — see apps/realtime/src/config.ts). All three routes exist on 4002: /health, /health/ready, /metrics (all 4 required metric names). The 4001-vs-4002 split is pre-documented in the realtime README/Dockerfile/.env.example; compose exposes both ports.
  2. api readiness canonical path = GET /api/v1/health/ready. The implementation served readiness at /api/v1/health/deep only, which contradicted both the item-1 contract and the K8s probes in infrastructure/kubernetes/api.yaml (already targeting /api/v1/health/ready). health.controller.ts now serves ready as canonical and keeps deep as a deprecated alias.
  3. Worker health server implemented (was headless-only). The worker was scaffolded with a Redis heartbeat (worker:heartbeat:<WORKER_ID>) and no port; item 4 requires apps/worker/src/health/server.ts on 4003. Both now exist: heartbeat (deep liveness for the api) + HTTP health server on HEALTH_PORT (default 4003) serving /api/v1/health + /health/ready. Worker Dockerfile now EXPOSE 4003; compose publishes 4003:4003.
  4. Compose app profile renamed full → apps. The task contract (TASK-0003 requirement 5: pnpm docker:up:apps) and the dev guide name the application profile apps; the implementation had declared it full. Renamed everywhere (compose + infrastructure/docker/README.md + infrastructure/nginx/README.md) and added the missing root scripts docker:up:apps, docker:logs, lint:fix, test:perf, db:verify, check (TASK-0001 requirement 2). db:verify points at prisma/verify.ts, which TASK-0011 will create.
  5. scripts/verify-clean-clone.sh (TASK-0012) is not yet scaffolded — tracked as the remaining Phase 0 file. Status (final consistency pass): created. scripts/verify-clean-clone.sh now exists (preflight → install → infra → wait deps → migrate → seed → db:verify → apps → health polls → build gates → PASS/FAIL summary; --skip-build + --preflight flags; takes the clone dir as $1; never down -v; cleans up only the apps-profile containers it started). prisma/verify.ts (TASK-0011) + the contracted prisma/seed.ts fixture + .github/workflows/clean-clone.yml (the TASK-0012 clean-clone job: develop push + manual dispatch) are also now scaffolded.
  6. Wire-format enum casing conflict (recorded, NOT silently fixed) — the API is the outlier; @factory/shared is the authoritative wire format. docs/architecture/system-architecture.md designates @factory/shared as "the single source of truth for wire format, used by web, api, worker, realtime." Its DTO layer (packages/shared/src/dto/*.ts) — which exists and is complete — uses lowercase/snake_case for roles (owner/admin/member/guest), views (table/board/dashboard), blocks (paragraph), and properties (select/multi_select), matching the docs/api/* examples (snake_case blocks/properties/views). The web (apps/web/src/lib/types.ts + components/editor/*) is already aligned to this wire format (30 snake_case BLOCK_TYPES, 24 PROPERTY_TYPES, lowercase roles — done during the consistency pass). The API is the lone outlier: its own DTOs (apps/api/src/modules/*/dto.ts) validate inbound z.enum(BLOCK_TYPES) / z.enum(PROPERTY_TYPES) / z.enum(VIEW_TYPES) / z.enum(WORKSPACE_ROLES) using the UPPERCASE constants in apps/api/src/constants.ts, which mirror the Prisma storage enums — so the API both accepts and emits UPPERCASE, contradicting the designated wire format (and docs/api's role examples, which use OWNER/ADMIN/… — ~18 role literals). This is a storage-vs-wire representation gap, not a value-set gap (the 30/24/9/4/5 sets match; only casing differs). Decision (per rule 29, follow the architecture): the wire format is @factory/shared's lowercase/snake_case. Phase 0 must (a) add a central enum-casing codec in @factory/shared (snake_case wire ⇄ UPPERCASE Prisma storage), (b) route every API DTO through it (inbound parse + outbound serialize), and (c) normalize the docs/api role examples to lowercase. The web needs no change. Tracked as Phase 0 execution work — recorded here rather than half-implemented at scaffold time.

TASK-0010

Title

Observability baseline (pino, requestId middleware, OTEL stub off)

Objective

Structured JSON logging via a shared pino factory, request-id propagated through the api request lifecycle, and a disabled-by-default OTel span helper — so Phase 15 can turn observability on without touching call sites.

Background

AGENTS.md requires logging + observability in every DoD. Without a shared logger each app would invent a format. The baseline installs no OTel exporter: spans run through a stub tracer (OTEL_ENABLED default false) — zero runtime cost, wiring ready.

Requirements

  1. packages/shared/src/logger.ts: createLogger(name, options) → pino; JSON in test/production, pretty in dev; level from LOG_LEVEL; redact paths req.headers.authorization, *.password, *.passwordHash, *.token, *.tokenHash, *.refreshToken, *.secret; base fields service, env, version.
  2. packages/shared/src/context.ts: AsyncLocalStorage request context (requestId; userId arrives in Phase 1); getContext(); per-request pino child via logger.with({ requestId }).
  3. api: apps/api/src/common/middleware/request-id.middleware.ts — accepts incoming X-Request-Id matching ^[A-Za-z0-9._-]{8,64}$ else crypto.randomUUID(); echoes on response header; stores in async context; registered in main.ts. Plus apps/api/src/common/filters/http-exception.filter.ts: every error response uses envelope { code, message, requestId, details? }, logged at warn with status, url, durationMs.
  4. worker + realtime: loggers at boot; worker logs jobId + queue per job; realtime logs clientId + room fields (populated when rooms land, Phase 7); unhandledRejection/uncaughtException handlers in all 3 node mains: log at error with context, then process.exit(1).
  5. packages/shared/src/tracing.ts: traced(name, fn) — OTEL_ENABLED=false (default) = zero-overhead passthrough; true uses @opentelemetry/api (no exporter installed); api wraps service entry points with traced(); zero console.* in app source (TASK-0003 rule).

Acceptance Criteria

  1. Every api log line in a request contains service + requestId, parseable JSON; two concurrent requests get distinct ids (middleware unit test).
  2. Valid incoming X-Request-Id: abc-def_123 is echoed in response + all logs; an invalid one is replaced by a generated UUID.
  3. A logged payload with a password field never contains the password value (redaction unit test).
  4. OTEL_ENABLED=false boots cleanly; traced() passthrough verified (called exactly once, no wrapper overhead).
  5. Handled error (404) returns the envelope with requestId; uncaughtException logs and exits 1.
  6. grep -rn "console\." apps/*/src packages/*/src returns zero hits.

Backend Changes

Frontend Changes

Database Changes

None

API Changes

Tests

Security

Documentation

Dependencies

Definition of Done

Shared logger + context + OTEL stub shipped; middleware + exception filter live; crash handlers in all 3 node apps; zero console.*; all tests green; docs written.

TASK-0011

Title

Seed data verification

Objective

Turn the seed (TASK-0006) into a verified fixture: machine-checked invariants on the demo data that later integration/E2E tests rely on, plus a printed verification report.

Background

Demo credentials, slugs and structure become a contracted surface — E2E flows will hardcode demo@factory.local and the demo slug. This task makes any seed refactor that breaks the contract fail the pipeline instead of silently breaking Phase 1+ tests.

Requirements

  1. prisma/seed.ts ends with verifySeedData(prisma) (new prisma/verify.ts) asserting: both demo users VERIFIED/ACTIVE with non-null passwordHash; slug demo non-personal, owned by demo user; exactly 2 personal workspaces; every set ownerId has a WorkspaceMember row with role OWNER; exactly 2 teams in demo ws (unique slugs, valid fractional positions); exactly 6 pages in demo ws (every parentId same-workspace, positions unique per parent validated with the @factory/shared/positions comparator, "Getting started" has exactly 2 direct children); 1 database "Tasks" (exactly 5 properties: title, 2× select, date, people — order-insensitive; 3 records with non-empty titles) + 1 TABLE view; exactly 1 comment on "Getting started" by admin; demo user favorites "Getting started".
  2. Any failed check → table of expected vs actual → non-zero exit; non-production: seed prints the demo credentials block + personal-workspace slugs.
  3. Standalone pnpm db:verify runs the same assertions read-only against the current database (used by the runbook, TASK-0012); personal workspace slugs are personal-<4 random chars> and never hardcoded anywhere (E2E resolves them via API; only demo is fixed).

Acceptance Criteria

  1. Fresh db: pnpm db:seed passes, prints the full report (all checks ok) + credentials block (dev mode).
  2. Corrupting one invariant via psql (e.g. delete the "Tasks" database) makes pnpm db:verify exit non-zero, naming the check with expected vs actual.
  3. NODE_ENV=production seed still refuses (exit 65) — re-verified here.
  4. tests/integration/seed-verify.test.ts: seed → verify pass on Testcontainers, plus the position-uniqueness invariant independently re-checked with the shared comparator (the seed's own check is not trusted blindly).
  5. The report lists per-model counts (users, workspaces, teams, pages, databases, records, comments, favorites).

Backend Changes

Frontend Changes

None

Database Changes

None (read-only verification; no schema change).

API Changes

None

Tests

Security

Documentation

Dependencies

Definition of Done

Verify module + report shipped; all 5 criteria pass; pnpm db:verify standalone; docs updated; the fixture is a contracted surface.

TASK-0012

Title

Clean-clone verification runbook test

Objective

Prove the Phase 0 exit criterion end-to-end: a fresh clone on a clean machine runs install → docker up → migrate → seed → dev → health checks with zero manual fixes, and docs/development/development-guide.md documents exactly what the automated check runs.

Background

Everything Phase 0 built is only as good as its reproducibility. This task makes the developer experience an executable, CI-enforced runbook — the final gate before Phase 1.

Requirements

  1. Finalize docs/development/development-guide.md (consolidating the stubs from TASK-0001/0003/0004/0005/0009/0010/0011): prerequisites (Node 20, pnpm 9, Docker Engine + Compose v2, 4 GB RAM), the exact clean-clone step sequence, full port table (web 3000, api 4000, worker 4003, realtime 4001, postgres 5432, redis 6379, minio 9000/9001, opensearch 9200), demo credentials (TASK-0011), troubleshooting (port conflicts, volume state, image pulls, fail-fast env errors), and "What works in Phase 0" (health endpoints + dev stack only — no auth yet).
  2. scripts/verify-clean-clone.sh (set -euo pipefail, set -x): preflight (docker available, ports free) → pnpm install --frozen-lockfile → pnpm docker:up → wait for 4 dependency healthchecks (≤ 120 s) → pnpm db:migrate → pnpm db:seed → pnpm db:verify → pnpm docker:up:apps → poll all 4 apps' /api/v1/health + /health/ready (≤ 120 s; readiness 200 with all checks ok) → pnpm typecheck → pnpm test → pnpm lint → pnpm test:perf → PASS/FAIL summary; non-zero exit on any failure; --skip-build flag for CI speed.
  3. The script accepts the clone dir as $1 (default .) so CI can run it against a fresh git clone without touching the checkout.
  4. CI: clean-clone job (pushes to develop + manual dispatch) checks out to a scratch dir and runs the script; failure blocks Phase 0 sign-off (not the PR pipeline).
  5. The script never mutates git state, never runs down -v (re-runs safe against existing volumes), and cleans up the apps-profile containers it started.

Acceptance Criteria

  1. Clean machine + fresh git clone + bash scripts/verify-clean-clone.sh <dir> completes with the PASS summary in < 15 min; every summary step corresponds 1:1 to a numbered step in the development guide.
  2. Deliberately breaking one step (e.g. bad REDIS_URL in .env) stops the script at that step with the app's fail-fast error (not a generic crash), non-zero exit, and the failed runbook step printed.
  3. Running the script twice in a row passes (volume idempotency: second run reuses volumes, db:verify green).
  4. The clean-clone CI job passes on the Phase 0 branch (run URL recorded in commit).
  5. After the script finishes, no leftover apps-profile containers from its own run.

Backend Changes

Frontend Changes

None

Database Changes

None (the script runs existing migrate/seed/verify against the compose postgres).

API Changes

None (consumes only TASK-0009 endpoints).

Tests

Security

Documentation

Dependencies

Definition of Done

Guide finalized; script passes end-to-end on a clean machine twice; CI clean-clone job green; docs + README updated. Phase 0 exit criteria fully met — Phase 1 may start.