This is a TypeScript edge service template built with Fastify. There are no frontend, HTML, or browser UI components.
- Reusable edge-service template for Slack adapters, MCP servers, webhook receivers, and similar integration-facing services
- Node 24 is pinned in
.nvmrc; runnvm usefrom the repo root if the shell is on the wrong version - Commit workflow:
.claude/instructions/commit_workflow.md - Dependabot PR merging:
.claude/instructions/dependabot_workflow.md - CI/CD setup:
.claude/instructions/ci_cd.md - Only
src/server.tsreads environment variables — all other modules receive config via constructor/function arguments - Use the
buildTestApp()helper fromtest/helpers.tsfor all test setup — never instantiate Fastify directly in tests - All routes are JSON API endpoints.
GET /healthzis the baseline health check - All API errors use the standard envelope:
{ "error": { "code": "...", "message": "...", "details": {} } } - All success responses use:
{ "data": { ... } } - Use
AppErrorfromsrc/lib/errors.tsfor throwing typed errors — never throw plainErrorfor expected failure cases - Outbound calls to core APIs go through
CoreApiClient— never usefetchdirectly for backend calls
- Install deps:
npm install - Dev server:
npm run dev - Build:
npm run build - Test suite:
npm test - Test watch:
npm run test:watch - Typecheck:
npm run typecheck - Pre-commit:
npm run precommit
v0.1complete- See
CHANGELOG.mdfor the versioned task tracker
- Strict mode is enabled (
strict: trueplusnoUncheckedIndexedAccess,exactOptionalPropertyTypes,noImplicitOverride) - Use
typeimports for type-only imports:import type { FastifyPluginAsync } from "fastify" - Use
.jsextensions in import paths (required by NodeNext module resolution) - Use
readonlyon constructor parameters and properties that should not be reassigned - Prefix unused parameters with
_(configured in ESLint) - Prefer
unknownoverany— the codebase has zeroanyusage - Use
interfacefor object shapes that may be extended,typefor unions/intersections/utility types
- Use Vitest with explicit imports (
import { describe, it, expect } from "vitest") — no globals - Test files mirror the
src/directory structure undertest/ - Mock
fetchat the test level forCoreApiClienttests — do not use external HTTP mocking libraries - Use
app.inject()for route testing (Fastify's built-in light HTTP injection) - Clean up any mocks with
vi.restoreAllMocks()inafterEach
- Use
npm run precommitwhen you are done with all changes and fix any pending issues - Prettier handles formatting (run
npm run format) - ESLint 9 flat config with
typescript-eslint(runnpm run lint) - CI checks
format:checkandlint