# Approvals example

```sh
bunx @revnu/fuast new approvals --template approvals
```

Anyone in the workspace submits a request with an amount and a reason. An approver approves or rejects it with an optional note. Both sides get email, and a weekday digest reminds approvers of anything still pending.

## What it shows

- `auth: { requireSignIn: true }` for a workspace tool.
- Approvers from `ctx.workspace.members()`, optionally narrowed by `APPROVER_EMAILS` in env.
- `submit` emails approvers. `decide` checks that the caller is an approver, is not the submitter, and that the request is still pending, then emails the submitter. Email is always the last step.
- A `digest` schedule at `0 9 * * 1-5` (09:00 UTC on weekdays), plus `sendDigestNow`, which runs the same helper on demand for testing.
- WebMCP tools on `submit`, `decide`, `mine`, and `queue`, so a browser agent can file and decide requests.
- `submitterId` and `deciderId` declared as `userId()`, and names stored as snapshots.

## Workspace members as approvers

```ts
async function approvers(ctx: TeamContext): Promise<Member[]> {
  const members = await ctx.workspace.members();
  const allowed = parseEmailList(ctx.env.APPROVER_EMAILS);
  if (allowed.length === 0) return members;
  return members.filter((m) => allowed.includes(m.email.toLowerCase()));
}
```

The same helper runs in queries (to show the queue), mutations (to authorize decisions), and the schedule (to address the digest). Schedules may call `ctx.workspace.members()` even though they have no caller.

## The digest

```ts
schedules: {
  digest: schedule("0 9 * * 1-5", async (ctx) => {
    await sendDigest(ctx);
  })
}
```

`sendDigest` reads up to 100 pending requests through the `by_status` index and emails each approver once. It never calls `ctx.auth` guards, because schedules run as the system. See [schedules](https://fuast.com/docs/schedules.md).

## Configure

```txt
# .env.fuast.server
APPROVER_EMAILS=finance@acme.com,cto@acme.com
```

Without it, every workspace member can decide anyone else's request. For the hosted app, set it in the dashboard Env tab or deploy the file.

## Try it

```sh
bunx @revnu/fuast dev
```

Submit as `dev`, approve as `?fuast_user=alice`, and read the emails with `bunx @revnu/fuast logs --port 3000`. Click "Email digest now" to test the digest. Then:

```sh
bunx @revnu/fuast deploy
bunx @revnu/fuast share --visibility workspace
```
