API Setup
Setting up the Hono BFF API server
Overview
The API (apps/api) is a Hono-based BFF (Backend For Frontend) server that sits between the app and the database. It handles authentication, business logic, and data access via Drizzle ORM.
Prerequisites
- Node.js 24+
- pnpm 10+
- Local Supabase running (for Postgres) or a remote database
- Clerk account (for authentication)
Environment Variables
Create apps/api/.env from the example:
cp apps/api/.env.example apps/api/.env| Variable | Required | Default | Description |
|---|---|---|---|
PORT | No | 3002 | Server port |
DATABASE_URL | Yes | — | PostgreSQL connection string |
SUPABASE_URL | Yes | — | Supabase project URL (for auth integration) |
SUPABASE_SERVICE_ROLE_KEY | Yes | — | Supabase service role key |
CLERK_SECRET_KEY | Yes | — | Clerk secret key for JWT verification |
CLERK_WEBHOOK_SECRET | No | — | Clerk webhook signing secret. When not set, webhook routes are disabled. |
RESEND_API_KEY | No | — | Resend API key for transactional emails |
API_KEY | Yes | — | API key for server-to-server routes (deals endpoint) |
Local development values
PORT=3002
DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres
SUPABASE_URL=http://127.0.0.1:54321
SUPABASE_SERVICE_ROLE_KEY=<from supabase status>
CLERK_SECRET_KEY=sk_test_<from Clerk dashboard>
API_KEY=dev-api-keyRunning
# Start the API server (with hot reload)
pnpm dev:api
# Or from the api directory
cd apps/api && pnpm devThe API runs on http://localhost:3002 with:
- API routes at
/api/* - OpenAPI spec at
/doc - Swagger UI at
/swagger - Health check at
/health
Architecture
Middleware chain
Request → dependencies (db) → authMiddleware → createApi (repos with userId) → handlerAll protected routes go through authMiddleware (JWT verification) then createApi (creates repositories with the authenticated user context). Every repository receives the userId for permissions and scoping.
Event bus
The API uses a domain event bus for decoupled side effects:
// Events emitted by AccountsService
"account:created" → onboarding subscriber (seeds default boards)
"account:updated" → (future subscribers)Subscribers are registered at startup in src/index.ts.
Webhook routes
Webhook routes (/api/webhooks/*) have their own WebhookEnv context — separate from the main Api. They are only registered when CLERK_WEBHOOK_SECRET is configured.