File
Blob: AGENTS.md
AGENTS.md
Purpose
flamemail is a transactional-email testing service on Cloudflare's edge. It has a React SPA frontend and a Cloudflare Worker backend for HTTP APIs, Turnstile-backed inbox creation, tessera-backed admin auth, inbound email ingestion, WebSocket fanout, and scheduled cleanup.
Use this file for repo-specific safety rails. Use README.md for setup/deploy instructions, spec.md for detailed architecture and API rationale, wrangler.jsonc for Cloudflare bindings, and package.json for scripts.
Start Here
- Client entry and routes:
src/client/main.tsx,src/client/App.tsx. - Client API helpers and session/bookmark handling:
src/client/lib/api/. - Email HTML safety:
src/client/lib/email-html/. - Worker entry:
src/worker/index.tsexportsfetch(),email(),scheduled(), andInboxWebSocket. - HTTP routing and D1 session/bookmark setup:
src/worker/router.ts. - API route handlers:
src/worker/api/; keep reusable behavior insrc/worker/services/. - Inbox lifecycle, domains, cleanup, sessions, and WebSocket tickets:
src/worker/services/inbox/. - Inbound email pipeline:
src/worker/email-handler.ts. - Auth, cookies, origin checks, Turnstile, and OIDC:
src/worker/middleware/,src/worker/security.ts,src/worker/services/cookies.ts,src/worker/services/oidc.ts,src/worker/services/turnstile.ts. - Database schema and migrations:
src/worker/db/schema.ts,drizzle/.
Change Rules
- Prefer minimal, targeted changes and preserve the client/worker split.
- Do not introduce secrets into source control.
- Keep imports at the top of files and follow existing local patterns.
- Keep
src/shared/contracts/, worker routes, and client API helpers aligned for any request/response shape change. - Prefer
@cloudflare/util-en-gardefor new validated shapes. - API changes belong in
src/worker/api/, must be registered throughsrc/worker/router.ts, and should push business logic into services. - Frontend routes belong in
src/client/App.tsx; API calls belong insrc/client/lib/api/. - Database changes require
src/worker/db/schema.tsplus a reviewed Drizzle migration indrizzle/; apply schema changes locally before remote migration. - Run
npm run checkwhen practical. For docs-only changes, a targeted Prettier check is enough.
Security Invariants
- Treat inbound email content, HTML, attachments, links, headers, params, and API bodies as hostile.
/api/*and/wsrequests must run through the Worker before static asset handling; preserverun_worker_firstbehavior inwrangler.jsonc.- Anonymous inbox creation requires a valid Turnstile token and fails closed if Turnstile config or verification is missing, invalid, or unavailable.
- Admin access requires tessera OIDC plus a
subinTESSERA_OPERATOR_SUBS; missing config, an empty allowlist, or failed discovery must fail closed withADMIN_ACCESS_DISABLED. - Register tessera redirects as
<flamemail-origin>/api/public/admin/callback. - Admin sessions live in KV and an
HttpOnly,Secure,SameSite=Lax,__Host-flamemail-admincookie. OIDC transaction state lives only in the sealed__Host-flamemail-oidccookie. - Admin inspection on inbox routes requires explicit
?admin=1; cookie-authenticated mutations require same-origin checks. - Admin inspection of temporary inboxes is read-only except deleting the inbox itself.
- WebSocket upgrades require a valid origin and one-time ticket.
- D1 bookmarks use the
x-d1-bookmarkheader so reads can observe recent writes without forcing every request to primary. - Active domains seed permanent
admin,postmaster,abuse, andwebmasterinboxes. - Temporary inboxes expire and are purged by the hourly cron; cleanup changes must not leave access tokens or stored content behind.
- Plus aliases route to the same base inbox, while each email record preserves the exact delivered recipient address.
- Email HTML must remain sandboxed, remote resources blocked by default, and external links rewritten through
/link. - Delete and cleanup flows must consider D1 rows, KV session/ticket state, R2 objects, and Durable Object notifications. Revoke access and remove R2 objects before deleting D1 rows.
Task Checklist
- API change: update route, shared contract, client helper, router registration, and
npm run check. - Inbox lifecycle/storage change: account for D1, KV, R2, Durable Object side effects, cleanup, and real-time behavior.
- UI/security change: preserve session persistence, D1 bookmark propagation, Turnstile, OIDC, WebSocket isolation, and email HTML safety.
- Schema change: update schema, generate/review migration, apply locally, and re-test affected flows.
Local Notes
- Assume the dev server is already running. Do not start
npm run devagain unless the user asks or you have verified no relevant server is running. - Local admin sign-in uses
npm run oidc:localwith the.dev.vars.exampletessera values; seeREADME.mdfor setup details. - Cloudflare Email Routing catch-all rules are configured in the Cloudflare dashboard, not in code.