// `mail.sendWelcome` — example action that sends the `welcome` template // via @voltro/plugin-mail. With the `console` provider nothing leaves the // process — the send is logged + captured in the dev outbox (dashboard // Mail panel). Swap the provider in app.config.ts for real delivery. // // Email is external I/O → an action, not a mutation. import { Schema } from 'effect' import { defineAction } from '@voltro/protocol' export const sendWelcome = defineAction({ name: 'mail.sendWelcome', // Read this one carefully before copying it. Sending THIS APP'S branded mail // to a caller-supplied address is one of the few things a tenant boundary // does not bound — the recipient is an arbitrary third party, not a row. // // It is open here for exactly two reasons, both checkable in this repo: // `provider: 'console'` in app.config.ts means nothing leaves the process // (the send is logged and captured in the dev outbox), and no auth strategy // ships in this template, so a `guards: [{ scope: 'mail:send' }]` would deny // every caller rather than the wrong ones. // // The moment you swap in `resend` / `postmark` / `sendgrid` / `smtp`, this // becomes an open relay for your own domain's reputation. Add an auth // strategy and that `mail:send` guard in the SAME change. openAccess: 'sends the `welcome` template to a caller-supplied address via the `console` provider — ' + 'nothing leaves the process, it is logged and captured in the dev outbox. Switching to a ' + 'real provider makes this an open relay: add an auth strategy and a `mail:send` guard first.', input: Schema.Struct({ email: Schema.String, name: Schema.String, }), output: Schema.Struct({ id: Schema.String, provider: Schema.String, }), })