create-ailk 0.24.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -22
- package/component-catalog.json +3 -3
- package/component-catalog.md +3 -3
- package/dist/add-module.js +4 -2
- package/dist/add-route.d.ts +12 -1
- package/dist/add-route.js +31 -3
- package/dist/cli.js +12 -7
- package/dist/derive-architecture.d.ts +3 -4
- package/dist/derive-architecture.js +65 -29
- package/dist/lib/design-checks.d.ts +9 -4
- package/dist/lib/design-checks.js +13 -7
- package/dist/lib/extract-module-bundle.js +29 -2
- package/dist/lib/fetch-template-snapshot.d.ts +2 -1
- package/dist/lib/fetch-template-snapshot.js +8 -3
- package/dist/lib/import-graph.d.ts +1 -1
- package/dist/lib/import-graph.js +4 -4
- package/dist/lib/module-license-gate.d.ts +12 -1
- package/dist/lib/module-license-gate.js +36 -15
- package/dist/lib/module-tier.d.ts +2 -8
- package/dist/lib/module-tier.js +13 -12
- package/dist/module-architecture.d.ts +20 -3
- package/dist/module-architecture.js +129 -552
- package/dist/paid-sections.d.ts +25 -1
- package/dist/paid-sections.js +88 -3
- package/dist/starter-grid.d.ts +6 -6
- package/dist/starter-grid.js +12 -5
- package/dist/surfaces.js +39 -2
- package/dist/template-record.d.ts +21 -3
- package/dist/template-record.js +38 -7
- package/dist/topology.d.ts +16 -3
- package/dist/topology.js +54 -23
- package/dist/update.d.ts +10 -1
- package/dist/update.js +715 -21
- package/package.json +3 -3
- package/release-scope.json +2 -2
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +8 -2
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +2 -2
- package/site-templates/marketing-site/ailk-template.json +7 -1
- package/site-templates/marketing-site/provenance.json +7 -1
- package/site-templates/saas-product/ailk-template.json +2 -1
- package/site-templates/saas-product/provenance.json +1 -0
- package/templates/.claude/cloudparity-repo-hooks.json +5 -0
- package/templates/.claude/hooks/template-guard.sh +137 -0
- package/templates/.claude/rules/extending.md +106 -0
- package/templates/.claude/rules/loop-contract.md +2 -2
- package/templates/.claude/settings.json +11 -0
- package/templates/.env.example +20 -5
- package/templates/.github/workflows/ci.yml +7 -4
- package/templates/CLAUDE.md +11 -1
- package/templates/CONVENTIONS.md +8 -10
- package/templates/README.md +14 -13
- package/templates/apps/api/.env.example +23 -2
- package/templates/apps/api/CLAUDE.md +119 -83
- package/templates/apps/api/jest.config.cjs +15 -5
- package/templates/apps/api/package.json +16 -20
- package/templates/apps/api/src/__tests__/trusted-origins.server.test.ts +2 -2
- package/templates/apps/api/src/__tests__/vercel-handler.test.ts +4 -4
- package/templates/apps/api/src/index.ts +1 -1
- package/templates/apps/api/src/lib/__mocks__/prisma-client.js +16 -0
- package/templates/apps/api/src/lib/__mocks__/prisma.ts +3 -3
- package/templates/apps/api/src/modules/commerce.ts +10 -0
- package/templates/apps/api/src/modules/content-write.ts +10 -0
- package/templates/apps/api/src/modules/multi-tenant.ts +10 -0
- package/templates/apps/api/src/modules/scheduling.ts +10 -0
- package/templates/apps/api/src/modules/signal-collectors.ts +10 -0
- package/templates/apps/api/src/modules/workspace.ts +10 -0
- package/templates/apps/api/src/server.ts +117 -1882
- package/templates/apps/api/vercel.json +2 -2
- package/templates/apps/mcp/CLAUDE.md +90 -26
- package/templates/apps/mcp/__tests__/app-entry.test.ts +4 -254
- package/templates/apps/mcp/__tests__/boot-file.test.ts +92 -0
- package/templates/apps/mcp/jest.config.cjs +6 -1
- package/templates/apps/mcp/package.json +5 -13
- package/templates/apps/mcp/src/app.ts +8 -7
- package/templates/apps/mcp/src/index.ts +6 -34
- package/templates/apps/mcp/src/lib/paid-tools.generated.ts +10 -0
- package/templates/apps/mcp/src/lib/topology.generated.ts +2 -2
- package/templates/apps/mcp/src/site.ts +12 -0
- package/templates/apps/web/.env.example +1 -1
- package/templates/apps/web/CLAUDE.md +31 -3
- package/templates/apps/web/app/.well-known/mcp.json/route.ts +9 -3
- package/templates/apps/web/app/[locale]/(auth)/__tests__/auth-pages.test.tsx +43 -4
- package/templates/apps/web/app/[locale]/(auth)/legal-footnote.tsx +35 -0
- package/templates/apps/web/app/[locale]/(auth)/sign-in/__tests__/page.test.tsx +117 -8
- package/templates/apps/web/app/[locale]/(auth)/sign-in/page.tsx +14 -37
- package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-card.tsx +6 -6
- package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-text.ts +20 -35
- package/templates/apps/web/app/[locale]/(auth)/sign-up/__tests__/page.test.tsx +108 -0
- package/templates/apps/web/app/[locale]/(auth)/sign-up/__tests__/sign-up-card.test.tsx +111 -5
- package/templates/apps/web/app/[locale]/(auth)/sign-up/page.tsx +78 -16
- package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up-card.tsx +132 -12
- package/templates/apps/web/app/[locale]/(authed)/__tests__/gate.test.tsx +53 -1
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/billing.test.tsx +38 -0
- package/templates/apps/web/app/[locale]/(authed)/account/billing/page.tsx +4 -2
- package/templates/apps/web/app/[locale]/(authed)/sign-in-gate.tsx +47 -24
- package/templates/apps/web/app/[locale]/(authed)/signed-out-gate.generated.tsx +23 -4
- package/templates/apps/web/app/[locale]/contact/intake-analytics.ts +1 -1
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/magnet-page.test.tsx +22 -1
- package/templates/apps/web/app/[locale]/flows/[slug]/magnet-page.tsx +7 -3
- package/templates/apps/web/app/[locale]/layout.tsx +33 -13
- package/templates/apps/web/app/[locale]/meet/confirmed/BookingHandOff.tsx +128 -0
- package/templates/apps/web/app/[locale]/meet/confirmed/__tests__/BookingHandOff.test.tsx +126 -0
- package/templates/apps/web/app/[locale]/pricing/__tests__/unconnected.test.tsx +43 -0
- package/templates/apps/web/app/[locale]/pricing/page.tsx +7 -3
- package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/__tests__/route.test.ts +222 -0
- package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/route.ts +10 -3
- package/templates/apps/web/app/api/revalidate/route.ts +3 -3
- package/templates/apps/web/auth.ts +10 -6
- package/templates/apps/web/i18n/request.ts +49 -1
- package/templates/apps/web/jest.config.cjs +1 -0
- package/templates/apps/web/lib/__tests__/account-config.test.ts +7 -0
- package/templates/apps/web/lib/__tests__/auth-email.test.ts +276 -0
- package/templates/apps/web/lib/auth-email.ts +103 -21
- package/templates/apps/web/lib/hub-session/__tests__/sign-in-gate.test.tsx +72 -23
- package/templates/apps/web/lib/hub-session/sign-in-gate.tsx +94 -70
- package/templates/apps/web/lib/prisma-for-auth.ts +5 -2
- package/templates/apps/web/lib/relay.ts +2 -2
- package/templates/apps/web/lib/release-scope.ts +47 -0
- package/templates/apps/web/lib/server-api.ts +1 -1
- package/templates/apps/web/lib/sign-up-agreements.ts +291 -28
- package/templates/apps/web/lib/site-contributions.ts +18 -0
- package/templates/apps/web/messages/en.json +186 -20
- package/templates/apps/web/messages/site/en.json +1 -0
- package/templates/apps/web/src/lib/commerce-claim.ts +1 -1
- package/templates/customizations.yaml +37 -0
- package/templates/database/prisma.config.ts +10 -14
- package/templates/database/seed-test.ts +2 -2
- package/templates/database/seed.ts +5 -5
- package/templates/package.json +12 -6
- package/templates/pnpm-workspace.yaml +0 -1
- package/templates/project.yaml +16 -8
- package/templates/tools/jest/reporters.cjs +65 -0
- package/templates/tools/lint-architecture.ts +553 -7
- package/templates/tsconfig.json +1 -2
- package/versions.json +49 -36
- package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +0 -409
- package/templates/apps/api/src/__tests__/factories/agent-caller.ts +0 -102
- package/templates/apps/api/src/__tests__/factories/content-fixture.ts +0 -138
- package/templates/apps/api/src/__tests__/factories/in-memory-prisma.ts +0 -441
- package/templates/apps/api/src/__tests__/factories/index.ts +0 -70
- package/templates/apps/api/src/__tests__/factories/lead-fixture.ts +0 -82
- package/templates/apps/api/src/__tests__/leads-forwarded-rate-limit.test.ts +0 -135
- package/templates/apps/api/src/__tests__/services/enrichment-shim.test.ts +0 -126
- package/templates/apps/api/src/__tests__/stripe-boot.test.ts +0 -132
- package/templates/apps/api/src/__tests__/support/hub-sign-in-fake-db.ts +0 -362
- package/templates/apps/api/src/bin/__tests__/rate-limit-probe.test.ts +0 -184
- package/templates/apps/api/src/bin/abandon-sweep.ts +0 -42
- package/templates/apps/api/src/bin/rate-limit-probe.ts +0 -53
- package/templates/apps/api/src/bin/spokes.ts +0 -198
- package/templates/apps/api/src/bin/stripe-connections-rekey.ts +0 -45
- package/templates/apps/api/src/config/__tests__/hub-require-spoke-key.test.ts +0 -196
- package/templates/apps/api/src/config/__tests__/index.test.ts +0 -233
- package/templates/apps/api/src/config/__tests__/modules.test.ts +0 -76
- package/templates/apps/api/src/config/__tests__/stripe-connection-key.test.ts +0 -185
- package/templates/apps/api/src/config/__tests__/trusted-origins.test.ts +0 -238
- package/templates/apps/api/src/config/index.ts +0 -596
- package/templates/apps/api/src/config/modules.ts +0 -83
- package/templates/apps/api/src/lib/__tests__/agent-store.test.ts +0 -581
- package/templates/apps/api/src/lib/__tests__/auth-email-budget.test.ts +0 -143
- package/templates/apps/api/src/lib/__tests__/consent-ledger-double.ts +0 -237
- package/templates/apps/api/src/lib/__tests__/consent-store.test.ts +0 -353
- package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +0 -201
- package/templates/apps/api/src/lib/__tests__/deliverable-asset-store.test.ts +0 -224
- package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +0 -120
- package/templates/apps/api/src/lib/__tests__/errors.test.ts +0 -94
- package/templates/apps/api/src/lib/__tests__/file-fallback.test.ts +0 -144
- package/templates/apps/api/src/lib/__tests__/fixtures/HomePage/home.mdx +0 -8
- package/templates/apps/api/src/lib/__tests__/flow-completion-store.test.ts +0 -149
- package/templates/apps/api/src/lib/__tests__/flow-rename-race.db.test.ts +0 -116
- package/templates/apps/api/src/lib/__tests__/hub-sign-in-store.test.ts +0 -209
- package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +0 -257
- package/templates/apps/api/src/lib/__tests__/lead-delivery.test.ts +0 -96
- package/templates/apps/api/src/lib/__tests__/outbound-http.test.ts +0 -125
- package/templates/apps/api/src/lib/__tests__/prisma.test.ts +0 -165
- package/templates/apps/api/src/lib/__tests__/require-commerce-claim.test.ts +0 -317
- package/templates/apps/api/src/lib/__tests__/require-paid-tier.test.ts +0 -129
- package/templates/apps/api/src/lib/__tests__/site.test.ts +0 -308
- package/templates/apps/api/src/lib/__tests__/slice-load.test.ts +0 -89
- package/templates/apps/api/src/lib/__tests__/spoke-store.test.ts +0 -202
- package/templates/apps/api/src/lib/__tests__/stripe-admission.test.ts +0 -217
- package/templates/apps/api/src/lib/__tests__/stripe.test.ts +0 -82
- package/templates/apps/api/src/lib/agent-store.ts +0 -613
- package/templates/apps/api/src/lib/auth-email-budget.ts +0 -161
- package/templates/apps/api/src/lib/consent-store.ts +0 -363
- package/templates/apps/api/src/lib/content-adapter.ts +0 -112
- package/templates/apps/api/src/lib/deliverable-asset-store.ts +0 -96
- package/templates/apps/api/src/lib/error-serializer.ts +0 -164
- package/templates/apps/api/src/lib/errors.ts +0 -95
- package/templates/apps/api/src/lib/file-fallback.ts +0 -87
- package/templates/apps/api/src/lib/flow-completion-store.ts +0 -136
- package/templates/apps/api/src/lib/hub-sign-in-store.ts +0 -455
- package/templates/apps/api/src/lib/lead-capture-store.ts +0 -122
- package/templates/apps/api/src/lib/lead-delivery.ts +0 -52
- package/templates/apps/api/src/lib/license-key-store.ts +0 -45
- package/templates/apps/api/src/lib/locales.ts +0 -201
- package/templates/apps/api/src/lib/outbound-http.ts +0 -127
- package/templates/apps/api/src/lib/prisma.ts +0 -21
- package/templates/apps/api/src/lib/proposal-paid-store.ts +0 -66
- package/templates/apps/api/src/lib/rate-limit-probe.ts +0 -165
- package/templates/apps/api/src/lib/rate-limit-store.ts +0 -142
- package/templates/apps/api/src/lib/require-commerce-claim.ts +0 -250
- package/templates/apps/api/src/lib/require-paid-tier.ts +0 -53
- package/templates/apps/api/src/lib/site.ts +0 -257
- package/templates/apps/api/src/lib/slice-load.ts +0 -90
- package/templates/apps/api/src/lib/spoke-store.ts +0 -180
- package/templates/apps/api/src/lib/stripe.ts +0 -321
- package/templates/apps/api/src/lib/webhook-idempotency.ts +0 -156
- package/templates/apps/api/src/middleware/__tests__/adversarial/bearer-token-format.test.ts +0 -111
- package/templates/apps/api/src/middleware/__tests__/adversarial/cookie-or-bearer-precedence.test.ts +0 -172
- package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-bearer-skip.test.ts +0 -119
- package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-cookie-path.test.ts +0 -138
- package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-trusted-origins.test.ts +0 -142
- package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +0 -155
- package/templates/apps/api/src/middleware/__tests__/adversarial/session-timeout.test.ts +0 -139
- package/templates/apps/api/src/middleware/__tests__/auth.bearer-path.test.ts +0 -562
- package/templates/apps/api/src/middleware/__tests__/auth.both-present-precedence.test.ts +0 -76
- package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +0 -220
- package/templates/apps/api/src/middleware/__tests__/auth.database-not-configured.test.ts +0 -97
- package/templates/apps/api/src/middleware/__tests__/auth.hub-session-path.test.ts +0 -557
- package/templates/apps/api/src/middleware/__tests__/auth.neither-present.test.ts +0 -72
- package/templates/apps/api/src/middleware/__tests__/auth.optional-cookie.test.ts +0 -140
- package/templates/apps/api/src/middleware/__tests__/default-tenant.test.ts +0 -721
- package/templates/apps/api/src/middleware/__tests__/rate-limit-cross-isolate.db.test.ts +0 -220
- package/templates/apps/api/src/middleware/__tests__/rate-limit-store.test.ts +0 -430
- package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +0 -1409
- package/templates/apps/api/src/middleware/__tests__/write-budget.test.ts +0 -174
- package/templates/apps/api/src/middleware/auth.ts +0 -864
- package/templates/apps/api/src/middleware/default-tenant.ts +0 -166
- package/templates/apps/api/src/middleware/rate-limit.ts +0 -983
- package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +0 -391
- package/templates/apps/api/src/openapi/__tests__/spec-identity.test.ts +0 -182
- package/templates/apps/api/src/openapi/index.ts +0 -18
- package/templates/apps/api/src/openapi/spec.ts +0 -2148
- package/templates/apps/api/src/openapi/surface-drift.ts +0 -195
- package/templates/apps/api/src/routes/aeo/__tests__/index.test.ts +0 -175
- package/templates/apps/api/src/routes/aeo/index.ts +0 -107
- package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +0 -196
- package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +0 -249
- package/templates/apps/api/src/routes/auth/__tests__/hub-sign-in.test.ts +0 -532
- package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +0 -313
- package/templates/apps/api/src/routes/auth/__tests__/transactional-email.test.ts +0 -413
- package/templates/apps/api/src/routes/auth/__tests__/user.test.ts +0 -609
- package/templates/apps/api/src/routes/auth/hub-sign-in.ts +0 -242
- package/templates/apps/api/src/routes/auth/tokens.ts +0 -211
- package/templates/apps/api/src/routes/auth/transactional-email.ts +0 -301
- package/templates/apps/api/src/routes/auth/user.ts +0 -305
- package/templates/apps/api/src/routes/billing/plan-checkout.ts +0 -332
- package/templates/apps/api/src/routes/checkout/__tests__/live-key.test.ts +0 -178
- package/templates/apps/api/src/routes/checkout/__tests__/offerings-authorization.test.ts +0 -1426
- package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +0 -448
- package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +0 -1742
- package/templates/apps/api/src/routes/checkout/index.ts +0 -34
- package/templates/apps/api/src/routes/checkout/session.ts +0 -171
- package/templates/apps/api/src/routes/checkout/sessions.ts +0 -540
- package/templates/apps/api/src/routes/consent/__tests__/account.test.ts +0 -386
- package/templates/apps/api/src/routes/consent/__tests__/sign-up-rate-limit.test.ts +0 -160
- package/templates/apps/api/src/routes/consent/account.ts +0 -268
- package/templates/apps/api/src/routes/consent/cookie.ts +0 -90
- package/templates/apps/api/src/routes/consent/index.ts +0 -26
- package/templates/apps/api/src/routes/consent/unsubscribe.ts +0 -127
- package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +0 -853
- package/templates/apps/api/src/routes/content/__tests__/list-pages.test.ts +0 -230
- package/templates/apps/api/src/routes/content/__tests__/list-types.test.ts +0 -44
- package/templates/apps/api/src/routes/content/__tests__/locale.test.ts +0 -118
- package/templates/apps/api/src/routes/content/__tests__/offerings.test.ts +0 -731
- package/templates/apps/api/src/routes/content/__tests__/pricing.test.ts +0 -753
- package/templates/apps/api/src/routes/content/__tests__/rate-limit.test.ts +0 -51
- package/templates/apps/api/src/routes/content/__tests__/search.test.ts +0 -450
- package/templates/apps/api/src/routes/content/__tests__/shown-offerings.test.ts +0 -762
- package/templates/apps/api/src/routes/content/get-page.ts +0 -183
- package/templates/apps/api/src/routes/content/index.ts +0 -49
- package/templates/apps/api/src/routes/content/list-pages.ts +0 -74
- package/templates/apps/api/src/routes/content/list-types.ts +0 -19
- package/templates/apps/api/src/routes/content/offerings.ts +0 -184
- package/templates/apps/api/src/routes/content/pricing.ts +0 -176
- package/templates/apps/api/src/routes/content/rate-limit.ts +0 -22
- package/templates/apps/api/src/routes/content/search.ts +0 -100
- package/templates/apps/api/src/routes/content/shown-offerings.ts +0 -229
- package/templates/apps/api/src/routes/leads/__tests__/capture.test.ts +0 -88
- package/templates/apps/api/src/routes/leads/__tests__/list.test.ts +0 -171
- package/templates/apps/api/src/routes/leads/__tests__/magnet-completion.test.ts +0 -515
- package/templates/apps/api/src/routes/leads/__tests__/spoke.test.ts +0 -392
- package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +0 -165
- package/templates/apps/api/src/routes/leads/index.ts +0 -639
- package/templates/apps/api/src/routes/leads/list.ts +0 -104
- package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +0 -626
- package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +0 -1268
- package/templates/apps/api/src/routes/project-listings/__tests__/founder-identity.test.ts +0 -847
- package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +0 -491
- package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +0 -476
- package/templates/apps/api/src/routes/project-listings/__tests__/resume-email.test.ts +0 -872
- package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +0 -1022
- package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +0 -484
- package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +0 -535
- package/templates/apps/api/src/routes/project-listings/index.ts +0 -164
- package/templates/apps/api/src/routes/project-listings/me.ts +0 -87
- package/templates/apps/api/src/routes/project-listings/patch-copy.ts +0 -224
- package/templates/apps/api/src/routes/project-listings/patch-draft.ts +0 -102
- package/templates/apps/api/src/routes/project-listings/public.ts +0 -98
- package/templates/apps/api/src/routes/project-listings/respond.ts +0 -48
- package/templates/apps/api/src/routes/project-listings/resume-token.ts +0 -27
- package/templates/apps/api/src/routes/project-listings/start.ts +0 -140
- package/templates/apps/api/src/routes/project-listings/submit.ts +0 -130
- package/templates/apps/api/src/routes/project-listings/verify-email.ts +0 -150
- package/templates/apps/api/src/routes/requests/__tests__/confirm.test.ts +0 -686
- package/templates/apps/api/src/routes/requests/confirm.ts +0 -601
- package/templates/apps/api/src/routes/requests/index.ts +0 -54
- package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +0 -306
- package/templates/apps/api/src/routes/test/auth/session.ts +0 -143
- package/templates/apps/api/src/routes/webhooks/README.md +0 -398
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-checkout-consent.test.ts +0 -649
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-dunning.test.ts +0 -749
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +0 -449
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +0 -264
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-livemode-live.test.ts +0 -159
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-livemode.test.ts +0 -158
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-offerings.test.ts +0 -814
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +0 -301
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-proposal-paid.test.ts +0 -369
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +0 -215
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-request-paid.test.ts +0 -301
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-site-filter.test.ts +0 -809
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +0 -1155
- package/templates/apps/api/src/routes/webhooks/index.ts +0 -141
- package/templates/apps/api/src/routes/webhooks/stripe-offerings.ts +0 -384
- package/templates/apps/api/src/routes/webhooks/stripe.ts +0 -2028
- package/templates/apps/api/src/services/__tests__/abandon-email.test.ts +0 -645
- package/templates/apps/api/src/services/__tests__/answer-distributions.test.ts +0 -132
- package/templates/apps/api/src/services/__tests__/audit-log.test.ts +0 -1028
- package/templates/apps/api/src/services/__tests__/checkout-plan.test.ts +0 -313
- package/templates/apps/api/src/services/__tests__/consent-ledger.test.ts +0 -503
- package/templates/apps/api/src/services/__tests__/consent-migration.test.ts +0 -65
- package/templates/apps/api/src/services/__tests__/consent.test.ts +0 -299
- package/templates/apps/api/src/services/__tests__/default-tenant.test.ts +0 -147
- package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +0 -877
- package/templates/apps/api/src/services/__tests__/deliverable-resend.test.ts +0 -379
- package/templates/apps/api/src/services/__tests__/dunning-policy.test.ts +0 -368
- package/templates/apps/api/src/services/__tests__/entitlements.test.ts +0 -142
- package/templates/apps/api/src/services/__tests__/hub-sign-in.test.ts +0 -854
- package/templates/apps/api/src/services/__tests__/keyless-workspace-predicate.test.ts +0 -234
- package/templates/apps/api/src/services/__tests__/lead-accept-user.test.ts +0 -251
- package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +0 -2660
- package/templates/apps/api/src/services/__tests__/listing-config.test.ts +0 -166
- package/templates/apps/api/src/services/__tests__/magnet-completion.test.ts +0 -389
- package/templates/apps/api/src/services/__tests__/person.test.ts +0 -1204
- package/templates/apps/api/src/services/__tests__/plan-offerings.test.ts +0 -450
- package/templates/apps/api/src/services/__tests__/project-listings.counts.test.ts +0 -202
- package/templates/apps/api/src/services/__tests__/project-listings.fence.test.ts +0 -151
- package/templates/apps/api/src/services/__tests__/public-site-resolver.test.ts +0 -137
- package/templates/apps/api/src/services/__tests__/request-confirm.test.ts +0 -531
- package/templates/apps/api/src/services/__tests__/revalidation.test.ts +0 -372
- package/templates/apps/api/src/services/__tests__/slack-notify.test.ts +0 -348
- package/templates/apps/api/src/services/__tests__/spoke-resolution.test.ts +0 -660
- package/templates/apps/api/src/services/__tests__/usage-aggregation.test.ts +0 -941
- package/templates/apps/api/src/services/__tests__/usage-credits.test.ts +0 -588
- package/templates/apps/api/src/services/__tests__/verified-email.test.ts +0 -78
- package/templates/apps/api/src/services/abandon-email.ts +0 -336
- package/templates/apps/api/src/services/aeo-score.ts +0 -325
- package/templates/apps/api/src/services/answer-distributions.ts +0 -138
- package/templates/apps/api/src/services/audit-log.ts +0 -961
- package/templates/apps/api/src/services/checkout-buyer.ts +0 -168
- package/templates/apps/api/src/services/consent.ts +0 -834
- package/templates/apps/api/src/services/default-tenant.ts +0 -416
- package/templates/apps/api/src/services/deliverable-fulfillment.ts +0 -750
- package/templates/apps/api/src/services/dunning-policy.ts +0 -294
- package/templates/apps/api/src/services/enrichment-shim.ts +0 -53
- package/templates/apps/api/src/services/entitlements.ts +0 -338
- package/templates/apps/api/src/services/hub-sign-in.ts +0 -472
- package/templates/apps/api/src/services/lead-accept-user.ts +0 -126
- package/templates/apps/api/src/services/lead-promotion.ts +0 -160
- package/templates/apps/api/src/services/lead-routing.ts +0 -1372
- package/templates/apps/api/src/services/leads-inbox.ts +0 -312
- package/templates/apps/api/src/services/listing-config.ts +0 -178
- package/templates/apps/api/src/services/magnet-completion.ts +0 -242
- package/templates/apps/api/src/services/offerings/__tests__/catalog.test.ts +0 -348
- package/templates/apps/api/src/services/offerings/__tests__/checkout-session-record.test.ts +0 -268
- package/templates/apps/api/src/services/offerings/__tests__/connection.test.ts +0 -975
- package/templates/apps/api/src/services/offerings/__tests__/fixtures.ts +0 -416
- package/templates/apps/api/src/services/offerings/__tests__/org-products.test.ts +0 -400
- package/templates/apps/api/src/services/offerings/__tests__/readers.test.ts +0 -685
- package/templates/apps/api/src/services/offerings/__tests__/source.test.ts +0 -231
- package/templates/apps/api/src/services/offerings/catalog.ts +0 -318
- package/templates/apps/api/src/services/offerings/checkout-authorization.ts +0 -403
- package/templates/apps/api/src/services/offerings/checkout-session-record.ts +0 -192
- package/templates/apps/api/src/services/offerings/connection.ts +0 -1083
- package/templates/apps/api/src/services/offerings/index.ts +0 -614
- package/templates/apps/api/src/services/offerings/source.ts +0 -140
- package/templates/apps/api/src/services/offerings/store.ts +0 -150
- package/templates/apps/api/src/services/owner-workspaces.ts +0 -132
- package/templates/apps/api/src/services/person.ts +0 -1211
- package/templates/apps/api/src/services/plan-offerings.ts +0 -125
- package/templates/apps/api/src/services/project-listing-resume-email.ts +0 -326
- package/templates/apps/api/src/services/project-listings.ts +0 -2085
- package/templates/apps/api/src/services/public-site-resolver.ts +0 -396
- package/templates/apps/api/src/services/request-confirm.ts +0 -698
- package/templates/apps/api/src/services/revalidation.ts +0 -235
- package/templates/apps/api/src/services/slack-notify.ts +0 -291
- package/templates/apps/api/src/services/usage-aggregation.ts +0 -516
- package/templates/apps/api/src/services/usage-credits.ts +0 -340
- package/templates/apps/api/src/services/verified-email.ts +0 -71
- package/templates/apps/mcp/__tests__/abuse/daily-cap.test.ts +0 -52
- package/templates/apps/mcp/__tests__/abuse/email-validator.test.ts +0 -46
- package/templates/apps/mcp/__tests__/abuse/guard.test.ts +0 -198
- package/templates/apps/mcp/__tests__/abuse/honeypot.test.ts +0 -36
- package/templates/apps/mcp/__tests__/abuse/user-agent-deny.test.ts +0 -54
- package/templates/apps/mcp/__tests__/aeo-cli-parity.test.ts +0 -116
- package/templates/apps/mcp/__tests__/audit-single-page.test.ts +0 -299
- package/templates/apps/mcp/__tests__/boot.test.ts +0 -280
- package/templates/apps/mcp/__tests__/catalog-drift.test.ts +0 -359
- package/templates/apps/mcp/__tests__/config/modules.test.ts +0 -78
- package/templates/apps/mcp/__tests__/get_business_hours.test.ts +0 -82
- package/templates/apps/mcp/__tests__/get_faq.test.ts +0 -80
- package/templates/apps/mcp/__tests__/get_locations.test.ts +0 -65
- package/templates/apps/mcp/__tests__/get_offerings.test.ts +0 -557
- package/templates/apps/mcp/__tests__/get_pricing.test.ts +0 -524
- package/templates/apps/mcp/__tests__/get_site_info.test.ts +0 -81
- package/templates/apps/mcp/__tests__/http-transport.test.ts +0 -1232
- package/templates/apps/mcp/__tests__/index.test.ts +0 -195
- package/templates/apps/mcp/__tests__/lib/audit-single-page-readiness-scan.test.ts +0 -191
- package/templates/apps/mcp/__tests__/lib/commerce-claim.test.ts +0 -531
- package/templates/apps/mcp/__tests__/lib/content-adapter-parity.test.ts +0 -70
- package/templates/apps/mcp/__tests__/lib/content-adapter.test.ts +0 -162
- package/templates/apps/mcp/__tests__/lib/content-root.test.ts +0 -93
- package/templates/apps/mcp/__tests__/lib/errors.test.ts +0 -75
- package/templates/apps/mcp/__tests__/lib/fail-closed-tools.test.ts +0 -180
- package/templates/apps/mcp/__tests__/lib/public-workspace.test.ts +0 -124
- package/templates/apps/mcp/__tests__/list_pages.test.ts +0 -268
- package/templates/apps/mcp/__tests__/locale.test.ts +0 -120
- package/templates/apps/mcp/__tests__/module-exclusion.test.ts +0 -175
- package/templates/apps/mcp/__tests__/purchase-disabled.test.ts +0 -101
- package/templates/apps/mcp/__tests__/rate-limit-write.test.ts +0 -189
- package/templates/apps/mcp/__tests__/read_content.test.ts +0 -511
- package/templates/apps/mcp/__tests__/request_callback.test.ts +0 -160
- package/templates/apps/mcp/__tests__/search_content.test.ts +0 -271
- package/templates/apps/mcp/__tests__/server.test.ts +0 -388
- package/templates/apps/mcp/__tests__/start_purchase.test.ts +0 -448
- package/templates/apps/mcp/__tests__/submit_lead.test.ts +0 -222
- package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +0 -152
- package/templates/apps/mcp/__tests__/tools/create_project.test.ts +0 -243
- package/templates/apps/mcp/__tests__/tools/purchase.test.ts +0 -451
- package/templates/apps/mcp/src/abuse/daily-cap.ts +0 -47
- package/templates/apps/mcp/src/abuse/email-validator.ts +0 -25
- package/templates/apps/mcp/src/abuse/honeypot.ts +0 -21
- package/templates/apps/mcp/src/abuse/index.ts +0 -349
- package/templates/apps/mcp/src/abuse/user-agent-deny.ts +0 -58
- package/templates/apps/mcp/src/boot.ts +0 -167
- package/templates/apps/mcp/src/config/modules.ts +0 -43
- package/templates/apps/mcp/src/http-transport.ts +0 -564
- package/templates/apps/mcp/src/lib/audit-single-page.ts +0 -308
- package/templates/apps/mcp/src/lib/commerce-claim.ts +0 -263
- package/templates/apps/mcp/src/lib/content-adapter.ts +0 -116
- package/templates/apps/mcp/src/lib/empty-content-adapter.ts +0 -140
- package/templates/apps/mcp/src/lib/errors.ts +0 -61
- package/templates/apps/mcp/src/lib/license-key-store.ts +0 -45
- package/templates/apps/mcp/src/lib/locales.ts +0 -171
- package/templates/apps/mcp/src/lib/prisma.ts +0 -39
- package/templates/apps/mcp/src/lib/public-workspace.ts +0 -133
- package/templates/apps/mcp/src/lib/resolve-locale.ts +0 -30
- package/templates/apps/mcp/src/lib/shown-offerings.ts +0 -105
- package/templates/apps/mcp/src/lib/site-config.ts +0 -53
- package/templates/apps/mcp/src/lib/stripe-tax-signal.ts +0 -59
- package/templates/apps/mcp/src/request-context.ts +0 -52
- package/templates/apps/mcp/src/server.ts +0 -343
- package/templates/apps/mcp/src/serverless-app.ts +0 -88
- package/templates/apps/mcp/src/tools/audit.ts +0 -127
- package/templates/apps/mcp/src/tools/capture_lead.ts +0 -66
- package/templates/apps/mcp/src/tools/create_project.ts +0 -134
- package/templates/apps/mcp/src/tools/get_business_hours.ts +0 -68
- package/templates/apps/mcp/src/tools/get_faq.ts +0 -71
- package/templates/apps/mcp/src/tools/get_locations.ts +0 -88
- package/templates/apps/mcp/src/tools/get_offerings.ts +0 -96
- package/templates/apps/mcp/src/tools/get_pricing.ts +0 -94
- package/templates/apps/mcp/src/tools/get_site_info.ts +0 -86
- package/templates/apps/mcp/src/tools/index.ts +0 -138
- package/templates/apps/mcp/src/tools/list_pages.ts +0 -68
- package/templates/apps/mcp/src/tools/person_notes.ts +0 -25
- package/templates/apps/mcp/src/tools/proposals.ts +0 -27
- package/templates/apps/mcp/src/tools/purchase.ts +0 -205
- package/templates/apps/mcp/src/tools/read_content.ts +0 -81
- package/templates/apps/mcp/src/tools/request_callback.ts +0 -52
- package/templates/apps/mcp/src/tools/search_content.ts +0 -63
- package/templates/apps/mcp/src/tools/subscribe_newsletter.ts +0 -54
- package/templates/apps/mcp/src/workspace-server.ts +0 -224
- package/templates/database/CHANGELOG.md +0 -981
- package/templates/database/LICENSE +0 -202
- package/templates/database/NOTICE +0 -2
- package/templates/database/README.md +0 -243
- package/templates/database/__tests__/agents.db.test.ts +0 -320
- package/templates/database/__tests__/appointment.db.test.ts +0 -106
- package/templates/database/__tests__/artifact-content-store.db.test.ts +0 -316
- package/templates/database/__tests__/composite-fence.db.test.ts +0 -206
- package/templates/database/__tests__/consent-ledger.db.test.ts +0 -345
- package/templates/database/__tests__/consent-source-checkout-migration.test.ts +0 -79
- package/templates/database/__tests__/fence-fan-out.db.test.ts +0 -715
- package/templates/database/__tests__/fixtures/appointment-create-probe.ts +0 -79
- package/templates/database/__tests__/fixtures/person-backfill.json +0 -264
- package/templates/database/__tests__/fixtures/person-contact-backfill.json +0 -182
- package/templates/database/__tests__/fixtures/project-listing-consent-probe.ts +0 -100
- package/templates/database/__tests__/flow-completion-migration.test.ts +0 -115
- package/templates/database/__tests__/flow-completion.db.test.ts +0 -136
- package/templates/database/__tests__/flow-workspace-key.db.test.ts +0 -263
- package/templates/database/__tests__/flows-listing-diagnostic.test.ts +0 -392
- package/templates/database/__tests__/flows-presets.test.ts +0 -173
- package/templates/database/__tests__/in-page-magnets-migration.test.ts +0 -161
- package/templates/database/__tests__/lead-idempotency-key.db.test.ts +0 -92
- package/templates/database/__tests__/member-area.db.test.ts +0 -257
- package/templates/database/__tests__/member-contract-migration.test.ts +0 -85
- package/templates/database/__tests__/member-contract.db.test.ts +0 -413
- package/templates/database/__tests__/offerings-checkout-session.db.test.ts +0 -270
- package/templates/database/__tests__/offerings-migration.test.ts +0 -197
- package/templates/database/__tests__/offerings-shown-price-ids-migration.test.ts +0 -86
- package/templates/database/__tests__/offerings.db.test.ts +0 -303
- package/templates/database/__tests__/outbound-message-action.db.test.ts +0 -80
- package/templates/database/__tests__/person-contact.db.test.ts +0 -563
- package/templates/database/__tests__/person-notes.db.test.ts +0 -249
- package/templates/database/__tests__/person.db.test.ts +0 -586
- package/templates/database/__tests__/piece-kind-migration.test.ts +0 -67
- package/templates/database/__tests__/piece-kind.db.test.ts +0 -208
- package/templates/database/__tests__/prefixed-ids.db.test.ts +0 -222
- package/templates/database/__tests__/project-listing-consent-at.db.test.ts +0 -111
- package/templates/database/__tests__/seed.test.ts +0 -272
- package/templates/database/__tests__/spoke-registry.db.test.ts +0 -191
- package/templates/database/__tests__/tenancy.test.ts +0 -141
- package/templates/database/__tests__/trial-magnet-migration.test.ts +0 -186
- package/templates/database/__tests__/user-cascade.test.ts +0 -140
- package/templates/database/_gitignore +0 -8
- package/templates/database/auth/.gitkeep +0 -0
- package/templates/database/auth/schema.prisma +0 -641
- package/templates/database/config/.gitkeep +0 -0
- package/templates/database/config/schema.prisma +0 -441
- package/templates/database/content/.gitkeep +0 -0
- package/templates/database/content/schema.prisma +0 -339
- package/templates/database/eslint.config.mjs +0 -69
- package/templates/database/flows/listing-diagnostic.ts +0 -182
- package/templates/database/flows/presets.ts +0 -315
- package/templates/database/inbox/.gitkeep +0 -0
- package/templates/database/inbox/README.md +0 -3
- package/templates/database/inbox/__tests__/schema.test.ts +0 -44
- package/templates/database/inbox/schema.prisma +0 -1447
- package/templates/database/jest.config.cjs +0 -36
- package/templates/database/migrations/20260508000000_add_inbox_namespace/migration.sql +0 -328
- package/templates/database/migrations/20260513000000_better_auth_migration/migration.sql +0 -100
- package/templates/database/migrations/20260515000000_add_user_billing_fields/migration.sql +0 -28
- package/templates/database/migrations/20260516000000_add_user_tier_care_plan_seat/migration.sql +0 -25
- package/templates/database/migrations/20260518000000_add_telemetry_records/migration.sql +0 -42
- package/templates/database/migrations/20260525000000_theme_wiring/migration.sql +0 -67
- package/templates/database/migrations/20260710000000_retire_commercial_tier/migration.sql +0 -21
- package/templates/database/migrations/20260712215647_add_multi_tenant_tenancy/migration.sql +0 -201
- package/templates/database/migrations/20260713143320_reanchor_site_config_to_workspace/migration.sql +0 -67
- package/templates/database/migrations/20260713174000_add_audit_logs/migration.sql +0 -46
- package/templates/database/migrations/20260713190000_drop_telemetry_records/migration.sql +0 -25
- package/templates/database/migrations/20260713192000_add_uuidv7_function/migration.sql +0 -49
- package/templates/database/migrations/20260713192429_prefixed_uuid_entity_ids/migration.sql +0 -197
- package/templates/database/migrations/20260713200000_add_org_billing/migration.sql +0 -32
- package/templates/database/migrations/20260714000000_add_lead_promotion_fields/migration.sql +0 -22
- package/templates/database/migrations/20260714010000_add_usage_billing_content_models/migration.sql +0 -151
- package/templates/database/migrations/20260714020000_add_usage_billing_auth_config_models/migration.sql +0 -223
- package/templates/database/migrations/20260714030000_credit_balance_non_negative/migration.sql +0 -22
- package/templates/database/migrations/20260714030000_widen_usage_billing_report_aggregates/migration.sql +0 -32
- package/templates/database/migrations/20260810233516_add_flow_engine_models/migration.sql +0 -40
- package/templates/database/migrations/20260811020000_add_flow_session_abandon_email_columns/migration.sql +0 -4
- package/templates/database/migrations/20260811030000_add_flow_session_abandon_email_index/migration.sql +0 -2
- package/templates/database/migrations/20260811040000_add_flow_session_segment/migration.sql +0 -2
- package/templates/database/migrations/20260811050000_add_deliverable_models/migration.sql +0 -29
- package/templates/database/migrations/20260812000000_add_deliverable_grant_send_columns/migration.sql +0 -6
- package/templates/database/migrations/20260902222948_add_waitlist_experiment_models/migration.sql +0 -39
- package/templates/database/migrations/20260902224500_add_waitlist_id_format_checks/migration.sql +0 -24
- package/templates/database/migrations/20260903004112_add_flow_session_flags_aeo_score/migration.sql +0 -3
- package/templates/database/migrations/20260903010000_add_playbook_instance/migration.sql +0 -33
- package/templates/database/migrations/20260904000000_add_waitlist_followup_send/migration.sql +0 -30
- package/templates/database/migrations/20260905230000_add_flow_checkout/migration.sql +0 -47
- package/templates/database/migrations/20260906000000_add_flow_checkout_idempotency/migration.sql +0 -16
- package/templates/database/migrations/20260907120000_add_project_listing/migration.sql +0 -47
- package/templates/database/migrations/20260907130000_add_project_listing_slack_columns/migration.sql +0 -10
- package/templates/database/migrations/20260907180000_add_listing_csv_send/migration.sql +0 -26
- package/templates/database/migrations/20260909120000_project_listings_platform/migration.sql +0 -90
- package/templates/database/migrations/20260909180000_listing_draft_and_fields/migration.sql +0 -174
- package/templates/database/migrations/20260910120000_listing_public_site_key/migration.sql +0 -14
- package/templates/database/migrations/20260911120000_listing_copy_edit_audit/migration.sql +0 -25
- package/templates/database/migrations/20260911140000_listing_structured_address/migration.sql +0 -32
- package/templates/database/migrations/20260911180000_consent_grants/migration.sql +0 -71
- package/templates/database/migrations/20260911200000_listing_site_answers/migration.sql +0 -30
- package/templates/database/migrations/20260912120000_listing_owner_link/migration.sql +0 -49
- package/templates/database/migrations/20260914120000_listing_founder_identity/migration.sql +0 -123
- package/templates/database/migrations/20260915120000_project_listing_solution/migration.sql +0 -15
- package/templates/database/migrations/20260916120000_artifact_content_store/migration.sql +0 -158
- package/templates/database/migrations/20260917120000_callback_request_confirm/migration.sql +0 -40
- package/templates/database/migrations/20260918120000_add_appointment/migration.sql +0 -67
- package/templates/database/migrations/20260918120000_asset_metadata_columns/migration.sql +0 -70
- package/templates/database/migrations/20260919120000_flow_workspace_key/migration.sql +0 -181
- package/templates/database/migrations/20260919130000_flow_definition_admin_columns/migration.sql +0 -172
- package/templates/database/migrations/20260919130000_workspace_meetings/migration.sql +0 -41
- package/templates/database/migrations/20260919140000_inbox_workspace_key/migration.sql +0 -185
- package/templates/database/migrations/20260920120000_lead_handled_at/migration.sql +0 -70
- package/templates/database/migrations/20260920130000_lead_workspace_source_index/migration.sql +0 -57
- package/templates/database/migrations/20260921120000_deliverable_grant_workspace_key/migration.sql +0 -68
- package/templates/database/migrations/20260922120000_tenancy_fence/migration.sql +0 -1067
- package/templates/database/migrations/20260923120000_listing_capturing_magnet/migration.sql +0 -210
- package/templates/database/migrations/20261003120000_spoke_registry/migration.sql +0 -80
- package/templates/database/migrations/20261003130000_scheduling_connection/migration.sql +0 -49
- package/templates/database/migrations/20261005120000_agents/migration.sql +0 -84
- package/templates/database/migrations/20261008120000_user_last_workspace/migration.sql +0 -35
- package/templates/database/migrations/20261008130000_lead_idempotency_key/migration.sql +0 -20
- package/templates/database/migrations/20261009120000_agent_grants/migration.sql +0 -33
- package/templates/database/migrations/20261010120000_person/migration.sql +0 -106
- package/templates/database/migrations/20261010121000_person_backfill/migration.sql +0 -132
- package/templates/database/migrations/20261010130000_agent_grants_people_read/migration.sql +0 -20
- package/templates/database/migrations/20261011120000_member_area/migration.sql +0 -158
- package/templates/database/migrations/20261011130000_agent_grants_member_pieces_manage/migration.sql +0 -21
- package/templates/database/migrations/20261012120000_member_contract/migration.sql +0 -192
- package/templates/database/migrations/20261013120000_lead_spoke_checkout/migration.sql +0 -20
- package/templates/database/migrations/20261014120000_consent_ledger/migration.sql +0 -122
- package/templates/database/migrations/20261014120000_person_contact/migration.sql +0 -231
- package/templates/database/migrations/20261015120000_person_notes/migration.sql +0 -77
- package/templates/database/migrations/20261015120000_rate_limit_counters/migration.sql +0 -43
- package/templates/database/migrations/20261016120000_piece_kind/migration.sql +0 -95
- package/templates/database/migrations/20261017120000_outbound_message_action/migration.sql +0 -30
- package/templates/database/migrations/20261018120000_flow_completion/migration.sql +0 -52
- package/templates/database/migrations/20261019120000_consent_source_checkout/migration.sql +0 -27
- package/templates/database/migrations/20261020120000_offerings_data_model/migration.sql +0 -146
- package/templates/database/migrations/20261021120000_offerings_checkout_session/migration.sql +0 -77
- package/templates/database/migrations/20261022120000_in_page_magnets/migration.sql +0 -45
- package/templates/database/migrations/20261023120000_offerings_shown_price_ids/migration.sql +0 -47
- package/templates/database/migrations/20261024120000_organization_plan_checkout_session/migration.sql +0 -16
- package/templates/database/migrations/20261025120000_trial_magnet/migration.sql +0 -28
- package/templates/database/migrations/20261026120000_trial_magnet_proof_line/migration.sql +0 -23
- package/templates/database/migrations/migration_lock.toml +0 -3
- package/templates/database/ops/.gitkeep +0 -0
- package/templates/database/ops/schema.prisma +0 -43
- package/templates/database/package.json +0 -89
- package/templates/database/schema.prisma +0 -71
- package/templates/database/scripts/db-generate-locked.sh +0 -80
- package/templates/database/scripts/person-backfill.sql +0 -132
- package/templates/database/tenancy.ts +0 -183
- package/templates/database/tsconfig.build.json +0 -16
- package/templates/database/tsconfig.flows.json +0 -15
- package/templates/database/tsconfig.json +0 -16
- package/templates/database/tsconfig.tenancy.json +0 -14
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
// Customer Template Database Schema
|
|
2
|
-
//
|
|
3
|
-
// MINIMAL BUT EXTENSIBLE - Only stores auth and customer extensions
|
|
4
|
-
// All business data (leads, orders, analytics) lives on the Platform
|
|
5
|
-
//
|
|
6
|
-
// Schema layout: prismaSchemaFolder (ADR 0009 D4 Phase 2, #3607). Prisma reads
|
|
7
|
-
// the whole database/ folder — each model is defined ONCE in its namespace file
|
|
8
|
-
// (database/{auth,config,ops,inbox,content}/schema.prisma). This file holds ONLY
|
|
9
|
-
// the single generator + datasource blocks — it is model-free (#3607 AC-1). The
|
|
10
|
-
// former per-User site-config models (TenantTheme/TenantSiteIdentity/TenantSEO)
|
|
11
|
-
// were re-anchored to the config namespace keyed on workspaceId (#3641).
|
|
12
|
-
|
|
13
|
-
generator client {
|
|
14
|
-
provider = "prisma-client"
|
|
15
|
-
output = "./generated/client"
|
|
16
|
-
importFileExtension = "js"
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
datasource db {
|
|
20
|
-
provider = "postgresql"
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// ============================================================================
|
|
24
|
-
// API Token Authentication (Mobile Apps, CLI, External Clients)
|
|
25
|
-
// ============================================================================
|
|
26
|
-
|
|
27
|
-
// ============================================================================
|
|
28
|
-
// OAuth 2.0 (ChatGPT Plugin, Slack Bot, External Integrations)
|
|
29
|
-
// ============================================================================
|
|
30
|
-
|
|
31
|
-
// ============================================================================
|
|
32
|
-
// Push Notifications (Mobile Apps, Web Push)
|
|
33
|
-
// ============================================================================
|
|
34
|
-
|
|
35
|
-
// ============================================================================
|
|
36
|
-
// User Data Extensions (Customer Customizations)
|
|
37
|
-
// ============================================================================
|
|
38
|
-
|
|
39
|
-
// ============================================================================
|
|
40
|
-
// Site Settings (Site-wide Configuration)
|
|
41
|
-
// ============================================================================
|
|
42
|
-
|
|
43
|
-
// ============================================================================
|
|
44
|
-
// Inbox Namespace (database/inbox/schema.prisma — B1)
|
|
45
|
-
//
|
|
46
|
-
// Anonymous lead/subscriber/callback data. siteId is a plain String — no FK
|
|
47
|
-
// to auth-namespace models per ADR 0009 D2. Cross-namespace assembly routes
|
|
48
|
-
// through apps/api/src/services/ (D3).
|
|
49
|
-
// ============================================================================
|
|
50
|
-
|
|
51
|
-
// ============================================================================
|
|
52
|
-
// Tenancy — multi-tenant module (database/auth/schema.prisma — FEAT-042)
|
|
53
|
-
//
|
|
54
|
-
// Organization → Workspace → Membership. Same-namespace @relation to User is
|
|
55
|
-
// allowed (auth namespace: identity + tenancy membership per ADR 0009).
|
|
56
|
-
// Organization/Membership/Invitation are managed by the Better Auth
|
|
57
|
-
// organization plugin (apps/workspace auth config); Workspace is AILK's own
|
|
58
|
-
// model (plugin teams feature rejected — per-team membership contradicts
|
|
59
|
-
// org-level membership; see docs/research/ploy-capture/lessons/).
|
|
60
|
-
// ============================================================================
|
|
61
|
-
|
|
62
|
-
// ============================================================================
|
|
63
|
-
// Chat/Artifact substrate (database/content/schema.prisma)
|
|
64
|
-
//
|
|
65
|
-
// Event-sourced conversation transport + artifact persistence per
|
|
66
|
-
// docs/research/ploy-capture/BACKEND-REQUIREMENTS.md. Every table carries a
|
|
67
|
-
// non-null workspaceId tenant scope as a plain String — no cross-namespace
|
|
68
|
-
// FK into auth (ADR 0009 invariant 1). Cross-namespace assembly (tenant
|
|
69
|
-
// guard, unread counts per user) routes through apps/api/src/services/.
|
|
70
|
-
// ============================================================================
|
|
71
|
-
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# db-generate-locked.sh — serialise concurrent `pnpm --filter @working-theory/database db:generate`
|
|
3
|
-
# calls so parallel prebuild scripts don't race on database/generated/client/.
|
|
4
|
-
#
|
|
5
|
-
# Background: four apps-paid/* packages each declare a `prebuild` that calls
|
|
6
|
-
# db:generate. When `pnpm -r build` triggers them in parallel the concurrent
|
|
7
|
-
# Prisma invocations race on the shared database/generated/client/ output dir,
|
|
8
|
-
# producing either "directory not empty" rmdir errors or "doesn't look like a
|
|
9
|
-
# generated Prisma Client" sanity-check failures. See issue #1690.
|
|
10
|
-
#
|
|
11
|
-
# Lock mechanism: mkdir(1) is atomic on POSIX filesystems (including macOS APFS).
|
|
12
|
-
# The first caller wins the lock dir and runs the generate; concurrent callers
|
|
13
|
-
# spin-wait. If the winner finishes before they time out, they see the output
|
|
14
|
-
# dir already present and skip. Stale locks are detected via a PID file stored
|
|
15
|
-
# inside the lock dir; if the owning PID is no longer alive the lock is removed
|
|
16
|
-
# and the next caller re-runs the generate.
|
|
17
|
-
|
|
18
|
-
set -euo pipefail
|
|
19
|
-
|
|
20
|
-
# Workspace root: two levels up from database/scripts/
|
|
21
|
-
WORKSPACE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
22
|
-
DATABASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
23
|
-
|
|
24
|
-
LOCK_DIR="$WORKSPACE_ROOT/.claude/.db-generate.lock"
|
|
25
|
-
TIMEOUT_SECONDS=120
|
|
26
|
-
POLL_INTERVAL=1
|
|
27
|
-
|
|
28
|
-
# --- Acquire lock via atomic mkdir ---
|
|
29
|
-
acquire_lock() {
|
|
30
|
-
if mkdir "$LOCK_DIR" 2>/dev/null; then
|
|
31
|
-
echo "$$" > "$LOCK_DIR/pid"
|
|
32
|
-
return 0 # acquired
|
|
33
|
-
fi
|
|
34
|
-
return 1 # not acquired
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
# --- Check if a stale lock can be cleared ---
|
|
38
|
-
maybe_clear_stale_lock() {
|
|
39
|
-
local pid_file="$LOCK_DIR/pid"
|
|
40
|
-
if [ -f "$pid_file" ]; then
|
|
41
|
-
local owner_pid
|
|
42
|
-
owner_pid="$(cat "$pid_file" 2>/dev/null || echo "")"
|
|
43
|
-
if [ -n "$owner_pid" ] && ! kill -0 "$owner_pid" 2>/dev/null; then
|
|
44
|
-
# Owner process is gone — lock is stale; remove it
|
|
45
|
-
rm -rf "$LOCK_DIR"
|
|
46
|
-
fi
|
|
47
|
-
fi
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
# --- Release lock on exit ---
|
|
51
|
-
release_lock() {
|
|
52
|
-
rm -rf "$LOCK_DIR" 2>/dev/null || true
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
# --- Main ---
|
|
56
|
-
elapsed=0
|
|
57
|
-
|
|
58
|
-
while true; do
|
|
59
|
-
maybe_clear_stale_lock
|
|
60
|
-
if acquire_lock; then
|
|
61
|
-
trap release_lock EXIT
|
|
62
|
-
break
|
|
63
|
-
fi
|
|
64
|
-
|
|
65
|
-
# Another process holds the lock — if it already wrote the output, skip
|
|
66
|
-
if [ -d "$DATABASE_DIR/generated/client" ]; then
|
|
67
|
-
echo "db-generate-locked: client already present (written by concurrent process), skipping."
|
|
68
|
-
exit 0
|
|
69
|
-
fi
|
|
70
|
-
|
|
71
|
-
elapsed=$((elapsed + POLL_INTERVAL))
|
|
72
|
-
if [ "$elapsed" -ge "$TIMEOUT_SECONDS" ]; then
|
|
73
|
-
echo "db-generate-locked: timed out waiting for lock after ${TIMEOUT_SECONDS}s; running generate anyway." >&2
|
|
74
|
-
break
|
|
75
|
-
fi
|
|
76
|
-
sleep "$POLL_INTERVAL"
|
|
77
|
-
done
|
|
78
|
-
|
|
79
|
-
echo "db-generate-locked: running db:generate for @working-theory/database"
|
|
80
|
-
pnpm --filter @working-theory/database db:generate
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
-- #852 — the Person backfill (spec
|
|
2
|
-
-- docs/specs/852-person-the-per-workspace-client-spec.md D2, D4).
|
|
3
|
-
--
|
|
4
|
-
-- Fills "people" from the rows the hub already holds and stamps
|
|
5
|
-
-- leads.person_id and appointments.person_id, so the People list is not
|
|
6
|
-
-- empty on the day it ships. Set-based and idempotent: every insert is
|
|
7
|
-
-- ON CONFLICT DO NOTHING and every update is guarded by IS NULL, so running
|
|
8
|
-
-- this text twice changes nothing the first run wrote.
|
|
9
|
-
--
|
|
10
|
-
-- THE SAME TEXT, byte for byte, is database/scripts/person-backfill.sql. The
|
|
11
|
-
-- previous deployment keeps writing leads and appointments without a
|
|
12
|
-
-- person_id between this migration and the cutover to the new code; run
|
|
13
|
-
-- that script ONCE against the hub database after the cutover to stamp them.
|
|
14
|
-
-- database/__tests__/person.db.test.ts asserts the two files are identical
|
|
15
|
-
-- and that a second run changes no row.
|
|
16
|
-
--
|
|
17
|
-
-- Normalization — the SQL twin of apps/api/src/services/person.ts's
|
|
18
|
-
-- normalizePersonEmail / isStorablePersonEmail:
|
|
19
|
-
-- N(x) = lower(btrim(x, E' \t\n\r\f\x0B') COLLATE "C")
|
|
20
|
-
-- (\x0B is vertical tab; an E-string has no \v escape — E'\v'
|
|
21
|
-
-- is the letter v, which would strip the v of every .dev)
|
|
22
|
-
-- VALID(e) = e ~ '^[!-?A-~]+@[!-?A-~]+$' AND length(e) <= 254
|
|
23
|
-
-- NAME(x) = C0/C1 controls and bidi controls removed, trimmed, cut to
|
|
24
|
-
-- 200 characters; empty → NULL
|
|
25
|
-
-- A row whose email is not VALID makes no Person and keeps person_id NULL.
|
|
26
|
-
--
|
|
27
|
-
-- Sources, in order: leads (oldest first), then completed hub FlowCheckouts
|
|
28
|
-
-- through their lead (the customer id, first writer wins), then appointments
|
|
29
|
-
-- by attendee email. Subscriber is NOT a source; FlowSession, ProjectListing
|
|
30
|
-
-- and DeliverableGrant reach a Person through their lead at read time.
|
|
31
|
-
-- The join to "users" reads the auth namespace inside this one-off
|
|
32
|
-
-- statement only; it adds no foreign key (ADR 0009 invariant 1).
|
|
33
|
-
--
|
|
34
|
-
-- Rollback: nothing to undo on its own — dropping 20261010120000_person's
|
|
35
|
-
-- table and columns removes everything this wrote.
|
|
36
|
-
|
|
37
|
-
-- 1. Leads, oldest first: one Person per (workspace, normalized email). The
|
|
38
|
-
-- name is the oldest lead's payload.name when it is a JSON string.
|
|
39
|
-
INSERT INTO "people" ("workspace_id", "email", "name", "created_at", "updated_at")
|
|
40
|
-
SELECT DISTINCT ON (l."workspace_id", lower(btrim(l."email", E' \t\n\r\f\x0B') COLLATE "C"))
|
|
41
|
-
l."workspace_id",
|
|
42
|
-
lower(btrim(l."email", E' \t\n\r\f\x0B') COLLATE "C"),
|
|
43
|
-
CASE WHEN jsonb_typeof(l."payload" -> 'name') = 'string'
|
|
44
|
-
THEN NULLIF(left(btrim(regexp_replace(l."payload" ->> 'name', '[\x01-\x1F\x7F-\x9F\u200E\u200F\u202A-\u202E\u2066-\u2069]', '', 'g')), 200), '')
|
|
45
|
-
END,
|
|
46
|
-
l."created_at",
|
|
47
|
-
now()
|
|
48
|
-
FROM "leads" l
|
|
49
|
-
WHERE lower(btrim(l."email", E' \t\n\r\f\x0B') COLLATE "C") ~ '^[!-?A-~]+@[!-?A-~]+$'
|
|
50
|
-
AND length(lower(btrim(l."email", E' \t\n\r\f\x0B') COLLATE "C")) <= 254
|
|
51
|
-
ORDER BY l."workspace_id", lower(btrim(l."email", E' \t\n\r\f\x0B') COLLATE "C"), l."created_at" ASC, l."id" ASC
|
|
52
|
-
ON CONFLICT ("workspace_id", "email") DO NOTHING;
|
|
53
|
-
|
|
54
|
-
-- 2. Hub FlowCheckouts, through their lead (same workspace): the oldest
|
|
55
|
-
-- completed checkout with a customer id writes it onto a Person that has
|
|
56
|
-
-- none. First writer wins — oldest by completed_at, then created_at, then id.
|
|
57
|
-
UPDATE "people" p
|
|
58
|
-
SET "billing_provider" = 'stripe',
|
|
59
|
-
"billing_customer_id" = c."stripe_customer_id",
|
|
60
|
-
"updated_at" = now()
|
|
61
|
-
FROM (
|
|
62
|
-
SELECT DISTINCT ON (fc."workspace_id", lower(btrim(l."email", E' \t\n\r\f\x0B') COLLATE "C"))
|
|
63
|
-
fc."workspace_id",
|
|
64
|
-
lower(btrim(l."email", E' \t\n\r\f\x0B') COLLATE "C") AS "email",
|
|
65
|
-
fc."stripe_customer_id"
|
|
66
|
-
FROM "flow_checkouts" fc
|
|
67
|
-
JOIN "leads" l ON l."id" = fc."lead_id" AND l."workspace_id" = fc."workspace_id"
|
|
68
|
-
WHERE fc."status" = 'completed'
|
|
69
|
-
AND fc."stripe_customer_id" IS NOT NULL
|
|
70
|
-
AND fc."stripe_customer_id" <> ''
|
|
71
|
-
AND length(fc."stripe_customer_id") <= 255
|
|
72
|
-
ORDER BY fc."workspace_id", lower(btrim(l."email", E' \t\n\r\f\x0B') COLLATE "C"),
|
|
73
|
-
fc."completed_at" ASC NULLS LAST, fc."created_at" ASC, fc."id" ASC
|
|
74
|
-
) c
|
|
75
|
-
WHERE p."workspace_id" = c."workspace_id"
|
|
76
|
-
AND p."email" = c."email"
|
|
77
|
-
AND p."billing_customer_id" IS NULL;
|
|
78
|
-
|
|
79
|
-
-- 3. Appointments, by attendee email: a Person a lead already made keeps its
|
|
80
|
-
-- lead-derived name and created_at (ON CONFLICT DO NOTHING).
|
|
81
|
-
INSERT INTO "people" ("workspace_id", "email", "name", "created_at", "updated_at")
|
|
82
|
-
SELECT DISTINCT ON (a."workspace_id", lower(btrim(a."attendee_email", E' \t\n\r\f\x0B') COLLATE "C"))
|
|
83
|
-
a."workspace_id",
|
|
84
|
-
lower(btrim(a."attendee_email", E' \t\n\r\f\x0B') COLLATE "C"),
|
|
85
|
-
NULLIF(left(btrim(regexp_replace(a."attendee_name", '[\x01-\x1F\x7F-\x9F\u200E\u200F\u202A-\u202E\u2066-\u2069]', '', 'g')), 200), ''),
|
|
86
|
-
a."created_at",
|
|
87
|
-
now()
|
|
88
|
-
FROM "appointments" a
|
|
89
|
-
WHERE lower(btrim(a."attendee_email", E' \t\n\r\f\x0B') COLLATE "C") ~ '^[!-?A-~]+@[!-?A-~]+$'
|
|
90
|
-
AND length(lower(btrim(a."attendee_email", E' \t\n\r\f\x0B') COLLATE "C")) <= 254
|
|
91
|
-
ORDER BY a."workspace_id", lower(btrim(a."attendee_email", E' \t\n\r\f\x0B') COLLATE "C"), a."created_at" ASC, a."id" ASC
|
|
92
|
-
ON CONFLICT ("workspace_id", "email") DO NOTHING;
|
|
93
|
-
|
|
94
|
-
-- 4. Stamps: every lead and appointment with a storable email points at its
|
|
95
|
-
-- workspace's Person; a row already stamped is left alone.
|
|
96
|
-
UPDATE "leads"
|
|
97
|
-
SET "person_id" = p."id"
|
|
98
|
-
FROM "people" p
|
|
99
|
-
WHERE "leads"."person_id" IS NULL
|
|
100
|
-
AND p."workspace_id" = "leads"."workspace_id"
|
|
101
|
-
AND p."email" = lower(btrim("leads"."email", E' \t\n\r\f\x0B') COLLATE "C");
|
|
102
|
-
|
|
103
|
-
UPDATE "appointments"
|
|
104
|
-
SET "person_id" = p."id"
|
|
105
|
-
FROM "people" p
|
|
106
|
-
WHERE "appointments"."person_id" IS NULL
|
|
107
|
-
AND p."workspace_id" = "appointments"."workspace_id"
|
|
108
|
-
AND p."email" = lower(btrim("appointments"."attendee_email", E' \t\n\r\f\x0B') COLLATE "C");
|
|
109
|
-
|
|
110
|
-
-- 5. user_id, verified only: the oldest promoted lead (by promoted_at, then
|
|
111
|
-
-- created_at, then id) whose user is email-verified and whose verified
|
|
112
|
-
-- address normalizes to the Person's. An unverified or differing user is
|
|
113
|
-
-- never copied — the rule stampPersonUser applies to new rows.
|
|
114
|
-
UPDATE "people" p
|
|
115
|
-
SET "user_id" = c."user_id",
|
|
116
|
-
"updated_at" = now()
|
|
117
|
-
FROM (
|
|
118
|
-
SELECT DISTINCT ON (l."workspace_id", lower(btrim(l."email", E' \t\n\r\f\x0B') COLLATE "C"))
|
|
119
|
-
l."workspace_id",
|
|
120
|
-
lower(btrim(l."email", E' \t\n\r\f\x0B') COLLATE "C") AS "email",
|
|
121
|
-
l."promoted_user_id" AS "user_id"
|
|
122
|
-
FROM "leads" l
|
|
123
|
-
JOIN "users" u ON u."id" = l."promoted_user_id"
|
|
124
|
-
WHERE l."promoted_user_id" IS NOT NULL
|
|
125
|
-
AND u."email_verified" = true
|
|
126
|
-
AND lower(btrim(u."email", E' \t\n\r\f\x0B') COLLATE "C") = lower(btrim(l."email", E' \t\n\r\f\x0B') COLLATE "C")
|
|
127
|
-
ORDER BY l."workspace_id", lower(btrim(l."email", E' \t\n\r\f\x0B') COLLATE "C"),
|
|
128
|
-
l."promoted_at" ASC NULLS LAST, l."created_at" ASC, l."id" ASC
|
|
129
|
-
) c
|
|
130
|
-
WHERE p."workspace_id" = c."workspace_id"
|
|
131
|
-
AND p."email" = c."email"
|
|
132
|
-
AND p."user_id" IS NULL;
|
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Default tenancy identity constants — the SINGLE source of truth (spec D3).
|
|
3
|
-
*
|
|
4
|
-
* The well-known default Organization + Workspace ids/slugs that the
|
|
5
|
-
* single-tenant provision seed (Phase 1, #3622 — `database/seed.ts`) creates,
|
|
6
|
-
* and that the session-resolution guard (Phase 2, #3627 —
|
|
7
|
-
* `apps/api/src/services/tenant-context.ts`) binds on to resolve a default
|
|
8
|
-
* scope for a single-tenant deployment. Exported publicly via the
|
|
9
|
-
* `@working-theory/database/tenancy` subpath (see `package.json` `exports`)
|
|
10
|
-
* so `apps/api` can import them across the package boundary without a second,
|
|
11
|
-
* drift-prone declaration of the tenant-isolation identity.
|
|
12
|
-
*
|
|
13
|
-
* See docs/specs/single-tenant-session-workspace-spec.md §3 D3.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
// The three constants below are SENTINEL ids from the reserved range of the
|
|
17
|
-
// prefixed-UUIDv7 scheme (ADR-0031 rule 7): zero timestamp bits + version 7 +
|
|
18
|
-
// variant 8 + a small counter suffix. They are valid-shaped v7 ids (the
|
|
19
|
-
// database CHECK constraints admit them), can never collide with a generated
|
|
20
|
-
// id (a real v7's timestamp bits are the current epoch-ms, never zero), and
|
|
21
|
-
// are recognizable via `isSentinel(id)` from `@working-theory/ids` — key on
|
|
22
|
-
// that predicate, never a hardcoded literal. They carry the branded `Id<E>`
|
|
23
|
-
// types so consumers get compile-time entity safety (ADR-0031 rule 5).
|
|
24
|
-
|
|
25
|
-
import { isSentinel, type Id } from "@working-theory/ids";
|
|
26
|
-
|
|
27
|
-
/** Well-known default Organization identity — a fixed reserved-range sentinel. */
|
|
28
|
-
export const DEFAULT_ORG_ID =
|
|
29
|
-
"org_00000000-0000-7000-8000-000000000001" as Id<"organization">;
|
|
30
|
-
export const DEFAULT_ORG_SLUG = "default";
|
|
31
|
-
|
|
32
|
-
/** Well-known default Workspace identity — a fixed reserved-range sentinel. */
|
|
33
|
-
export const DEFAULT_WORKSPACE_ID =
|
|
34
|
-
"wksp_00000000-0000-7000-8000-000000000001" as Id<"workspace">;
|
|
35
|
-
export const DEFAULT_WORKSPACE_SLUG = "default";
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Well-known Membership id the single-tenant owner-pin binds the operator
|
|
39
|
-
* to (docs/specs/single-tenant-owner-pin-spec.md D2). A fixed sentinel id
|
|
40
|
-
* makes the TOFU operator-binding insert race-safe: the `Membership.id`
|
|
41
|
-
* primary-key uniqueness — not application-level "is this the first
|
|
42
|
-
* user?" logic — enforces exactly one owner under concurrent first-logins.
|
|
43
|
-
*/
|
|
44
|
-
export const OPERATOR_MEMBERSHIP_ID =
|
|
45
|
-
"member_00000000-0000-7000-8000-000000000001" as Id<"membership">;
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* The minimal structural client the one-workspace predicate needs — no
|
|
49
|
-
* `@prisma/client` import, so this file stays a leaf `tsconfig.tenancy.json`
|
|
50
|
-
* can build without the generated client (#5876 spec D2). `apps/api` and
|
|
51
|
-
* `apps/mcp` are both `database`-importers (`architecture.yaml`
|
|
52
|
-
* `may_import_from`), and `database/**` is already wholesale-excluded from
|
|
53
|
-
* the tenant-scope `forbidden_pattern` — the only file this predicate could
|
|
54
|
-
* live in without widening that security allowlist.
|
|
55
|
-
*/
|
|
56
|
-
export interface WorkspacePredicateClient {
|
|
57
|
-
workspace: {
|
|
58
|
-
count(): Promise<number>;
|
|
59
|
-
findUnique(args: {
|
|
60
|
-
where: { id: string };
|
|
61
|
-
}): Promise<{ organizationId: string } | null>;
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* The one-workspace deployment predicate (#5876 spec D2), shared by every
|
|
67
|
-
* caller across the package boundary: `workspace.count() !== 1 ⇒ null`, then
|
|
68
|
-
* the sole workspace must be the well-known default AND hang off a sentinel
|
|
69
|
-
* Organization, or the deployment is not unambiguously single-tenant.
|
|
70
|
-
*
|
|
71
|
-
* Returns the **row** (`{ id, organizationId }`), not a projection — a
|
|
72
|
-
* caller that needs `organizationId` (as `resolveDefaultTenant` in
|
|
73
|
-
* `apps/api/src/services/default-tenant.ts` does) would otherwise have to
|
|
74
|
-
* run a second `findUnique`, which is the second-predicate drift NFR-7
|
|
75
|
-
* forbids. A caller that only needs the id projects `.id` itself.
|
|
76
|
-
*
|
|
77
|
-
* Carries no authentication — it answers "is this deployment one-workspace,
|
|
78
|
-
* and which workspace is it," nothing about the caller.
|
|
79
|
-
*/
|
|
80
|
-
export async function resolveDefaultWorkspaceRow(
|
|
81
|
-
prisma: WorkspacePredicateClient,
|
|
82
|
-
): Promise<{ id: Id<"workspace">; organizationId: string } | null> {
|
|
83
|
-
const workspaceCount = await prisma.workspace.count();
|
|
84
|
-
if (workspaceCount !== 1) {
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
const workspace = await prisma.workspace.findUnique({
|
|
88
|
-
where: { id: DEFAULT_WORKSPACE_ID },
|
|
89
|
-
});
|
|
90
|
-
// The default workspace must hang off the sentinel default Organization
|
|
91
|
-
// (ADR-0031 rule 7): keyed on the reserved-range predicate, not a literal.
|
|
92
|
-
if (!workspace || !isSentinel(workspace.organizationId)) {
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
return { id: DEFAULT_WORKSPACE_ID, organizationId: workspace.organizationId };
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* The sentinel-EXISTENCE predicate (#6155 spec D2 rule 2), a SIBLING of
|
|
100
|
-
* {@link resolveDefaultWorkspaceRow}, not a replacement for it: it answers
|
|
101
|
-
* "does the well-known default workspace exist", never "is this deployment
|
|
102
|
-
* unambiguously single-tenant" — so it carries NO `workspace.count()` gate.
|
|
103
|
-
*
|
|
104
|
-
* The two questions coincide on a one-workspace deployment and diverge on a
|
|
105
|
-
* correctly-configured MULTI-workspace one: there,
|
|
106
|
-
* `resolveDefaultWorkspaceRow`'s count gate returns `null` even though the
|
|
107
|
-
* seeded sentinel workspace is present and resolvable. The site-alias
|
|
108
|
-
* resolver (`apps/api/src/lib/site.ts`) needs the sentinel-existence answer
|
|
109
|
-
* — the literal alias `"default"` names the seeded sentinel workspace on
|
|
110
|
-
* EVERY database, single- or multi-tenant (`database/seed.ts` upserts it
|
|
111
|
-
* unconditionally) — so it calls this function, not
|
|
112
|
-
* `resolveDefaultWorkspaceRow`.
|
|
113
|
-
*
|
|
114
|
-
* `resolveDefaultWorkspaceRow` is deliberately NOT modified or loosened:
|
|
115
|
-
* `resolveDefaultTenant` (`apps/api/src/services/default-tenant.ts`) depends
|
|
116
|
-
* on its single-tenancy meaning, so widening it would silently widen
|
|
117
|
-
* single-tenant detection for callers that are correct today. One function,
|
|
118
|
-
* one question.
|
|
119
|
-
*/
|
|
120
|
-
export async function resolveSentinelWorkspaceRow(
|
|
121
|
-
prisma: WorkspacePredicateClient,
|
|
122
|
-
): Promise<{ id: Id<"workspace">; organizationId: string } | null> {
|
|
123
|
-
const workspace = await prisma.workspace.findUnique({
|
|
124
|
-
where: { id: DEFAULT_WORKSPACE_ID },
|
|
125
|
-
});
|
|
126
|
-
if (!workspace || !isSentinel(workspace.organizationId)) {
|
|
127
|
-
return null;
|
|
128
|
-
}
|
|
129
|
-
return { id: DEFAULT_WORKSPACE_ID, organizationId: workspace.organizationId };
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// ---------------------------------------------------------------------------
|
|
133
|
-
// #852 D7 — the Person timeline's pre-migration email fallback.
|
|
134
|
-
//
|
|
135
|
-
// A FlowSession or ProjectListing written before the Person backfill and
|
|
136
|
-
// never tied to a lead (`lead_id IS NULL`) reaches its Person only by email.
|
|
137
|
-
// These three SQL texts are the ONLY way that match is made: run by
|
|
138
|
-
// `apps/api/src/lib/tenant-db.ts`'s `people.timeline` through
|
|
139
|
-
// `$queryRawUnsafe(SQL, email, workspaceId, cutoff)`, and executed verbatim
|
|
140
|
-
// against live Postgres by `database/__tests__/person.db.test.ts` — one
|
|
141
|
-
// string, proven where it runs. `$n` placeholders only, never interpolation.
|
|
142
|
-
//
|
|
143
|
-
// The match is EXACT equality of the normalized column against the Person's
|
|
144
|
-
// stored (already-normalized) email — never Prisma's `mode: "insensitive"`,
|
|
145
|
-
// which compiles to ILIKE: `_`/`%` would act as wildcards and non-ASCII case
|
|
146
|
-
// would fold, joining another client's rows (SEC-852-B). The normalization is
|
|
147
|
-
// the backfill's N(x) (database/migrations/20261010121000_person_backfill).
|
|
148
|
-
//
|
|
149
|
-
// `$3` is the cutoff: `finished_at` of the backfill migration's
|
|
150
|
-
// `_prisma_migrations` row (`PERSON_CUTOFF_SQL`). That column is timestamptz;
|
|
151
|
-
// the inbox `created_at` columns are timestamp(3) holding UTC (Prisma's
|
|
152
|
-
// convention), so the comparison converts the cutoff to UTC wall time. Only
|
|
153
|
-
// rows strictly older than the cutoff qualify. Each returns ids only, at most
|
|
154
|
-
// 50, newest first; the caller re-reads them through its scoped findMany.
|
|
155
|
-
// ---------------------------------------------------------------------------
|
|
156
|
-
|
|
157
|
-
/** The `_prisma_migrations` key whose `finished_at` is the fallback cutoff. */
|
|
158
|
-
export const PERSON_BACKFILL_MIGRATION = "20261010121000_person_backfill";
|
|
159
|
-
|
|
160
|
-
/** `$1` = the Person's email, `$2` = workspace id, `$3` = the cutoff. */
|
|
161
|
-
export const PERSON_FALLBACK_FLOW_SESSIONS_SQL = String.raw`SELECT "id" FROM "flow_sessions"
|
|
162
|
-
WHERE "workspace_id" = $2::text
|
|
163
|
-
AND "lead_id" IS NULL
|
|
164
|
-
AND "created_at" < ($3::timestamptz AT TIME ZONE 'UTC')
|
|
165
|
-
AND lower(btrim("email", E' \t\n\r\f\x0B') COLLATE "C") = $1::text
|
|
166
|
-
ORDER BY "created_at" DESC, "id" DESC
|
|
167
|
-
LIMIT 50`;
|
|
168
|
-
|
|
169
|
-
/** `$1` = the Person's email, `$2` = workspace id, `$3` = the cutoff. */
|
|
170
|
-
export const PERSON_FALLBACK_PROJECT_LISTINGS_SQL = String.raw`SELECT "id" FROM "project_listings"
|
|
171
|
-
WHERE "workspace_id" = $2::text
|
|
172
|
-
AND "lead_id" IS NULL
|
|
173
|
-
AND "created_at" < ($3::timestamptz AT TIME ZONE 'UTC')
|
|
174
|
-
AND lower(btrim("founder_email", E' \t\n\r\f\x0B') COLLATE "C") = $1::text
|
|
175
|
-
ORDER BY "created_at" DESC, "id" DESC
|
|
176
|
-
LIMIT 50`;
|
|
177
|
-
|
|
178
|
-
/** The cutoff read: the backfill's `finished_at`, or no row when it has not run. */
|
|
179
|
-
export const PERSON_CUTOFF_SQL = `SELECT "finished_at" FROM "_prisma_migrations"
|
|
180
|
-
WHERE "migration_name" = '20261010121000_person_backfill'
|
|
181
|
-
AND "finished_at" IS NOT NULL
|
|
182
|
-
AND "rolled_back_at" IS NULL
|
|
183
|
-
LIMIT 1`;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../tsconfig.base.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"outDir": "./dist",
|
|
7
|
-
"rootDir": "./generated",
|
|
8
|
-
"declaration": true,
|
|
9
|
-
"composite": true,
|
|
10
|
-
"noEmit": false,
|
|
11
|
-
"skipLibCheck": true,
|
|
12
|
-
"types": ["node"]
|
|
13
|
-
},
|
|
14
|
-
"include": ["generated/**/*.ts"],
|
|
15
|
-
"exclude": ["node_modules", "dist", "__tests__"]
|
|
16
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../tsconfig.base.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"outDir": "./dist",
|
|
7
|
-
"rootDir": ".",
|
|
8
|
-
"declaration": true,
|
|
9
|
-
"noEmit": false,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"types": ["node"]
|
|
12
|
-
},
|
|
13
|
-
"include": ["flows/**/*.ts"],
|
|
14
|
-
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/__tests__/**"]
|
|
15
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../tsconfig.base.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"noEmit": true,
|
|
5
|
-
"rootDir": ".",
|
|
6
|
-
"types": ["node"]
|
|
7
|
-
},
|
|
8
|
-
"include": [
|
|
9
|
-
"prisma.config.ts",
|
|
10
|
-
"seed.ts",
|
|
11
|
-
"seed-test.ts",
|
|
12
|
-
"tenancy.ts",
|
|
13
|
-
"__tests__/fixtures/appointment-create-probe.ts",
|
|
14
|
-
"flows/**/*.ts"
|
|
15
|
-
]
|
|
16
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../tsconfig.base.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"outDir": "./dist",
|
|
7
|
-
"rootDir": ".",
|
|
8
|
-
"declaration": true,
|
|
9
|
-
"noEmit": false,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"types": ["node"]
|
|
12
|
-
},
|
|
13
|
-
"include": ["tenancy.ts"]
|
|
14
|
-
}
|