Takazudo Modular Docs

Type to search...

to open search from anywhere

/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.

Email

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).