@voltro/cli 0.1.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/CHANGELOG.md +52 -0
- package/LICENSE +57 -0
- package/README.md +26 -0
- package/SECURITY.md +56 -0
- package/THIRD-PARTY-NOTICES.md +20236 -0
- package/bin/voltro.mjs +43 -0
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +9 -0
- package/dist/commands-CfPH2Wf4.js +18061 -0
- package/dist/frameworkInspectState-CX2250XB.js +86 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.js +5 -0
- package/dist/inspectState.d.ts +116 -0
- package/dist/inspectState.js +2 -0
- package/dist/startup.d.ts +26 -0
- package/dist/startup.js +2 -0
- package/dist/startupRunner-CRhuUl91.js +71 -0
- package/package.json +88 -0
- package/templates/AGENTS.core.md +258 -0
- package/templates/AGENTS.md +351 -0
- package/templates/agent-docs/_index.md +93 -0
- package/templates/agent-docs/_manifest.json +655 -0
- package/templates/agent-docs/ai.md +1845 -0
- package/templates/agent-docs/authentication.md +1788 -0
- package/templates/agent-docs/caching.md +624 -0
- package/templates/agent-docs/cli.md +1650 -0
- package/templates/agent-docs/configuration.md +295 -0
- package/templates/agent-docs/data.md +2172 -0
- package/templates/agent-docs/database/advancedqueries.md +1583 -0
- package/templates/agent-docs/database/columntypes.md +1200 -0
- package/templates/agent-docs/database/hosting.md +881 -0
- package/templates/agent-docs/database/migrations.md +2938 -0
- package/templates/agent-docs/database/misc.md +270 -0
- package/templates/agent-docs/database/overview.md +108 -0
- package/templates/agent-docs/database/querying.md +1622 -0
- package/templates/agent-docs/database/scaling.md +331 -0
- package/templates/agent-docs/database/schema.md +1458 -0
- package/templates/agent-docs/database/seedsdialects.md +1235 -0
- package/templates/agent-docs/database/transactions.md +285 -0
- package/templates/agent-docs/deployment.md +999 -0
- package/templates/agent-docs/internationalization.md +359 -0
- package/templates/agent-docs/introduction.md +438 -0
- package/templates/agent-docs/multi-tenancy.md +610 -0
- package/templates/agent-docs/observability.md +350 -0
- package/templates/agent-docs/plugins.md +1273 -0
- package/templates/agent-docs/reference.md +978 -0
- package/templates/agent-docs/routing.md +1553 -0
- package/templates/agent-docs/scheduling.md +666 -0
- package/templates/agent-docs/schema-driven-ui.md +607 -0
- package/templates/agent-docs/security.md +42 -0
- package/templates/agent-docs/templates/apibackends.md +3214 -0
- package/templates/agent-docs/templates/appshells.md +2062 -0
- package/templates/agent-docs/templates/custom.md +128 -0
- package/templates/agent-docs/templates/overview.md +122 -0
- package/templates/agent-docs/templates/serverless.md +315 -0
- package/templates/agent-docs/testing.md +376 -0
- package/templates/agent-docs/workflows.md +1351 -0
- package/templates/apps/api-ai/README.md +105 -0
- package/templates/apps/api-ai/actions/summarize.action.server.tsx +32 -0
- package/templates/apps/api-ai/actions/summarize.action.ts +33 -0
- package/templates/apps/api-ai/agents/support.agent.server.tsx +31 -0
- package/templates/apps/api-ai/agents/support.agent.tsx +27 -0
- package/templates/apps/api-ai/app.config.ts +57 -0
- package/templates/apps/api-ai/database/schema.ts +67 -0
- package/templates/apps/api-ai/package.json +27 -0
- package/templates/apps/api-ai/seeds/docs.seed.ts +67 -0
- package/templates/apps/api-ai/template.json +6 -0
- package/templates/apps/api-ai/tests/summarize.test.ts +50 -0
- package/templates/apps/api-ai/tools/searchDocs.tool.tsx +60 -0
- package/templates/apps/api-ai/tsconfig.json +5 -0
- package/templates/apps/api-auth/.env +17 -0
- package/templates/apps/api-auth/README.md +109 -0
- package/templates/apps/api-auth/actions/me.action.server.ts +20 -0
- package/templates/apps/api-auth/actions/me.action.ts +19 -0
- package/templates/apps/api-auth/app.config.ts +59 -0
- package/templates/apps/api-auth/database/schema.ts +26 -0
- package/templates/apps/api-auth/package.json +28 -0
- package/templates/apps/api-auth/template.json +6 -0
- package/templates/apps/api-auth/tests/me.test.ts +37 -0
- package/templates/apps/api-auth/tsconfig.json +5 -0
- package/templates/apps/api-backend/README.md +25 -0
- package/templates/apps/api-backend/app.config.ts +39 -0
- package/templates/apps/api-backend/database/schema.ts +57 -0
- package/templates/apps/api-backend/mutations/notes.create.mutation.server.ts +19 -0
- package/templates/apps/api-backend/mutations/notes.create.mutation.ts +37 -0
- package/templates/apps/api-backend/package.json +28 -0
- package/templates/apps/api-backend/queries/notes.query.server.ts +14 -0
- package/templates/apps/api-backend/queries/notes.query.ts +20 -0
- package/templates/apps/api-backend/template.json +6 -0
- package/templates/apps/api-backend/tests/notes.create.test.ts +50 -0
- package/templates/apps/api-backend/tsconfig.json +5 -0
- package/templates/apps/api-backend-deactivation/README.md +49 -0
- package/templates/apps/api-backend-deactivation/actions/users.get.action.server.ts +17 -0
- package/templates/apps/api-backend-deactivation/actions/users.get.action.ts +18 -0
- package/templates/apps/api-backend-deactivation/app.config.ts +20 -0
- package/templates/apps/api-backend-deactivation/database/schema.ts +41 -0
- package/templates/apps/api-backend-deactivation/mutations/users.create.mutation.server.ts +6 -0
- package/templates/apps/api-backend-deactivation/mutations/users.create.mutation.ts +16 -0
- package/templates/apps/api-backend-deactivation/mutations/users.deactivate.mutation.server.ts +10 -0
- package/templates/apps/api-backend-deactivation/mutations/users.deactivate.mutation.ts +19 -0
- package/templates/apps/api-backend-deactivation/package.json +28 -0
- package/templates/apps/api-backend-deactivation/template.json +6 -0
- package/templates/apps/api-backend-deactivation/tests/users.deactivate.test.ts +47 -0
- package/templates/apps/api-backend-deactivation/tsconfig.json +5 -0
- package/templates/apps/api-backend-mail/README.md +39 -0
- package/templates/apps/api-backend-mail/actions/sendWelcome.action.server.ts +15 -0
- package/templates/apps/api-backend-mail/actions/sendWelcome.action.ts +21 -0
- package/templates/apps/api-backend-mail/app.config.ts +34 -0
- package/templates/apps/api-backend-mail/database/schema.ts +57 -0
- package/templates/apps/api-backend-mail/emails/welcome.email.tsx +106 -0
- package/templates/apps/api-backend-mail/mutations/notes.create.mutation.server.ts +19 -0
- package/templates/apps/api-backend-mail/mutations/notes.create.mutation.ts +37 -0
- package/templates/apps/api-backend-mail/package.json +30 -0
- package/templates/apps/api-backend-mail/queries/notes.query.server.ts +14 -0
- package/templates/apps/api-backend-mail/queries/notes.query.ts +20 -0
- package/templates/apps/api-backend-mail/template.json +6 -0
- package/templates/apps/api-backend-mail/tests/notes.create.test.ts +50 -0
- package/templates/apps/api-backend-mail/tsconfig.json +5 -0
- package/templates/apps/api-backend-mariadb/.env.example +35 -0
- package/templates/apps/api-backend-mariadb/README.md +31 -0
- package/templates/apps/api-backend-mariadb/app.config.ts +68 -0
- package/templates/apps/api-backend-mariadb/database/schema.ts +57 -0
- package/templates/apps/api-backend-mariadb/mutations/notes.create.mutation.server.ts +19 -0
- package/templates/apps/api-backend-mariadb/mutations/notes.create.mutation.ts +37 -0
- package/templates/apps/api-backend-mariadb/package.json +30 -0
- package/templates/apps/api-backend-mariadb/queries/notes.query.server.ts +14 -0
- package/templates/apps/api-backend-mariadb/queries/notes.query.ts +20 -0
- package/templates/apps/api-backend-mariadb/template.json +6 -0
- package/templates/apps/api-backend-mariadb/tests/notes.create.test.ts +50 -0
- package/templates/apps/api-backend-mariadb/tsconfig.json +5 -0
- package/templates/apps/api-backend-storage/README.md +86 -0
- package/templates/apps/api-backend-storage/actions/uploadAvatar.action.server.ts +21 -0
- package/templates/apps/api-backend-storage/actions/uploadAvatar.action.ts +21 -0
- package/templates/apps/api-backend-storage/actions/uploadDocument.action.server.ts +21 -0
- package/templates/apps/api-backend-storage/actions/uploadDocument.action.ts +20 -0
- package/templates/apps/api-backend-storage/app.config.ts +38 -0
- package/templates/apps/api-backend-storage/database/schema.ts +57 -0
- package/templates/apps/api-backend-storage/mutations/notes.create.mutation.server.ts +19 -0
- package/templates/apps/api-backend-storage/mutations/notes.create.mutation.ts +37 -0
- package/templates/apps/api-backend-storage/package.json +27 -0
- package/templates/apps/api-backend-storage/queries/notes.query.server.ts +14 -0
- package/templates/apps/api-backend-storage/queries/notes.query.ts +20 -0
- package/templates/apps/api-backend-storage/template.json +6 -0
- package/templates/apps/api-backend-storage/tests/notes.create.test.ts +50 -0
- package/templates/apps/api-backend-storage/tsconfig.json +5 -0
- package/templates/apps/api-data-advanced/.env +17 -0
- package/templates/apps/api-data-advanced/README.md +88 -0
- package/templates/apps/api-data-advanced/app.config.ts +56 -0
- package/templates/apps/api-data-advanced/database/actors.entity.ts +14 -0
- package/templates/apps/api-data-advanced/database/authors.entity.ts +30 -0
- package/templates/apps/api-data-advanced/database/authors.relations.ts +15 -0
- package/templates/apps/api-data-advanced/database/books.entity.ts +59 -0
- package/templates/apps/api-data-advanced/database/books.relations.ts +10 -0
- package/templates/apps/api-data-advanced/database/index.ts +23 -0
- package/templates/apps/api-data-advanced/database/tenants.entity.ts +11 -0
- package/templates/apps/api-data-advanced/package.json +28 -0
- package/templates/apps/api-data-advanced/queries/authors.withBooks.query.server.ts +18 -0
- package/templates/apps/api-data-advanced/queries/authors.withBooks.query.ts +40 -0
- package/templates/apps/api-data-advanced/queries/books.search.query.server.ts +17 -0
- package/templates/apps/api-data-advanced/queries/books.search.query.ts +39 -0
- package/templates/apps/api-data-advanced/seeds/catalog.seed.ts +101 -0
- package/templates/apps/api-data-advanced/template.json +6 -0
- package/templates/apps/api-data-advanced/tests/queries.test.ts +124 -0
- package/templates/apps/api-data-advanced/tsconfig.json +5 -0
- package/templates/apps/api-durable/README.md +81 -0
- package/templates/apps/api-durable/aggregates/orderStats.aggregate.ts +49 -0
- package/templates/apps/api-durable/app.config.ts +41 -0
- package/templates/apps/api-durable/database/schema.ts +65 -0
- package/templates/apps/api-durable/mutations/orders.approve.mutation.server.ts +43 -0
- package/templates/apps/api-durable/mutations/orders.approve.mutation.ts +23 -0
- package/templates/apps/api-durable/mutations/orders.place.mutation.server.ts +45 -0
- package/templates/apps/api-durable/mutations/orders.place.mutation.ts +40 -0
- package/templates/apps/api-durable/package.json +28 -0
- package/templates/apps/api-durable/schedules/nightlyReport.cron.tsx +37 -0
- package/templates/apps/api-durable/startup/warm.startup.tsx +33 -0
- package/templates/apps/api-durable/subscribers/orderChanges.subscribe.ts +27 -0
- package/templates/apps/api-durable/template.json +6 -0
- package/templates/apps/api-durable/tests/orders.place.test.ts +91 -0
- package/templates/apps/api-durable/triggers/order.placed.trigger.tsx +21 -0
- package/templates/apps/api-durable/tsconfig.json +5 -0
- package/templates/apps/api-durable/workflows/order.fulfill.workflow.server.tsx +103 -0
- package/templates/apps/api-durable/workflows/order.fulfill.workflow.tsx +25 -0
- package/templates/apps/api-feature-flags/README.md +63 -0
- package/templates/apps/api-feature-flags/actions/notes.export.action.server.ts +11 -0
- package/templates/apps/api-feature-flags/actions/notes.export.action.ts +18 -0
- package/templates/apps/api-feature-flags/app.config.ts +41 -0
- package/templates/apps/api-feature-flags/database/schema.ts +37 -0
- package/templates/apps/api-feature-flags/mutations/notes.create.mutation.server.ts +29 -0
- package/templates/apps/api-feature-flags/mutations/notes.create.mutation.ts +28 -0
- package/templates/apps/api-feature-flags/package.json +29 -0
- package/templates/apps/api-feature-flags/template.json +6 -0
- package/templates/apps/api-feature-flags/tests/notes.create.test.ts +67 -0
- package/templates/apps/api-feature-flags/tsconfig.json +5 -0
- package/templates/apps/api-governance/.env +4 -0
- package/templates/apps/api-governance/README.md +61 -0
- package/templates/apps/api-governance/actions/profiles.get.action.server.ts +17 -0
- package/templates/apps/api-governance/actions/profiles.get.action.ts +17 -0
- package/templates/apps/api-governance/app.config.ts +35 -0
- package/templates/apps/api-governance/database/schema.ts +41 -0
- package/templates/apps/api-governance/mutations/profiles.create.mutation.server.ts +17 -0
- package/templates/apps/api-governance/mutations/profiles.create.mutation.ts +21 -0
- package/templates/apps/api-governance/package.json +29 -0
- package/templates/apps/api-governance/template.json +6 -0
- package/templates/apps/api-governance/tests/profiles.create.test.ts +59 -0
- package/templates/apps/api-governance/tsconfig.json +5 -0
- package/templates/apps/api-kv/README.md +100 -0
- package/templates/apps/api-kv/actions/sync.pull.action.server.ts +75 -0
- package/templates/apps/api-kv/actions/sync.pull.action.ts +25 -0
- package/templates/apps/api-kv/actions/sync.reset.action.server.ts +25 -0
- package/templates/apps/api-kv/actions/sync.reset.action.ts +22 -0
- package/templates/apps/api-kv/actions/sync.status.action.server.ts +28 -0
- package/templates/apps/api-kv/actions/sync.status.action.ts +17 -0
- package/templates/apps/api-kv/app.config.ts +48 -0
- package/templates/apps/api-kv/database/schema.ts +62 -0
- package/templates/apps/api-kv/package.json +28 -0
- package/templates/apps/api-kv/queries/events.list.query.server.ts +14 -0
- package/templates/apps/api-kv/queries/events.list.query.ts +23 -0
- package/templates/apps/api-kv/template.json +6 -0
- package/templates/apps/api-kv/tests/sync.test.ts +103 -0
- package/templates/apps/api-kv/tsconfig.json +5 -0
- package/templates/apps/api-moderation/README.md +46 -0
- package/templates/apps/api-moderation/app.config.ts +33 -0
- package/templates/apps/api-moderation/database/schema.ts +45 -0
- package/templates/apps/api-moderation/mutations/comments.create.mutation.server.ts +8 -0
- package/templates/apps/api-moderation/mutations/comments.create.mutation.ts +20 -0
- package/templates/apps/api-moderation/mutations/posts.create.mutation.server.ts +9 -0
- package/templates/apps/api-moderation/mutations/posts.create.mutation.ts +25 -0
- package/templates/apps/api-moderation/package.json +29 -0
- package/templates/apps/api-moderation/template.json +6 -0
- package/templates/apps/api-moderation/tests/posts.create.test.ts +79 -0
- package/templates/apps/api-moderation/tsconfig.json +5 -0
- package/templates/apps/api-observability/README.md +106 -0
- package/templates/apps/api-observability/app.config.ts +32 -0
- package/templates/apps/api-observability/database/schema.ts +38 -0
- package/templates/apps/api-observability/mutations/notes.create.mutation.server.ts +33 -0
- package/templates/apps/api-observability/mutations/notes.create.mutation.ts +15 -0
- package/templates/apps/api-observability/package.json +29 -0
- package/templates/apps/api-observability/queries/notes.list.query.server.ts +7 -0
- package/templates/apps/api-observability/queries/notes.list.query.ts +14 -0
- package/templates/apps/api-observability/template.json +6 -0
- package/templates/apps/api-observability/tests/notes.create.test.ts +36 -0
- package/templates/apps/api-observability/tsconfig.json +5 -0
- package/templates/apps/api-ratelimit/README.md +49 -0
- package/templates/apps/api-ratelimit/app.config.ts +42 -0
- package/templates/apps/api-ratelimit/database/schema.ts +37 -0
- package/templates/apps/api-ratelimit/mutations/notes.create.mutation.server.ts +16 -0
- package/templates/apps/api-ratelimit/mutations/notes.create.mutation.ts +34 -0
- package/templates/apps/api-ratelimit/package.json +29 -0
- package/templates/apps/api-ratelimit/template.json +6 -0
- package/templates/apps/api-ratelimit/tests/notes.create.test.ts +69 -0
- package/templates/apps/api-ratelimit/tsconfig.json +5 -0
- package/templates/apps/api-rbac/README.md +59 -0
- package/templates/apps/api-rbac/app.config.ts +48 -0
- package/templates/apps/api-rbac/database/schema.ts +37 -0
- package/templates/apps/api-rbac/mutations/notes.create.mutation.server.ts +22 -0
- package/templates/apps/api-rbac/mutations/notes.create.mutation.ts +26 -0
- package/templates/apps/api-rbac/package.json +29 -0
- package/templates/apps/api-rbac/template.json +6 -0
- package/templates/apps/api-rbac/tests/notes.create.test.ts +80 -0
- package/templates/apps/api-rbac/tsconfig.json +5 -0
- package/templates/apps/api-rest/README.md +85 -0
- package/templates/apps/api-rest/app.config.ts +70 -0
- package/templates/apps/api-rest/database/schema.ts +52 -0
- package/templates/apps/api-rest/lib/product.ts +30 -0
- package/templates/apps/api-rest/package.json +27 -0
- package/templates/apps/api-rest/routes/v1/products.create.route.tsx +45 -0
- package/templates/apps/api-rest/routes/v1/products.delete.route.tsx +25 -0
- package/templates/apps/api-rest/routes/v1/products.get.route.tsx +29 -0
- package/templates/apps/api-rest/routes/v1/products.list.route.tsx +43 -0
- package/templates/apps/api-rest/template.json +6 -0
- package/templates/apps/api-rest/tests/products.create.test.ts +53 -0
- package/templates/apps/api-rest/tsconfig.json +5 -0
- package/templates/apps/api-saas/README.md +106 -0
- package/templates/apps/api-saas/app.config.ts +51 -0
- package/templates/apps/api-saas/database/schema.ts +50 -0
- package/templates/apps/api-saas/mutations/projects.create.mutation.server.ts +52 -0
- package/templates/apps/api-saas/mutations/projects.create.mutation.ts +18 -0
- package/templates/apps/api-saas/package.json +31 -0
- package/templates/apps/api-saas/queries/projects.list.query.server.ts +7 -0
- package/templates/apps/api-saas/queries/projects.list.query.ts +18 -0
- package/templates/apps/api-saas/template.json +6 -0
- package/templates/apps/api-saas/tests/projects.create.test.ts +47 -0
- package/templates/apps/api-saas/tsconfig.json +5 -0
- package/templates/apps/api-search/README.md +68 -0
- package/templates/apps/api-search/app.config.ts +31 -0
- package/templates/apps/api-search/database/schema.ts +47 -0
- package/templates/apps/api-search/lib/search.ts +27 -0
- package/templates/apps/api-search/mutations/articles.create.mutation.server.ts +19 -0
- package/templates/apps/api-search/mutations/articles.create.mutation.ts +35 -0
- package/templates/apps/api-search/package.json +29 -0
- package/templates/apps/api-search/queries/articles.list.query.server.ts +14 -0
- package/templates/apps/api-search/queries/articles.list.query.ts +19 -0
- package/templates/apps/api-search/seeds/articles.seed.ts +41 -0
- package/templates/apps/api-search/startup/searchBackfill.startup.tsx +24 -0
- package/templates/apps/api-search/template.json +6 -0
- package/templates/apps/api-search/tests/articles.create.test.ts +69 -0
- package/templates/apps/api-search/tsconfig.json +5 -0
- package/templates/apps/api-versioning/README.md +51 -0
- package/templates/apps/api-versioning/actions/documents.asOf.action.server.ts +13 -0
- package/templates/apps/api-versioning/actions/documents.asOf.action.ts +14 -0
- package/templates/apps/api-versioning/actions/documents.history.action.server.ts +15 -0
- package/templates/apps/api-versioning/actions/documents.history.action.ts +17 -0
- package/templates/apps/api-versioning/app.config.ts +24 -0
- package/templates/apps/api-versioning/database/schema.ts +38 -0
- package/templates/apps/api-versioning/mutations/documents.create.mutation.server.ts +8 -0
- package/templates/apps/api-versioning/mutations/documents.create.mutation.ts +21 -0
- package/templates/apps/api-versioning/mutations/documents.update.mutation.server.ts +9 -0
- package/templates/apps/api-versioning/mutations/documents.update.mutation.ts +21 -0
- package/templates/apps/api-versioning/package.json +29 -0
- package/templates/apps/api-versioning/template.json +6 -0
- package/templates/apps/api-versioning/tests/documents.create.test.ts +37 -0
- package/templates/apps/api-versioning/tsconfig.json +5 -0
- package/templates/apps/api-webhooks/.env +6 -0
- package/templates/apps/api-webhooks/README.md +106 -0
- package/templates/apps/api-webhooks/app.config.ts +16 -0
- package/templates/apps/api-webhooks/database/schema.ts +49 -0
- package/templates/apps/api-webhooks/events/order.completed.webhook.tsx +22 -0
- package/templates/apps/api-webhooks/mutations/orders.fulfill.mutation.server.ts +37 -0
- package/templates/apps/api-webhooks/mutations/orders.fulfill.mutation.ts +15 -0
- package/templates/apps/api-webhooks/package.json +28 -0
- package/templates/apps/api-webhooks/queries/orders.list.query.server.ts +7 -0
- package/templates/apps/api-webhooks/queries/orders.list.query.ts +15 -0
- package/templates/apps/api-webhooks/template.json +6 -0
- package/templates/apps/api-webhooks/tests/orders.fulfill.test.ts +51 -0
- package/templates/apps/api-webhooks/tsconfig.json +5 -0
- package/templates/apps/api-webhooks/webhooks/orders.webhook.tsx +35 -0
- package/templates/apps/changelog/README.md +77 -0
- package/templates/apps/changelog/app.config.ts +27 -0
- package/templates/apps/changelog/content/releases/0.1.0.mdx +19 -0
- package/templates/apps/changelog/content/releases/0.2.0.mdx +28 -0
- package/templates/apps/changelog/package.json +30 -0
- package/templates/apps/changelog/scripts/generate-rss.mjs +38 -0
- package/templates/apps/changelog/src/globals.css +66 -0
- package/templates/apps/changelog/src/globals.d.ts +16 -0
- package/templates/apps/changelog/src/lib/locale.test.ts +72 -0
- package/templates/apps/changelog/src/lib/locale.ts +55 -0
- package/templates/apps/changelog/src/lib/releases.ts +21 -0
- package/templates/apps/changelog/src/locales/de.ts +22 -0
- package/templates/apps/changelog/src/locales/en.ts +30 -0
- package/templates/apps/changelog/src/pages/[locale]/[slug].tsx +24 -0
- package/templates/apps/changelog/src/pages/[locale]/index.tsx +13 -0
- package/templates/apps/changelog/src/pages/[locale]/mirrors.test.tsx +95 -0
- package/templates/apps/changelog/src/pages/[slug].test.tsx +127 -0
- package/templates/apps/changelog/src/pages/[slug].tsx +52 -0
- package/templates/apps/changelog/src/pages/index.test.tsx +112 -0
- package/templates/apps/changelog/src/pages/index.tsx +55 -0
- package/templates/apps/changelog/src/pages/layout.tsx +84 -0
- package/templates/apps/changelog/template.json +6 -0
- package/templates/apps/changelog/tsconfig.json +11 -0
- package/templates/apps/edge-functions/README.md +55 -0
- package/templates/apps/edge-functions/functions/aiComplete.serverless.ts +58 -0
- package/templates/apps/edge-functions/functions/currencyConvert.serverless.ts +47 -0
- package/templates/apps/edge-functions/functions/geoGreeting.serverless.ts +44 -0
- package/templates/apps/edge-functions/functions/health.serverless.ts +29 -0
- package/templates/apps/edge-functions/functions/resolveLink.serverless.ts +32 -0
- package/templates/apps/edge-functions/functions/shareLink.serverless.ts +30 -0
- package/templates/apps/edge-functions/functions/slackNotify.serverless.ts +40 -0
- package/templates/apps/edge-functions/functions/verifySignature.serverless.ts +52 -0
- package/templates/apps/edge-functions/package.json +21 -0
- package/templates/apps/edge-functions/template.json +6 -0
- package/templates/apps/edge-functions/tsconfig.json +10 -0
- package/templates/apps/frontend-admin/README.md +40 -0
- package/templates/apps/frontend-admin/app.config.ts +37 -0
- package/templates/apps/frontend-admin/package.json +30 -0
- package/templates/apps/frontend-admin/src/config.ts +8 -0
- package/templates/apps/frontend-admin/src/globals.css +76 -0
- package/templates/apps/frontend-admin/src/globals.d.ts +6 -0
- package/templates/apps/frontend-admin/src/lib/admin.ts +16 -0
- package/templates/apps/frontend-admin/src/lib/auth.ts +24 -0
- package/templates/apps/frontend-admin/src/locales/de.ts +67 -0
- package/templates/apps/frontend-admin/src/locales/en.ts +79 -0
- package/templates/apps/frontend-admin/src/locales/index.ts +15 -0
- package/templates/apps/frontend-admin/src/pages/(marketing)/index.test.tsx +55 -0
- package/templates/apps/frontend-admin/src/pages/(marketing)/index.tsx +32 -0
- package/templates/apps/frontend-admin/src/pages/(marketing)/layout.tsx +29 -0
- package/templates/apps/frontend-admin/src/pages/(marketing)/login.test.tsx +73 -0
- package/templates/apps/frontend-admin/src/pages/(marketing)/login.tsx +35 -0
- package/templates/apps/frontend-admin/src/pages/admin/[entity].tsx +121 -0
- package/templates/apps/frontend-admin/src/pages/admin/entity.test.tsx +119 -0
- package/templates/apps/frontend-admin/src/pages/admin/error.tsx +20 -0
- package/templates/apps/frontend-admin/src/pages/admin/fallbacks.test.tsx +68 -0
- package/templates/apps/frontend-admin/src/pages/admin/index.test.tsx +88 -0
- package/templates/apps/frontend-admin/src/pages/admin/index.tsx +65 -0
- package/templates/apps/frontend-admin/src/pages/admin/layout.test.tsx +114 -0
- package/templates/apps/frontend-admin/src/pages/admin/layout.tsx +97 -0
- package/templates/apps/frontend-admin/src/pages/admin/loading.tsx +15 -0
- package/templates/apps/frontend-admin/src/pages/admin/not-found.tsx +15 -0
- package/templates/apps/frontend-admin/src/pages/layout.tsx +12 -0
- package/templates/apps/frontend-admin/src/pages/layouts.test.tsx +54 -0
- package/templates/apps/frontend-admin/template.json +6 -0
- package/templates/apps/frontend-admin/tsconfig.json +11 -0
- package/templates/apps/frontend-app/README.md +98 -0
- package/templates/apps/frontend-app/app.config.ts +43 -0
- package/templates/apps/frontend-app/package.json +30 -0
- package/templates/apps/frontend-app/src/locales/de.ts +36 -0
- package/templates/apps/frontend-app/src/locales/en.ts +43 -0
- package/templates/apps/frontend-app/src/locales/index.ts +15 -0
- package/templates/apps/frontend-app/src/pages/index.test.tsx +167 -0
- package/templates/apps/frontend-app/src/pages/index.tsx +136 -0
- package/templates/apps/frontend-app/src/pages/layout.tsx +41 -0
- package/templates/apps/frontend-app/src/pages/schema-ui.test.tsx +99 -0
- package/templates/apps/frontend-app/src/pages/schema-ui.tsx +74 -0
- package/templates/apps/frontend-app/template.json +6 -0
- package/templates/apps/frontend-app/tsconfig.json +11 -0
- package/templates/apps/frontend-blank/README.md +18 -0
- package/templates/apps/frontend-blank/app.config.ts +29 -0
- package/templates/apps/frontend-blank/package.json +29 -0
- package/templates/apps/frontend-blank/src/locales/de.ts +15 -0
- package/templates/apps/frontend-blank/src/locales/en.ts +22 -0
- package/templates/apps/frontend-blank/src/locales/index.ts +15 -0
- package/templates/apps/frontend-blank/src/pages/index.test.tsx +55 -0
- package/templates/apps/frontend-blank/src/pages/index.tsx +27 -0
- package/templates/apps/frontend-blank/src/pages/layout.test.tsx +54 -0
- package/templates/apps/frontend-blank/src/pages/layout.tsx +35 -0
- package/templates/apps/frontend-blank/template.json +6 -0
- package/templates/apps/frontend-blank/tsconfig.json +11 -0
- package/templates/apps/frontend-contact/README.md +65 -0
- package/templates/apps/frontend-contact/app.config.ts +25 -0
- package/templates/apps/frontend-contact/functions/sendMessage.serverless.ts +69 -0
- package/templates/apps/frontend-contact/package.json +33 -0
- package/templates/apps/frontend-contact/src/components/ContactForm.island.test.tsx +142 -0
- package/templates/apps/frontend-contact/src/components/ContactForm.island.tsx +104 -0
- package/templates/apps/frontend-contact/src/config.ts +12 -0
- package/templates/apps/frontend-contact/src/globals.css +84 -0
- package/templates/apps/frontend-contact/src/lib/locale.ts +55 -0
- package/templates/apps/frontend-contact/src/locales/de.ts +26 -0
- package/templates/apps/frontend-contact/src/locales/en.ts +29 -0
- package/templates/apps/frontend-contact/src/pages/[locale]/index.tsx +14 -0
- package/templates/apps/frontend-contact/src/pages/index.test.tsx +70 -0
- package/templates/apps/frontend-contact/src/pages/index.tsx +63 -0
- package/templates/apps/frontend-contact/src/pages/layout.tsx +65 -0
- package/templates/apps/frontend-contact/template.json +6 -0
- package/templates/apps/frontend-contact/tsconfig.json +11 -0
- package/templates/apps/frontend-dashboard/README.md +54 -0
- package/templates/apps/frontend-dashboard/app.config.ts +39 -0
- package/templates/apps/frontend-dashboard/package.json +29 -0
- package/templates/apps/frontend-dashboard/src/config.ts +8 -0
- package/templates/apps/frontend-dashboard/src/globals.css +72 -0
- package/templates/apps/frontend-dashboard/src/globals.d.ts +6 -0
- package/templates/apps/frontend-dashboard/src/lib/auth.ts +27 -0
- package/templates/apps/frontend-dashboard/src/locales/de.ts +49 -0
- package/templates/apps/frontend-dashboard/src/locales/en.ts +60 -0
- package/templates/apps/frontend-dashboard/src/locales/index.ts +15 -0
- package/templates/apps/frontend-dashboard/src/pages/(marketing)/index.test.tsx +55 -0
- package/templates/apps/frontend-dashboard/src/pages/(marketing)/index.tsx +34 -0
- package/templates/apps/frontend-dashboard/src/pages/(marketing)/layout.tsx +32 -0
- package/templates/apps/frontend-dashboard/src/pages/(marketing)/login.test.tsx +74 -0
- package/templates/apps/frontend-dashboard/src/pages/(marketing)/login.tsx +40 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/error.tsx +21 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/fallbacks.test.tsx +68 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/index.test.tsx +55 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/index.tsx +38 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/layout.test.tsx +88 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/layout.tsx +69 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/loading.tsx +21 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/not-found.tsx +19 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/settings.test.tsx +69 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/settings.tsx +35 -0
- package/templates/apps/frontend-dashboard/src/pages/layout.tsx +12 -0
- package/templates/apps/frontend-dashboard/src/pages/layouts.test.tsx +54 -0
- package/templates/apps/frontend-dashboard/template.json +6 -0
- package/templates/apps/frontend-dashboard/tsconfig.json +11 -0
- package/templates/apps/frontend-docs/README.md +19 -0
- package/templates/apps/frontend-docs/app.config.ts +25 -0
- package/templates/apps/frontend-docs/package.json +29 -0
- package/templates/apps/frontend-docs/src/globals.css +32 -0
- package/templates/apps/frontend-docs/src/lib/locale.test.ts +72 -0
- package/templates/apps/frontend-docs/src/lib/locale.ts +56 -0
- package/templates/apps/frontend-docs/src/locales/de.ts +24 -0
- package/templates/apps/frontend-docs/src/locales/en.ts +28 -0
- package/templates/apps/frontend-docs/src/pages/[locale]/docs/[...slug].tsx +18 -0
- package/templates/apps/frontend-docs/src/pages/[locale]/index.tsx +13 -0
- package/templates/apps/frontend-docs/src/pages/[locale]/mirrors.test.tsx +67 -0
- package/templates/apps/frontend-docs/src/pages/docs/[...slug].test.tsx +115 -0
- package/templates/apps/frontend-docs/src/pages/docs/[...slug].tsx +82 -0
- package/templates/apps/frontend-docs/src/pages/index.test.tsx +90 -0
- package/templates/apps/frontend-docs/src/pages/index.tsx +45 -0
- package/templates/apps/frontend-docs/src/pages/layout.test.tsx +84 -0
- package/templates/apps/frontend-docs/src/pages/layout.tsx +66 -0
- package/templates/apps/frontend-docs/template.json +6 -0
- package/templates/apps/frontend-docs/tsconfig.json +11 -0
- package/templates/apps/frontend-i18n/README.md +61 -0
- package/templates/apps/frontend-i18n/app.config.ts +33 -0
- package/templates/apps/frontend-i18n/package.json +28 -0
- package/templates/apps/frontend-i18n/src/globals.css +46 -0
- package/templates/apps/frontend-i18n/src/globals.d.ts +6 -0
- package/templates/apps/frontend-i18n/src/lib/locale.test.ts +72 -0
- package/templates/apps/frontend-i18n/src/lib/locale.ts +55 -0
- package/templates/apps/frontend-i18n/src/locales/de.ts +24 -0
- package/templates/apps/frontend-i18n/src/locales/en.ts +25 -0
- package/templates/apps/frontend-i18n/src/pages/[locale]/about.tsx +11 -0
- package/templates/apps/frontend-i18n/src/pages/[locale]/index.tsx +13 -0
- package/templates/apps/frontend-i18n/src/pages/[locale]/mirrors.test.tsx +50 -0
- package/templates/apps/frontend-i18n/src/pages/about.test.tsx +75 -0
- package/templates/apps/frontend-i18n/src/pages/about.tsx +31 -0
- package/templates/apps/frontend-i18n/src/pages/index.test.tsx +102 -0
- package/templates/apps/frontend-i18n/src/pages/index.tsx +43 -0
- package/templates/apps/frontend-i18n/src/pages/layout.test.tsx +86 -0
- package/templates/apps/frontend-i18n/src/pages/layout.tsx +70 -0
- package/templates/apps/frontend-i18n/template.json +6 -0
- package/templates/apps/frontend-i18n/tsconfig.json +11 -0
- package/templates/apps/frontend-landing/README.md +17 -0
- package/templates/apps/frontend-landing/app.config.ts +25 -0
- package/templates/apps/frontend-landing/package.json +29 -0
- package/templates/apps/frontend-landing/src/globals.css +23 -0
- package/templates/apps/frontend-landing/src/lib/locale.test.ts +72 -0
- package/templates/apps/frontend-landing/src/lib/locale.ts +55 -0
- package/templates/apps/frontend-landing/src/locales/de.ts +24 -0
- package/templates/apps/frontend-landing/src/locales/en.ts +26 -0
- package/templates/apps/frontend-landing/src/pages/[locale]/index.tsx +13 -0
- package/templates/apps/frontend-landing/src/pages/[locale]/mirrors.test.tsx +37 -0
- package/templates/apps/frontend-landing/src/pages/index.test.tsx +110 -0
- package/templates/apps/frontend-landing/src/pages/index.tsx +75 -0
- package/templates/apps/frontend-landing/src/pages/layout.test.tsx +84 -0
- package/templates/apps/frontend-landing/src/pages/layout.tsx +66 -0
- package/templates/apps/frontend-landing/template.json +6 -0
- package/templates/apps/frontend-landing/tsconfig.json +11 -0
- package/templates/apps/frontend-spa/README.md +45 -0
- package/templates/apps/frontend-spa/app.config.ts +27 -0
- package/templates/apps/frontend-spa/package.json +29 -0
- package/templates/apps/frontend-spa/src/globals.css +84 -0
- package/templates/apps/frontend-spa/src/locales/de.ts +22 -0
- package/templates/apps/frontend-spa/src/locales/en.ts +29 -0
- package/templates/apps/frontend-spa/src/locales/index.ts +15 -0
- package/templates/apps/frontend-spa/src/pages/index.test.tsx +137 -0
- package/templates/apps/frontend-spa/src/pages/index.tsx +123 -0
- package/templates/apps/frontend-spa/src/pages/layout.tsx +27 -0
- package/templates/apps/frontend-spa/template.json +6 -0
- package/templates/apps/frontend-spa/tsconfig.json +11 -0
- package/templates/apps/frontend-ssr/README.md +68 -0
- package/templates/apps/frontend-ssr/app.config.ts +32 -0
- package/templates/apps/frontend-ssr/package.json +29 -0
- package/templates/apps/frontend-ssr/src/globals.css +67 -0
- package/templates/apps/frontend-ssr/src/locales/de.ts +41 -0
- package/templates/apps/frontend-ssr/src/locales/en.ts +54 -0
- package/templates/apps/frontend-ssr/src/locales/index.ts +16 -0
- package/templates/apps/frontend-ssr/src/pages/feed-swr.test.tsx +69 -0
- package/templates/apps/frontend-ssr/src/pages/feed-swr.tsx +54 -0
- package/templates/apps/frontend-ssr/src/pages/feed.test.tsx +73 -0
- package/templates/apps/frontend-ssr/src/pages/feed.tsx +64 -0
- package/templates/apps/frontend-ssr/src/pages/index.test.tsx +89 -0
- package/templates/apps/frontend-ssr/src/pages/index.tsx +72 -0
- package/templates/apps/frontend-ssr/src/pages/layout.tsx +37 -0
- package/templates/apps/frontend-ssr/template.json +6 -0
- package/templates/apps/frontend-ssr/tsconfig.json +11 -0
- package/templates/apps/frontend-ssr-api/README.md +50 -0
- package/templates/apps/frontend-ssr-api/app.config.ts +43 -0
- package/templates/apps/frontend-ssr-api/package.json +30 -0
- package/templates/apps/frontend-ssr-api/src/globals.css +38 -0
- package/templates/apps/frontend-ssr-api/src/globals.d.ts +6 -0
- package/templates/apps/frontend-ssr-api/src/locales/de.ts +20 -0
- package/templates/apps/frontend-ssr-api/src/locales/en.ts +31 -0
- package/templates/apps/frontend-ssr-api/src/locales/index.ts +16 -0
- package/templates/apps/frontend-ssr-api/src/pages/index.test.tsx +105 -0
- package/templates/apps/frontend-ssr-api/src/pages/index.tsx +83 -0
- package/templates/apps/frontend-ssr-api/src/pages/layout.tsx +28 -0
- package/templates/apps/frontend-ssr-api/template.json +6 -0
- package/templates/apps/frontend-ssr-api/tsconfig.json +11 -0
- package/templates/apps/frontend-static-blog/README.md +49 -0
- package/templates/apps/frontend-static-blog/app.config.ts +34 -0
- package/templates/apps/frontend-static-blog/package.json +28 -0
- package/templates/apps/frontend-static-blog/src/components/ReadingProgress.island.test.tsx +65 -0
- package/templates/apps/frontend-static-blog/src/components/ReadingProgress.island.tsx +35 -0
- package/templates/apps/frontend-static-blog/src/content/posts.ts +64 -0
- package/templates/apps/frontend-static-blog/src/globals.css +75 -0
- package/templates/apps/frontend-static-blog/src/lib/locale.test.ts +72 -0
- package/templates/apps/frontend-static-blog/src/lib/locale.ts +55 -0
- package/templates/apps/frontend-static-blog/src/locales/de.ts +19 -0
- package/templates/apps/frontend-static-blog/src/locales/en.ts +26 -0
- package/templates/apps/frontend-static-blog/src/pages/[locale]/blog/[slug].tsx +20 -0
- package/templates/apps/frontend-static-blog/src/pages/[locale]/index.tsx +13 -0
- package/templates/apps/frontend-static-blog/src/pages/[locale]/mirrors.test.tsx +62 -0
- package/templates/apps/frontend-static-blog/src/pages/blog/[slug].test.tsx +116 -0
- package/templates/apps/frontend-static-blog/src/pages/blog/[slug].tsx +69 -0
- package/templates/apps/frontend-static-blog/src/pages/index.test.tsx +100 -0
- package/templates/apps/frontend-static-blog/src/pages/index.tsx +58 -0
- package/templates/apps/frontend-static-blog/src/pages/layout.tsx +63 -0
- package/templates/apps/frontend-static-blog/template.json +6 -0
- package/templates/apps/frontend-static-blog/tsconfig.json +11 -0
- package/templates/baselines/bare/.env.example +37 -0
- package/templates/baselines/bare/README.md +47 -0
- package/templates/baselines/bare/baseline.json +31 -0
- package/templates/baselines/bare/deploy/README.md +43 -0
- package/templates/baselines/bare/deploy/voltro.service.example +36 -0
- package/templates/baselines/compose/.env.example +46 -0
- package/templates/baselines/compose/README.md +69 -0
- package/templates/baselines/compose/baseline.json +51 -0
- package/templates/baselines/compose/docker/.dockerignore +38 -0
- package/templates/baselines/compose/docker/api.Dockerfile +57 -0
- package/templates/baselines/compose/docker/dev.Dockerfile +35 -0
- package/templates/baselines/compose/docker/web.Dockerfile +59 -0
- package/templates/baselines/compose/docker-compose.dev.yml +89 -0
- package/templates/baselines/compose/docker-compose.prod.yml +87 -0
- package/templates/baselines/compose/docker-compose.yml +41 -0
- package/templates/baselines/compose-mariadb/.env.example +57 -0
- package/templates/baselines/compose-mariadb/README.md +78 -0
- package/templates/baselines/compose-mariadb/baseline.json +51 -0
- package/templates/baselines/compose-mariadb/docker/.dockerignore +38 -0
- package/templates/baselines/compose-mariadb/docker/api.Dockerfile +57 -0
- package/templates/baselines/compose-mariadb/docker/dev.Dockerfile +35 -0
- package/templates/baselines/compose-mariadb/docker/mariadb-init.sql +6 -0
- package/templates/baselines/compose-mariadb/docker/web.Dockerfile +59 -0
- package/templates/baselines/compose-mariadb/docker-compose.dev.yml +117 -0
- package/templates/baselines/compose-mariadb/docker-compose.prod.yml +114 -0
- package/templates/baselines/compose-mariadb/docker-compose.yml +79 -0
- package/templates/baselines/helm/.env.example +39 -0
- package/templates/baselines/helm/README.md +98 -0
- package/templates/baselines/helm/baseline.json +53 -0
- package/templates/baselines/helm/charts/voltro-app/.helmignore +10 -0
- package/templates/baselines/helm/charts/voltro-app/Chart.yaml +10 -0
- package/templates/baselines/helm/charts/voltro-app/templates/_helpers.tpl +36 -0
- package/templates/baselines/helm/charts/voltro-app/templates/configmap.yaml +13 -0
- package/templates/baselines/helm/charts/voltro-app/templates/deployment-api.yaml +120 -0
- package/templates/baselines/helm/charts/voltro-app/templates/deployment-web.yaml +45 -0
- package/templates/baselines/helm/charts/voltro-app/templates/ingress.yaml +37 -0
- package/templates/baselines/helm/charts/voltro-app/templates/postgres-service.yaml +19 -0
- package/templates/baselines/helm/charts/voltro-app/templates/postgres-statefulset.yaml +73 -0
- package/templates/baselines/helm/charts/voltro-app/templates/secret.yaml +33 -0
- package/templates/baselines/helm/charts/voltro-app/templates/service-api.yaml +19 -0
- package/templates/baselines/helm/charts/voltro-app/templates/service-web.yaml +19 -0
- package/templates/baselines/helm/charts/voltro-app/values-dev.yaml +21 -0
- package/templates/baselines/helm/charts/voltro-app/values-prod.yaml +58 -0
- package/templates/baselines/helm/charts/voltro-app/values-staging.yaml +25 -0
- package/templates/baselines/helm/charts/voltro-app/values.yaml +109 -0
- package/templates/baselines/helm/deploy/README.md +94 -0
- package/templates/patches/@effect__cluster@0.59.0.patch +262 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# Database
|
|
2
|
+
|
|
3
|
+
> Spin up an isolated branch of a tenant's data — a namespace snapshot/restore by default (dialect-agnostic, no vendor lock) or a Neon copy-on-write fast-path on Postgres — then bind to it and tear it down. The basis for per-PR preview environments.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<!-- source: en/database/branching.md -->
|
|
10
|
+
## Data branching
|
|
11
|
+
|
|
12
|
+
_Spin up an isolated branch of a tenant's data — a namespace snapshot/restore by default (dialect-agnostic, no vendor lock) or a Neon copy-on-write fast-path on Postgres — then bind to it and tear it down. The basis for per-PR preview environments._
|
|
13
|
+
|
|
14
|
+
Data branching creates an **isolated copy of a tenant's data** you can read and
|
|
15
|
+
write without touching the source — the basis for per-PR preview environments and
|
|
16
|
+
safe "try a migration against real-shaped data" workflows. The default mechanism
|
|
17
|
+
is a **namespace snapshot/restore** (works on every dialect, no vendor lock); on
|
|
18
|
+
Postgres backed by Neon, a **copy-on-write branch** fast-path is used instead.
|
|
19
|
+
|
|
20
|
+
## The plan/execute split
|
|
21
|
+
|
|
22
|
+
Branching is a **plan** (what to do) + an **executor** (do it), mirroring the
|
|
23
|
+
migration engine. The plan is pure + inspectable; the executor performs the I/O.
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { planBranch, resolveBranchMechanism } from '@voltro/database'
|
|
27
|
+
|
|
28
|
+
// Pick the mechanism: 'neon-cow' when seeding a copy on a Neon URL,
|
|
29
|
+
// 'namespace' (schema-per-branch) otherwise.
|
|
30
|
+
const mechanism = resolveBranchMechanism({ seed: 'copy', dbUrl: connectionString })
|
|
31
|
+
const steps = planBranch({
|
|
32
|
+
mechanism,
|
|
33
|
+
branchId: 'branch_acme_pr128',
|
|
34
|
+
tableNames,
|
|
35
|
+
seed: 'copy',
|
|
36
|
+
parentNamespace: 'public', // namespace mechanism: the schema to snapshot from
|
|
37
|
+
})
|
|
38
|
+
// steps: e.g. [{ kind: 'neon-branch-create', … }] or per-table namespace snapshot steps
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Provision + tear down
|
|
42
|
+
|
|
43
|
+
`provisionBranch` / `teardownBranch` run a plan through an injected
|
|
44
|
+
`BranchExecutor` (the dialect/Neon adapter). Injected so the lifecycle is
|
|
45
|
+
unit-testable with a recording executor — no live DB:
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { provisionBranch, teardownBranch } from '@voltro/database'
|
|
49
|
+
|
|
50
|
+
const result = await provisionBranch(
|
|
51
|
+
{ appSlug: 'acme', prNumber: 128, seed: 'copy', tableNames, dbUrl: connectionString },
|
|
52
|
+
executor,
|
|
53
|
+
)
|
|
54
|
+
// result: { branchId, mechanism, steps, … } — for 'neon-cow' also the
|
|
55
|
+
// branch's own connection string to bind the preview store to.
|
|
56
|
+
|
|
57
|
+
// …run the preview against result, then:
|
|
58
|
+
await teardownBranch(result.branchId, result.mechanism, executor)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`admitBranch` gates whether a branch may be served (e.g. it exists + is ready)
|
|
62
|
+
so a request never binds to a half-provisioned branch.
|
|
63
|
+
|
|
64
|
+
## Mechanisms
|
|
65
|
+
|
|
66
|
+
| mechanism | when | how |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| `namespace-snapshot` | any dialect (default) | snapshot the tenant's namespace → restore into a new branch namespace |
|
|
69
|
+
| `neon-branch` | Postgres on Neon | a copy-on-write Neon branch (instant, storage-shared) |
|
|
70
|
+
|
|
71
|
+
The mechanism is resolved from the connection, so the same `planBranch` call
|
|
72
|
+
produces the right steps for the deployment's database — dialect-agnostic by
|
|
73
|
+
default, with the Neon fast-path when it's available. No code path is locked to a
|
|
74
|
+
vendor.
|
|
75
|
+
|
|
76
|
+
> Branching copies **data**, not the schema definition — apply migrations to a
|
|
77
|
+
> branch the same way you would to any store. Teardown is explicit; a branch
|
|
78
|
+
> left bound holds its namespace/Neon branch until torn down.
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
<!-- source: en/database/sensitivity.md -->
|
|
85
|
+
## Data classification (.sensitive / .safe)
|
|
86
|
+
|
|
87
|
+
_Classify columns as .sensitive(class) or .safe() so the export masker can replace PII with realistic, referentially-consistent fakes at the source. Fail-closed — an unclassified column blocks a masking export._
|
|
88
|
+
|
|
89
|
+
Two column modifiers that carry **data-sensitivity metadata** into the
|
|
90
|
+
schema — nothing at runtime, nothing in the DDL. They exist for one job:
|
|
91
|
+
letting `voltro data export --profile dev` replace personal data with
|
|
92
|
+
realistic, referentially-consistent fakes at the **source**, so a copy of
|
|
93
|
+
prod that lands in dev/stage never contains real user data.
|
|
94
|
+
|
|
95
|
+
- **`.sensitive(class)`** — this column holds personal/sensitive data of a
|
|
96
|
+
known CLASS (`email`, `phone`, `secret`, …). The class picks a
|
|
97
|
+
format-preserving fake.
|
|
98
|
+
- **`.safe()`** — this column was reviewed and holds NO PII; copy it verbatim.
|
|
99
|
+
|
|
100
|
+
They pair: under a masking profile every exported column must be **one or the
|
|
101
|
+
other** (or the primary key / a foreign key, which are implicitly safe), or the
|
|
102
|
+
export **refuses**. That is the whole point — see [why fail-closed](#why-fail-closed).
|
|
103
|
+
|
|
104
|
+
## `.sensitive(class)` — mark a column as PII
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import { id, text, table } from '@voltro/database'
|
|
108
|
+
|
|
109
|
+
export const users = table('users', {
|
|
110
|
+
id: id(),
|
|
111
|
+
email: text().sensitive('email'),
|
|
112
|
+
name: text().sensitive('fullName'),
|
|
113
|
+
})
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**What it does:** nothing at runtime and nothing in the emitted DDL. It is
|
|
117
|
+
pure metadata — the export masker reads it (from the DECLARED schema) and picks
|
|
118
|
+
a format-preserving fake for the column.
|
|
119
|
+
|
|
120
|
+
**Why you use it:** lower environments must never contain real user data — for
|
|
121
|
+
GDPR, for least privilege, and to shrink the blast radius of a leaked dev dump.
|
|
122
|
+
Classifying the PII columns lets the framework substitute realistic,
|
|
123
|
+
referentially-consistent fakes **automatically at the source**, so real values
|
|
124
|
+
never reach the bundle, transit, or a developer's machine.
|
|
125
|
+
|
|
126
|
+
### Known classes
|
|
127
|
+
|
|
128
|
+
Each known class maps to a format-preserving fake (a fake email is a valid
|
|
129
|
+
email, a fake phone looks like a phone). The class is also what a
|
|
130
|
+
[masking policy](/docs/cli/data#masking-prod-dev-stage-safely) keys its
|
|
131
|
+
per-class overrides on.
|
|
132
|
+
|
|
133
|
+
| Class | Fake |
|
|
134
|
+
|---|---|
|
|
135
|
+
| `email` | valid-looking address (`ada.lovelace4823@example.com`) |
|
|
136
|
+
| `fullName` | `First Last` |
|
|
137
|
+
| `firstName` | a first name |
|
|
138
|
+
| `lastName` | a last name |
|
|
139
|
+
| `username` | a handle |
|
|
140
|
+
| `phone` | a phone number |
|
|
141
|
+
| `address` | a street address |
|
|
142
|
+
| `company` | a company name |
|
|
143
|
+
| `url` | a URL |
|
|
144
|
+
| `ip` | an IPv4 address |
|
|
145
|
+
| `creditCard` | a Luhn-valid 16-digit number |
|
|
146
|
+
| `date` | date-shifted (see below) |
|
|
147
|
+
| `secret` | nulled |
|
|
148
|
+
| `freeText` | redacted to `[redacted]` |
|
|
149
|
+
|
|
150
|
+
`date`, `secret`, and `freeText` are the non-`fake` defaults: `date` shifts by a
|
|
151
|
+
seed-derived offset (relative intervals and ordering survive), `secret` is set
|
|
152
|
+
to `null`, `freeText` becomes `[redacted]`. Every default is overridable per
|
|
153
|
+
class or per column in the [masking policy](/docs/cli/data#masking-prod-dev-stage-safely).
|
|
154
|
+
|
|
155
|
+
**Custom classes.** The known set is only what gives editor autocomplete — any
|
|
156
|
+
string is accepted. Use a custom class (e.g. `.sensitive('iban')`) and give it a
|
|
157
|
+
transform in the policy's `classes` (an unmapped custom class falls back to
|
|
158
|
+
`redact`).
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
account: text().sensitive('iban'), // give 'iban' an action in the policy's `classes`
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## `.safe()` — mark a column reviewed-safe
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import { id, integer, text, table } from '@voltro/database'
|
|
168
|
+
|
|
169
|
+
export const posts = table('posts', {
|
|
170
|
+
id: id(),
|
|
171
|
+
title: text().safe(), // public — copy verbatim
|
|
172
|
+
status: text().oneOf(['draft', 'live']).safe(),
|
|
173
|
+
views: integer().safe(),
|
|
174
|
+
})
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**What it does:** metadata only — it copies verbatim under a masking profile.
|
|
178
|
+
|
|
179
|
+
**Why it exists:** masking is **fail-closed**. Under a masking profile a column
|
|
180
|
+
that is neither `.sensitive()` nor `.safe()` **blocks the export** until it is
|
|
181
|
+
consciously classified — so adding a column later can never silently leak PII to
|
|
182
|
+
dev. `.safe()` is the explicit *"I looked, it's fine"* acknowledgement (a public
|
|
183
|
+
title, a status enum, a counter).
|
|
184
|
+
|
|
185
|
+
## Primary keys and foreign keys are implicitly safe
|
|
186
|
+
|
|
187
|
+
You do **not** annotate every id. `id()` (a primary key) and `reference()` (a
|
|
188
|
+
foreign key) columns are opaque identifiers — keeping them verbatim is exactly
|
|
189
|
+
what makes joins survive the copy — so they are treated as **safe by default**
|
|
190
|
+
under a masking profile. No `.safe()` needed.
|
|
191
|
+
|
|
192
|
+
An explicit `.sensitive()` still overrides this for the rare case where the key
|
|
193
|
+
itself is PII (a natural key like an email-as-id):
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
// A table keyed by a natural PII value — classify it explicitly.
|
|
197
|
+
subscription: table('subscription', {
|
|
198
|
+
email: text().sensitive('email'), // this IS the PK, and it IS PII → fake it
|
|
199
|
+
plan: text().safe(),
|
|
200
|
+
})
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Interaction with `.encrypted()`
|
|
204
|
+
|
|
205
|
+
This is the subtle trap. [`.encrypted()`](/docs/database/columns) protects data
|
|
206
|
+
**at rest** (the stored value is opaque ciphertext), but the runtime
|
|
207
|
+
**decrypts on read** — so by the time the export streams the row, the column is
|
|
208
|
+
back to **plaintext**. Encryption at rest gives you *nothing* at export time.
|
|
209
|
+
|
|
210
|
+
The framework therefore treats an `.encrypted()` column as
|
|
211
|
+
**`.sensitive('secret')` automatically** (so it is nulled under a masking
|
|
212
|
+
profile) — unless you classify it otherwise:
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
ssn: text().encrypted(), // ⇒ implicitly sensitive('secret') → nulled on export
|
|
216
|
+
phone: text().encrypted().sensitive('phone'), // explicit class wins → fake phone instead of null
|
|
217
|
+
review: text().encrypted().safe(), // encrypted at rest, but reviewed-safe → copied verbatim
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Precedence, exactly:
|
|
221
|
+
|
|
222
|
+
1. An explicit **`.sensitive(class)`** wins — the column is faked by that class.
|
|
223
|
+
2. Otherwise **`.encrypted()`** (without `.safe()`) implies `sensitive('secret')`
|
|
224
|
+
→ the column is nulled.
|
|
225
|
+
3. **`.safe()`** on an encrypted column suppresses the implied secret and copies
|
|
226
|
+
it verbatim — say this only when you have genuinely reviewed the plaintext.
|
|
227
|
+
|
|
228
|
+
## Worked example
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
import { id, text, table } from '@voltro/database'
|
|
232
|
+
|
|
233
|
+
export const users = table('users', {
|
|
234
|
+
id: id(), // PK → implicitly safe
|
|
235
|
+
email: text().sensitive('email'), // → fake email
|
|
236
|
+
name: text().sensitive('fullName'), // → fake name
|
|
237
|
+
ssn: text().encrypted(), // → implicitly sensitive('secret') → nulled
|
|
238
|
+
status: text().oneOf(['active', 'banned']).safe(), // reviewed → copied verbatim
|
|
239
|
+
bio: text(), // UNCLASSIFIED → blocks a masking export
|
|
240
|
+
})
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Under a masking profile this table exports fine **except** `bio`: it is neither
|
|
244
|
+
`.sensitive()` nor `.safe()`, so the export refuses and names it. Classify it
|
|
245
|
+
(`.sensitive('freeText')` if it may contain PII, `.safe()` if it can't) — or
|
|
246
|
+
override it in the policy's `columns` — and the export proceeds.
|
|
247
|
+
|
|
248
|
+
Classification is invisible everywhere else: it does not change the column's SQL
|
|
249
|
+
type, its nullability, or any query. It is read **only** at export time.
|
|
250
|
+
|
|
251
|
+
## Why fail-closed
|
|
252
|
+
|
|
253
|
+
Fail-**open** masking is worse than no masking. If a newly-added, unclassified
|
|
254
|
+
column were copied verbatim by default, the copy would *look* masked — giving
|
|
255
|
+
false confidence — while leaking real PII into dev on the very next schema
|
|
256
|
+
change. The failure is silent and the blast radius grows over time.
|
|
257
|
+
|
|
258
|
+
Fail-**closed** flips that: the export **stops** and names the unreviewed column,
|
|
259
|
+
forcing a conscious `.sensitive()` / `.safe()` decision before any data moves.
|
|
260
|
+
The cost is a one-line annotation per new column; the payoff is that a PII leak
|
|
261
|
+
to a lower environment can't happen by omission. Preview the exact set that
|
|
262
|
+
would block with [`--dry-run`](/docs/cli/data#dry-run-preview-without-writing)
|
|
263
|
+
before a real run.
|
|
264
|
+
|
|
265
|
+
## See also
|
|
266
|
+
|
|
267
|
+
- [`voltro data` — masking, profiles, subsetting](/docs/cli/data) — the
|
|
268
|
+
export command, the masking policy, `--dry-run`, and the audit manifest.
|
|
269
|
+
- [Column types](/docs/database/columns) — `.encrypted()` and the other
|
|
270
|
+
column modifiers.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Database
|
|
2
|
+
|
|
3
|
+
> How Voltro talks to Postgres — the schema DSL, the query builder, mixins, migrations, and the reactive engine's relationship to all of it.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<!-- source: en/database/overview.md -->
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
_How Voltro talks to Postgres — the schema DSL, the query builder, mixins, migrations, and the reactive engine's relationship to all of it._
|
|
13
|
+
|
|
14
|
+
Voltro's data layer is opinionated. One database (Postgres), one connection layer (`@effect/sql`), one schema DSL (built into the framework). No second ORM, no second query builder, no codegen step you have to remember to run.
|
|
15
|
+
|
|
16
|
+
This section covers everything about how the framework reads + writes data.
|
|
17
|
+
|
|
18
|
+
## The shape of it
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
┌───────────────────────────────────────────────────────────┐
|
|
22
|
+
│ Schema DSL (apps/api/database/*.entity.ts) │
|
|
23
|
+
│ table(...) + columns + mixins │
|
|
24
|
+
└────────────────┬──────────────────────────────────────────┘
|
|
25
|
+
│ voltro migrate
|
|
26
|
+
▼
|
|
27
|
+
┌───────────────────────────────────────────────────────────┐
|
|
28
|
+
│ Postgres │
|
|
29
|
+
└────────────────┬──────────────────────────────────────────┘
|
|
30
|
+
│
|
|
31
|
+
▼
|
|
32
|
+
┌───────────────────────────────────────────────────────────┐
|
|
33
|
+
│ Runtime data layer (ctx.store inside every executor) │
|
|
34
|
+
│ - select/insert/update/delete builders │
|
|
35
|
+
│ - dependency tracking for subscriptions │
|
|
36
|
+
│ - tenant-mixin AND-merging │
|
|
37
|
+
└───────────────────────────────────────────────────────────┘
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
You declare tables once. The migrator produces SQL; the runtime gives you a typed `ctx.store`; the reactive engine watches the same rows.
|
|
41
|
+
|
|
42
|
+
## A first table
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
// apps/api/database/notes.entity.ts
|
|
46
|
+
import {
|
|
47
|
+
table, id, text, integer, timestamp,
|
|
48
|
+
} from '@voltro/database'
|
|
49
|
+
import { tenant } from '@voltro/plugin-multitenancy'
|
|
50
|
+
|
|
51
|
+
export const notes = table('notes', {
|
|
52
|
+
id: id(),
|
|
53
|
+
title: text(),
|
|
54
|
+
body: text(),
|
|
55
|
+
views: integer().default(0),
|
|
56
|
+
createdAt: timestamp().default('now'),
|
|
57
|
+
updatedAt: timestamp().default('now').onUpdate('now'),
|
|
58
|
+
})
|
|
59
|
+
.with(tenant()) // adds tenantId + scoping — mixins chain via .with(), not spread
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
After `voltro migrate`:
|
|
63
|
+
|
|
64
|
+
- A `notes` table exists in Postgres with the columns above + tenant column from the mixin.
|
|
65
|
+
- A typed `ctx.store.select('notes')` etc. is available everywhere.
|
|
66
|
+
- Subscriptions reading `notes` get auto-scoped to the caller's tenant.
|
|
67
|
+
|
|
68
|
+
## What's in this section
|
|
69
|
+
|
|
70
|
+
### Schema basics
|
|
71
|
+
- [Column types](/docs/database/columns) — every column function, their SQL type, modifiers
|
|
72
|
+
- [Mixins](/docs/database/mixins) — `tenant()`, `audit()`, `softDelete()`, writing your own
|
|
73
|
+
- [Indexes](/docs/database/indexes) — single-column, composite, partial, expression, GiST, HNSW
|
|
74
|
+
- [Migrations](/docs/database/migrations) — the migration story end-to-end, including production
|
|
75
|
+
|
|
76
|
+
### Specialized columns
|
|
77
|
+
- [Enums (`dbEnum`)](/docs/database/enums) — postgres-native ENUM types
|
|
78
|
+
- [Generated columns](/docs/database/generated-columns) — DB-computed values
|
|
79
|
+
- [Arrays + intervals](/docs/database/arrays-intervals) — native postgres types + cross-dialect codec
|
|
80
|
+
- [JSON columns](/docs/database/json) — typed `jsonb`, indexing, paths
|
|
81
|
+
- [Vector columns](/docs/database/vectors) — pgvector, embedding, ANN search, HNSW
|
|
82
|
+
- [PostGIS](/docs/database/postgis) — geography/geometry for location-aware apps
|
|
83
|
+
- [Full-text search](/docs/database/full-text-search) — tsvector + GIN + `.matching()`
|
|
84
|
+
|
|
85
|
+
### Reading data
|
|
86
|
+
- [Query builder](/docs/database/query-builder) — `select`, `where`, aggregates, raw SQL escape hatch
|
|
87
|
+
- [Joins & relations](/docs/database/joins) — explicit joins, eager loading, the runtime's tracking
|
|
88
|
+
- [Aggregations](/docs/database/aggregations) — `count` / `sum` / `groupBy` / `having` + window functions
|
|
89
|
+
- [Sub-queries](/docs/database/sub-queries) — `inSubquery` / `exists` predicates
|
|
90
|
+
- [Set operations](/docs/database/set-operations) — `union` / `intersect` / `except`
|
|
91
|
+
- [DISTINCT + DISTINCT ON](/docs/database/distinct) — dedup + one-per-group
|
|
92
|
+
- [Self-joins](/docs/database/self-joins) — `.as(alias)` + `.innerJoin(table, alias, on)`
|
|
93
|
+
- [Recursive CTEs](/docs/database/recursive-cte) — `WITH RECURSIVE` for tree walks
|
|
94
|
+
- [SQL views](/docs/database/views) — `view(name, columns, select)` read-only named SELECTs
|
|
95
|
+
|
|
96
|
+
### Writing data
|
|
97
|
+
- [Transactions](/docs/database/transactions) — how `ctx.store` works inside mutations + workflows
|
|
98
|
+
- [Bulk operations](/docs/database/bulk-operations) — `updateMany` / `upsert` / `insertIgnore`
|
|
99
|
+
|
|
100
|
+
## Conventions enforced by the framework
|
|
101
|
+
|
|
102
|
+
| | Why |
|
|
103
|
+
|---|---|
|
|
104
|
+
| One table per `database/*.entity.ts` file + a `database/index.ts` barrel | Discovery walks `*.entity.ts` / `*.schema.ts` / `schema.ts`; the entity-per-file model is the primary convention. |
|
|
105
|
+
| All columns NOT NULL by default; `.nullable()` to opt in | Three-valued logic is the source of half of all SQL bugs. The default is the safer one. |
|
|
106
|
+
| `id` columns default to **TypeID** (`<prefix>_<ulid>`), not serial integers | Sortable by time, URL-safe, branded to the table type, no leaking sequential row counts. |
|
|
107
|
+
| Timestamps are `timestamptz` | Always UTC, never naive. The wire format is ISO 8601. |
|
|
108
|
+
| Mixins are chained via `.with(mixin())` | Keeps the table declaration readable + composable; the dep resolver dedups shared mixins. |
|