/netlify/functions/CLAUDE.md
CLAUDE.md at /netlify/functions/CLAUDE.md
Path: netlify/functions/CLAUDE.md
Netlify Functions
Serverless API backend for the notify/reservation system. 16 TypeScript functions bundled with esbuild.
Architecture
- Public endpoints:
notify-signup.ts,reservation.ts— user-facing form submissions - Admin endpoints:
admin-*.ts— authenticated CRUD for managing subscriptions/reservations - Shared modules in
shared/: CORS, auth, blob storage, email, webhooks, validation, types
Conventions
Admin Handlers
Use createAdminHandler() wrapper — handles CORS, POST validation, Bearer token auth, JSON parsing, and error handling:
import { createAdminHandler } from './shared/index.js';
export default createAdminHandler(async ({ body, origin, request }) => {
// Your logic here
return { body: responseObject };
});
Bulk Operations
Use validateBulkIdsRequest() from shared/validation.ts for archive/unarchive/delete endpoints. All 6 bulk handlers follow the same pattern.
Import sendSingleEmail from ./shared/email.js directly (NOT via shared/index.ts — Resend package is excluded from the barrel export to avoid loading it in functions that don’t need email).
Blob Storage
- Store name:
preorder-data(production) /preorder-data-preview(preview/dev) - Key patterns:
notify:{slug}:{id},reservation:{slug}:{id},index:notify:{slug},config:email-template:* - Index updates are not atomic — acceptable for low-traffic
CORS
shared/cors.ts— public endpoint CORS (reflects allowed origins)shared/admin-auth.ts— admin endpoint CORS (stricter, no fallback origin)- Both allow Netlify branch deploy URLs via regex:
/^https:\/\/[a-z0-9-]+--takazudomodular\.netlify\.app$/
Webhooks
shared/slack.ts— private admin notifications (includes PII)shared/discord.ts— public notifications (product info only, no PII)- Use
Promise.allSettled()for parallel notification dispatch
Product Validation
isValidProductSlug()— format check (regex)isKnownProductSlug()— existence check (against product map)- Both must pass before accepting submissions
Photo uploader endpoints (Cloudflare Worker behind a proxy shim)
Photo metadata storage and the actual /photo-uploader-{login,sign,commit} handlers are served by the Cloudflare Worker at sub-packages/photo-uploader-worker/. See its CLAUDE.md for D1 binding setup, the secrets runbook, and the deploy procedure. The Netlify path /.netlify/functions/photo-uploader-{login,sign,commit} is served by three thin proxy Functions in this directory (photo-uploader-login.ts, photo-uploader-sign.ts, photo-uploader-commit.ts) that forward to the Worker via shared/photo-uploader-proxy.ts. We can’t use [[redirects]] rewrites here because Netlify silently drops rules whose from starts with /.netlify/. The shim is intentionally minimal — all auth, D1, R2 signing logic lives in the Worker.
Routing
Production uses netlify.toml [[redirects]]. Preview deploys use static/_redirects which must include admin-specific rules (the generic /api/* splat doesn’t map slashes to dashes).