This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
TypeScript edge service template for integration-facing services (Slack adapters, MCP servers, webhook receivers). This is a reusable foundation — it contains no product logic, only service plumbing. Node 24+ (pinned in .nvmrc).
- Commit workflow:
.claude/instructions/commit_workflow.md - Dependabot PR merging:
.claude/instructions/dependabot_workflow.md - CI/CD setup:
.claude/instructions/ci_cd.md
# Install dependencies
npm install
# Development server (hot reload)
npm run dev
# Build
npm run build
# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Type checking
npm run typecheck
# Lint
npm run lint
npm run lint:fix
# Format
npm run format
npm run format:check # used in CI
# Pre-commit checks (format, lint, typecheck, tests)
npm run precommitsrc/server.ts is the only file that reads environment variables. Everything else receives configuration via constructor/function arguments, making all modules independently testable.
src/app.ts exports buildApp(opts?) — a Fastify instance factory. Tests call buildApp({ logLevel: "silent" }) via the buildTestApp() helper in test/helpers.ts.
src/config/env.ts— Zod schema for environment validation. ExportsEnvSchema(for testing) andEnvtype. ValidatesPORT,HOST,LOG_LEVEL,CORE_API_BASE_URL,CORE_API_TOKEN.src/lib/errors.ts—AppErrorclass withcode,message,statusCode,details. Used by the error handler to produce consistent error envelopes.src/lib/core-api-client.ts—CoreApiClientclass for calling backend APIs. Constructor injection (baseUrl, token) — no env dependency.src/routes/health.ts—GET /healthzhealth check endpoint.
genReqId— Usesx-request-idfrom request header or generates UUID v4onRequesthook — Setsx-request-idresponse headeronResponsehook — Structured request/response logging (request_id, method, url, status_code, duration_ms)- Error handler —
AppError→ typed envelope; unknown errors → 500 with generic message - Not-found handler — 404 with standard error envelope
All API errors use a stable envelope:
{ "error": { "code": "...", "message": "...", "details": {} } }Success responses use:
{ "data": { ... } }- 18 tests across 6 test files
- Uses Vitest with explicit imports (no globals)
buildTestApp()helper intest/helpers.tscreates a silent Fastify instanceCoreApiClienttests mock globalfetch- Test file structure mirrors
src/layout
Dev requires a .env file (see .env.example):
| Variable | Default | Description |
|---|---|---|
PORT |
3001 | HTTP port |
HOST |
0.0.0.0 | Bind address |
LOG_LEVEL |
info | Pino log level |
CORE_API_BASE_URL |
— | Backend API URL (required) |
CORE_API_TOKEN |
— | Bearer token for backend API (required) |
v0.1 complete. See CHANGELOG.md for the versioned task tracker.