// "Export all notes" — gated DECLARATIVELY. There's no flag check in the // handler: the `gatedBy: { 'notes.export': 'betaExport' }` map in app.config.ts // makes the framework fail `FlagDisabled` BEFORE this handler runs whenever // `betaExport` is off. Flip the flag (config, or a postgres-store toggle) and // the same call starts succeeding — no code change. // // Declaring `error: FlagDisabled` surfaces the gate's rejection typed. import { defineAction } from '@voltro/protocol' import { FlagDisabled } from '@voltro/plugin-flags/errors' import { Schema } from 'effect' export const exportNotes = defineAction({ name: 'notes.export', // A flag gate is NOT an access decision, and this pair is the clearest place // in the templates to see why. `gatedBy` decides WHETHER THE FEATURE IS ON — // it is a release control, flipped for everyone at once (or by rollout // bucket), and `betaExport: false` in app.config.ts happens to close this // door today. `guards:` / `openAccess:` decide WHO MAY CALL IT. Turning the // flag on must not silently also decide the second question, so the // procedure declares both. // // Open because no auth strategy and no rbac ship here: every caller resolves // to an anonymous Subject with no scopes, so a scope guard would deny all of // them. What the handler returns is a COUNT of the request tenant's own notes // — no bodies, no other tenant's rows (`tenant()` scopes the read). openAccess: 'returns a COUNT of the request tenant\'s own notes — no row contents leave. The ' + '`betaExport` flag gates whether the feature runs at all; that is a release control, not ' + 'an access decision, which is why this line exists alongside it.', input: Schema.Struct({}), output: Schema.Struct({ exported: Schema.Number }), error: FlagDisabled, })