# amd-notify-bun

Bun port of the `exult-amd-notify` Cloudflare Worker. Polls AdvancedMD every
5 minutes for newly added patients and sends a Teams notification through the
local `teams-channel` bun server.

## What it does

1. Loads state (last poll date + seen patient IDs) from a JSON file on disk.
2. Authenticates to AdvancedMD via the partner-login XML-RPC API.
3. Calls `getupdatedpatients` with `datechanged=<last poll>`.
4. Filters to patients whose `createdAt` is newer than the last poll and that
   we have not already notified about.
5. Enriches each new patient with next appointment + referring provider.
6. POSTs a notification to the teams-channel bun's `/api/notify` compat
   endpoint (which translates the legacy `{chat_id, text}` shape to a Bot
   Framework activity and delivers it via the saved conversation reference).
7. Writes updated state back to disk.

## Differences vs the CF Worker

| Concern        | CF Worker                                | bun service                                       |
|----------------|------------------------------------------|---------------------------------------------------|
| Scheduling     | `wrangler.toml` cron `*/5 * * * *`       | systemd user timer (`OnUnitActiveSec=5min`)       |
| State          | CF KV namespace `STATE`                  | JSON at `/home/claude/state/amd-notify.json`      |
| Teams endpoint | `exult-teams-proxy.workers.dev/api/messages/send` | `claude-cloud.tail053faf.ts.net/teams/api/notify` |
| Secrets        | `wrangler secret`                        | gitignored env file `/home/claude/.config/amd-notify.env` |

## Environment variables

Required in `/home/claude/.config/amd-notify.env`:

```
AMD_OFFICE_KEY=161112
AMD_USERNAME=ARC022825
AMD_PASSWORD=<advancedmd password>
AMD_APPNAME=TEMP
TEAMS_WORKER_URL=https://claude-cloud.tail053faf.ts.net/teams
TEAMS_API_KEY=<shared secret matching MSTEAMS_NOTIFY_API_KEY on the teams-channel bun>
TEAMS_CHAT_ID=<target Teams chat / conversation id>
```

Optional:

```
AMD_NOTIFY_STATE_FILE=/home/claude/state/amd-notify.json   # state file path
AMD_NOTIFY_MOCK=1                                          # skip the real AMD calls (for smoke tests)
```

## Operator install checklist

1. Populate `/home/claude/.config/amd-notify.env` with the AMD + Teams creds
   (see "Environment variables" above). Copy `AMD_PASSWORD` from the CF worker
   secret. Pick any strong random value for `TEAMS_API_KEY`.
2. Set the same `TEAMS_API_KEY` value in the teams-channel service env as
   `MSTEAMS_NOTIFY_API_KEY` (or otherwise the `/api/notify` route will refuse
   all calls with HTTP 503).
3. Restart the teams-channel server so it picks up the new env var + new route:
   `tmux send-keys -t teams Enter` (or however your orchestrator restarts it).
4. Install the systemd timer:

```bash
mkdir -p /home/claude/.config/systemd/user
cp tools/amd-notify-bun/systemd/amd-notify.service /home/claude/.config/systemd/user/
cp tools/amd-notify-bun/systemd/amd-notify.timer   /home/claude/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now amd-notify.timer
```

5. Once the new amd-notify is healthy (after 1-2 polls), decommission the
   Cloudflare worker:
   `cd tools/amd-notify-worker && bunx wrangler delete exult-amd-notify`.

Verify it is scheduled:

```bash
systemctl --user list-timers amd-notify
```

Run once manually:

```bash
systemctl --user start amd-notify.service
journalctl --user -u amd-notify.service -n 50
```

## Smoke test (no AMD creds required)

```bash
AMD_NOTIFY_MOCK=1 \
TEAMS_WORKER_URL=https://claude-cloud.tail053faf.ts.net/teams \
TEAMS_API_KEY=<key> \
TEAMS_CHAT_ID=<chat id> \
bun tools/amd-notify-bun/poller.ts
```

This will synthesize one fake patient, POST to the teams compat endpoint,
write state to `/home/claude/state/amd-notify.json`, and exit 0.
