Runbooks
Ops Desk — Inbound Email Worker Deploy
Ops Desk — Inbound Email Worker Deploy
Turnkey deploy for the workers/desk-inbound/ Cloudflare Email Routing worker built in
Plan 2. Everything here needs your Cloudflare + Supabase accounts, so it’s an operator
task (not something the agents can do). Do it in order; each step has a verify.
What this worker does: receives mail to
support@, requires DMARC pass, matches the sender againstdesk_allowlist, and either appends a verified reply, opens a new ticket, or quarantines — writing to Supabase with the service-role key. See the spec §6–§7.
Prerequisites
- Supabase project for the dashboard (the one
dashboard/src/lib/supabase.tspoints at). - Cloudflare account with the
cybersuite.techzone and Email Routing enabled. wranglerauthenticated:cd workers/desk-inbound && npx wrangler login.- The dashboard domain you want
support@to belong to.
1. Apply the Supabase migrations
The desk tables/RLS/RPC ship as migrations but the CLI isn’t installed locally, so apply
them in the Supabase SQL editor (or via supabase db push if you wire the CLI):
dashboard/supabase/migrations/003_desk_schema.sql(tables, enums,desk_ticket_seq)dashboard/supabase/migrations/004_desk_rls.sql(operator-only RLS)dashboard/supabase/migrations/005_desk_ticket_rpc.sql(desk_next_ticket_no())
Verify: select table_name from information_schema.tables where table_name like 'desk_%';
returns the four desk_* tables; select desk_next_ticket_no(); returns CS-T-1000.
2. Seed the allowlist (per customer)
For each onboarded firm, add their authorized domain(s):
insert into desk_allowlist (customer, domain, active) values ('CS-0001', 'lawfirm.com', true);
-- optional specific address instead of/in addition to a domain:
insert into desk_allowlist (customer, address, active) values ('CS-0001', 'vip@other.com', true);
Verify: select customer, domain, address from desk_allowlist where active;
3. Create the KV namespace
cd workers/desk-inbound
npx wrangler kv namespace create DESK_KV
Copy the printed id into wrangler.toml ([[kv_namespaces]] id = "..."), replacing
REPLACE_WITH_KV_NAMESPACE_ID.
4. Fill wrangler.toml vars
SUPABASE_URL= your project URL (same asPUBLIC_SUPABASE_URL).RATE_PER_SENDER_HOUR/RATE_GLOBAL_HOUR— leave at20/300unless you have a reason.
5. Set the secrets (never commit these)
npx wrangler secret put SUPABASE_SERVICE_ROLE_KEY # Supabase → Project Settings → API → service_role
npx wrangler secret put DESK_REPLY_SECRET # a long random string; MUST be reused by the Plan 3 outbound notifier
DESK_REPLY_SECRETis the HMAC key for reply tokens. The inbound worker (verify) and the outbound notifier (sign) must use the same value or replies won’t thread.
6. Deploy
npx wrangler deploy
Verify: the deploy prints a worker URL and version; npx wrangler tail shows it live.
7. Route support@ to the worker
Cloudflare dashboard → Email → Email Routing → Routing rules → create/route
support@cybersuite.tech (or your chosen address) → Send to a Worker → desk-inbound.
Confirm Email Routing is verified for the domain (MX/SPF/DKIM records added by Cloudflare).
8. Smoke test
- From an allowlisted domain mailbox, email
support@…with any subject/body.- Verify: within ~30s a ticket appears in the dashboard
/desklist (CS-T-####, status open), andnpx wrangler tailshows theemail()invocation.
- Verify: within ~30s a ticket appears in the dashboard
- From a NON-allowlisted address, email
support@….- Verify: it does NOT create a ticket; it appears in
/desk/quarantinewith reasonsender not allowlisted.
- Verify: it does NOT create a ticket; it appears in
- Spoof check (optional): send from a domain that fails DMARC.
- Verify: quarantined with an
auth: dmarc=...reason — no ticket.
- Verify: quarantined with an
Rollback
- Remove the Email Routing rule (mail stops reaching the worker; senders get normal MX behavior). The worker + tables stay intact for re-enable.
- The worker only ever writes desk rows; it never deletes. Quarantine rows are inert.
Notes / limits (from the Plan 2 reviews)
- Rate-limit uses KV counters (not atomic) — fine at email volumes; revisit Durable Objects only if you see abuse at scale.
- Reply tokens are HMAC-bound to ticket + customer (after the Plan 3-eve hardening), and the DB also checks the ticket’s customer on append — double protection against cross-customer note injection.
- The outbound side (acks, notifications) lands in Plan 3; until then the worker writes tickets/notes silently (visible in the dashboard) without emailing the client back.