// Data-governance backend for the {{projectName}} project — field encryption, // GDPR export/erase, a consent ledger, and retention sweeps in one plugin. // // `@voltro/plugin-governance` does four things: // - fieldEncryption: registers the AES-256-GCM cipher for `.encrypted()` // columns (key from the secret VOLTRO_FIELD_ENCRYPTION_KEY). Handlers see // plaintext; the column stores an opaque `enc:v1:…` string at rest. // - GDPR: synthesizes admin-gated `governance.export` / `governance.erase` // that walk the declared `subjectScopes`. // - consent: `governance.consent` / `governance.hasConsent` + the service. // - retention: a periodic sweep that deletes/anonymises rows past their TTL. import { defineEnv, envVar } from '@voltro/env' import { governancePlugin } from '@voltro/plugin-governance' export const env = defineEnv({ LOG_LEVEL: envVar.enum(['debug', 'info', 'warn', 'error'], { access: 'public', default: 'info' }), // Declared so the boot gate can see it — governancePlugin reads the key // through the Secrets-Resolver (`process.env`), and an undeclared key would // fail at the first `.encrypted()` write instead of at boot. // // `generate: 'hex'` mints a project-local key into a gitignored `.env.local` // on first `voltro dev`, so nothing ships with the template. Your deployment // needs its own: `voltro secret generate field-encryption`. 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: [ governancePlugin({ // Key from the secret VOLTRO_FIELD_ENCRYPTION_KEY, declared above. LOSE // THE KEY, LOSE THE DATA — GCM fails closed, it never silently corrupts. fieldEncryption: true, // GDPR export/erase walk these (table + the column holding the subject id). subjectScopes: [{ table: 'profiles', subjectField: 'id' }], // Delete profiles untouched for a year (the sweep runs periodically). retention: [{ table: 'profiles', ttlMs: 365 * 86_400_000, action: 'delete' }], }), ], }