// Backend app for the {{projectName}} project. Read by `voltro dev`. // // This template demonstrates the framework's ADVANCED schema-DSL surface // on a small library/catalog domain (authors + books): // - the *.entity.ts / *.relations.ts split (one table per file), // - relations() + eager `.with({ books: true })` loading, // - full-text search via `.fullTextIndex(...)` + `.matching(...)`, // - `dbEnum(...)` native enum columns, // - `array(text())` columns + a stored `.generatedAs(...)` column, // - `.encrypted()` field encryption (AES-256-GCM at rest), // - declarative query result caching (`cache` on `defineQuery`). // // `store: 'memory'` keeps boot zero-infra (no docker). The schema DSL is // identical across every SQL backend — switch to `'postgres'` to see the // native ENUM / tsvector-FTS / text[] DDL the migrator emits. On `memory` // the same features run through the in-process store (FTS degrades to a // substring scan, arrays round-trip as JS arrays, encryption still applies). // // `governancePlugin({ fieldEncryption: true })` registers the AES-256-GCM // cipher that makes the `authors.bio` `.encrypted()` column work — without // it, boot fails loud ("an `.encrypted()` column exists but no cipher is // registered"). The key is read from the secret `VOLTRO_FIELD_ENCRYPTION_KEY` // via the Secrets-Resolver (which reads the process environment). The shipped // `.env` carries a DEV-ONLY key so the template boots out of the box — see the // README to generate a real one for production. Lose the key → lose the // ciphertext (GCM fails closed). import { defineEnv, envVar } from '@voltro/env' import { governancePlugin } from '@voltro/plugin-governance' // Typed environment — declare your env once; it's validated at boot (fail-fast) // and read on the server via `serverEnv` / `getSecret` from '@voltro/env/server'. // `access` is required: 'public' (browser-safe) or 'secret' (server-only, never // bundled). Run `voltro env` to see the manifest. See the Environment docs. export const env = defineEnv({ LOG_LEVEL: envVar.enum(['debug', 'info', 'warn', 'error'], { access: 'public', default: 'info' }), // The 32-byte hex key the field-encryption cipher uses. // // `generate: 'hex'` gives this project its OWN key: `voltro dev` mints one // into a gitignored `.env.local` on first boot, and no value ships with the // template. A shipped key would be published to everyone who downloads the // template — and unlike a session secret, that also means every // `.encrypted()` column in a deployment built from it is readable. // // Note it is minted into the ENVIRONMENT, not declared as a typed-env // `default`: governancePlugin resolves the key through the Secrets-Resolver // (which reads `process.env`), so a default would satisfy the boot gate // while the cipher still failed to resolve. // // Your DEPLOYMENT needs its own (`voltro secret generate field-encryption`). // Lose the key → lose the ciphertext (GCM fails closed, never silent // corruption). Rotating it makes existing `.encrypted()` values unreadable. VOLTRO_FIELD_ENCRYPTION_KEY: envVar.secret({ generate: 'hex', minLength: 64, description: 'AES-256 key (64 hex chars) for `.encrypted()` columns.', }), }) export default { type: 'api' as const, name: '{{capProjectName}}{{capAppName}}', store: 'memory' as const, env, plugins: [ // Registers the cipher for `.encrypted()` columns. Key from the secret // VOLTRO_FIELD_ENCRYPTION_KEY (or pass { fieldEncryption: { secretKey } }). governancePlugin({ fieldEncryption: true }), ], }