Maintaining the API
Adding or changing Hono routes, keeping the OpenAPI spec in sync, implications for the API reference, and the realtime/SSE event-extension procedure.
The API layer lives in packages/api/src/routes/vtc/ (operator routes) plus Phase 2 routes for driver/, tracking/, agency/, and realtime/. The HTTP framework is Hono 4.12+ with hono-openapi for spec generation.
Adding a new route
1. Choose the correct bounded-context file
Route files are organized by domain:
| File | Domain |
|---|---|
pricing.ts | Pricing zones, rates, strategies |
fleet.ts | Vehicles, drivers |
crm.ts | Contacts, clients |
quotes.ts | Quotes, quote lines |
orders.ts | Orders |
missions.ts | Missions, dispatch |
billing.ts | Invoices, payments |
settings.ts | Organization settings |
integrations.ts | External integrations |
driver/ | Driver-app-specific endpoints |
tracking/ | Customer tracking endpoints |
agency/ | Agency portal endpoints |
realtime.ts | SSE stream endpoints |
2. Define the route with hono-openapi
Every new route must include hono-openapi decorator metadata so it appears in the generated openapi.json. Without it, the route is invisible to the API reference (Story 85-6).
// Example skeleton for a new route
import { describeRoute } from 'hono-openapi'
import { resolver, validator } from 'hono-openapi/zod'
app.get(
'/api/v1/missions/:id/status',
requireOperatorAuth,
describeRoute({
tags: ['missions'],
summary: 'Get mission status',
responses: {
200: {
description: 'Mission status',
content: { 'application/json': { schema: resolver(MissionStatusSchema) } },
},
},
}),
validator('param', ParamSchema),
async (c) => {
// handler
}
)3. Apply the correct auth middleware
| Audience | Middleware |
|---|---|
| Operator back-office | requireOperatorAuth |
| Agency portal | requireAgencyAuth |
| Driver app | requireDriverAuth |
| Customer tracking | validateTrackingToken (public) |
4. Run type-check and tests
pnpm --filter api exec tsc --noEmit
pnpm --filter api testFix all TypeScript errors before proceeding.
5. Regenerate the OpenAPI spec
After any route change, regenerate the OpenAPI spec artifact:
pnpm --filter api buildThe build emits an updated openapi.json. Commit this file alongside the route change — do not let the spec drift from the implementation.
Cross-link: Story 85-5 describes the full spec-generation pipeline. Story 85-6 describes how the interactive API reference consumes the spec.
Changing an existing route
Backward-compatible changes (safe)
- Adding an optional request field.
- Adding a new response field (clients ignore unknown fields).
- Adding a new optional query parameter.
Breaking changes (coordinate with clients)
- Removing or renaming a request field.
- Changing a response field's type.
- Removing a route entirely.
- Changing a route's path or HTTP method.
For breaking changes, version the endpoint (/api/v2/...) or provide a deprecation window with Deprecation and Sunset response headers before removal.
Realtime / SSE — extending event types
The SSE backbone is in packages/realtime. Event types are published by API services and forwarded to connected clients.
When to add a new event type
Add a new event type when:
- A new server-side state transition must be communicated to a client in real time.
- Polling would introduce unacceptable latency for a user-facing feature.
Polling-fallback impact
Every new SSE event type must have a polling-fallback equivalent — a REST endpoint that clients can call when the SSE connection is unavailable (network interruption, service worker context, background tab). Document the polling endpoint alongside the event type.
Procedure
- Define the new event type constant in
packages/realtime/src/events.ts(or the equivalent event catalog file). - Publish the event from the relevant service in
packages/api/src/services/. - Subscribe and forward the event in the appropriate SSE route handler in
packages/api/src/routes/vtc/realtime.ts(operator) orpackages/api/src/routes/driver/realtime.ts(driver). - Update the consuming app to handle the new event type.
- Verify the polling-fallback endpoint is in place.
Apps — when a screen change requires regenerating screenshots
Any change to a screen rendered by apps/web, apps/agency, apps/tracking, or apps/driver that alters the visible layout must trigger screenshot regeneration for the screenshot-drift gate (FR414).
Run the screenshot capture script after UI changes:
pnpm --filter docs exec playwright test --project=screenshotsCommit the new baseline screenshots alongside the code change.
Documentation impact
API changes require updating:
- The OpenAPI spec (
openapi.json) — always regenerate after a route change. - The API Reference — automatically reflects the regenerated spec.
- Any user-facing documentation page that describes the changed endpoint — use the traceability matrix (FR415).
See also: Packages overview — packages/api · Data Model maintenance · Traceability signal
Maintaining the Data Model
The Prisma schema-change procedure, backward-compatibility considerations, and when to reach for a migration versus a code change.
Traceability Signal and CI Gates
The FR→page traceability matrix, the screen registry, and the three CI gates (FR415 traceability, FR417 locale parity, FR414 screenshot drift) that protect documentation integrity.