security domain
owns who may call a boundary, what they may read and change, and how secrets and untrusted inputs stay outside the durable core.
why
every durable write is only as trustworthy as the weakest boundary in front of it. authentication, authorization, secrets, rate limits, and webhook verification group because they are all proofs a boundary must hold before an effect is allowed: who is calling, what they may change, and whether the caller can exhaust the system. once untrusted input reaches the core, no amount of internal correctness restores the lost proof.
when to use
owns a decision when the question is what a boundary must prove before an effect is allowed — authentication, authorization, secrets, rate limits, webhook verification. accepted-input shape belongs to the contract domain.
good and bad
bad
// route handler immediately uses external dataexport const handleWebhook = async (c: Context) => {const payload = await c.req.json(); // unknown shapeconst userId = payload.user_id; // no validationconst action = payload.action; // no checking// durable write happens directlyawait updateUserPlan({ userId, plan: payload.plan });// malicious caller sends: { user_id: "admin", plan: "premium" }// admin account is now premium without authorization};
untrusted input reaches the durable core with no proof of sender or
permission. a forged webhook sends { user_id: "admin", plan: "premium" }
and the admin account silently becomes premium. signature never verified,
no rate limit (quota exhausted), no audit trail of who triggered the change.
good
// boundary validates caller, signature, and rate limits BEFORE the serviceexport const handleWebhook = async (c: Context) => {// 1. Prove who sent thisconst authenticated = await authenticateWebhookCaller(c);if (!authenticated) return c.json({ error: "unauthorized" }, 401);// 2. Verify it came from the claimed provider (not spoofed)const payload = await c.req.raw.arrayBuffer();const signature = c.req.header("x-webhook-signature");const verified = verifyProviderSignature(payload, signature);if (!verified) return c.json({ error: "signature_invalid" }, 401);// 3. Rate-limit untrusted callersconst remaining = await rateLimitBucket.tryConsume(authenticated.callerId);if (remaining <= 0) return c.json({ error: "rate_limited" }, 429);// 4. Validate and map external shape to domain contractconst parsed = WebhookPayloadSchema.parse(await c.req.json());// 5. Delegate to domain service (now safe)const result = await handleUserPlanUpdate({callerId: authenticated.callerId,userId: parsed.userId,plan: parsed.plan,});// 6. Log the audit trailawait auditLog.record({event: "webhook_processed",callerId: authenticated.callerId,userId: parsed.userId,});return c.json(result);};
every proof is made explicitly at one visible boundary: authenticate, verify signature, rate-limit, schema-parse, delegate, audit. the domain service receives only trusted data and knows who triggered the change. an auditor reads one file to verify the whole posture; a new route inherits the guarantees by composing the same guard order.