---
description: Express API conventions (Math Tutoring App)
globs: api/**/*.js
alwaysApply: false
---

# API Patterns — `api/`

Stack: **Express** (CommonJS **`.js`**), **Vercel AI SDK** (`ai`, `@ai-sdk/openai`), deployed as **Vercel** serverless. **No database in this API** — persistence is **Firebase** from the **webapp** only.

## Folder layout (actual)

```
api/
  server.js          ← Express app, CORS, JSON, mounts routes, error handler
  index.js             ← Vercel entry; re-exports app
  routes/
    chat.js            ← POST /chat, SSE streaming, tool schemas (Zod)
  services/
    promptService.js   ← System prompt / message building
    contextManager.js  ← Conversation context helpers (if used)
  src/lib/
    logger.js            ← Pino singleton; pino-http attaches `req.log` per request (see server.js)
  src/config/          ← Centralized env (Phase 4 — read REFACTOR_RUNBOOK.md)
```

There is **no** `middleware/` or `prisma/` here. Do not add Prisma or hand-written SQL migrations to this project.

## Responsibilities

- **`routes/`** — Thin HTTP: validate inputs, call `services/`, set status codes, stream SSE. Avoid huge inline prompt strings; keep them in `services/promptService.js` (or dedicated modules under `services/`).
- **`services/`** — Business-ish logic: prompt construction, helpers. No Firebase Admin for Firestore user data (removed by design); optional context utilities only.
- **`server.js`** — App wiring only; avoid new domain logic here.

## LLM & streaming

- Use the **Vercel AI SDK** patterns already in `routes/chat.js` (`streamText`, tools, Zod `inputSchema`).
- **OpenAI API key** must stay **server-side** only (`OPENAI_API_KEY`).

## Environment variables

- **Do not** scatter new `process.env` reads — the refactor runbook centralizes config under **`api/src/config/`** (Phase 4). Until then, follow existing patterns and Oxlint overrides documented in the runbook.

## Logging

- Import **`api/src/lib/logger.js`** for startup and process-level logs; in routes use **`req.log`** from **pino-http** (registered first in `server.js`).
- Never use `console.*` in application code.

## Errors

- Prefer consistent JSON error shapes for new routes; match existing `{ error, message }` style in this codebase unless a refactor standardizes on another shape.

## SSE

- Chat streaming uses `text/event-stream` and `data: …` lines as already implemented; preserve headers (`Content-Type`, `Cache-Control`, `Connection`) when touching streaming code.
