feat(api): full API surface with typed DTOs and role-gated stubs (PH1.7) #74

Merged
bart merged 5 commits from feature/api-surface into main 2026-09-11 12:43:06 +00:00
Collaborator

Description

This finishes the whole planning-tool API's shape: every endpoint from the API design (docs/09-api.md) now exists — with the right URL, method, request/response data, and who's allowed to call it — even though most of them don't do their real work yet (they answer "not implemented" until the ticket that builds that piece lands). Vehicles, sites, and the catalogue (service types, skills, reason codes), plus crews and people, are fully working already: list, create, edit, and (soft) delete, with paging, safe retries, and optimistic-concurrency editing all included for free.

The practical effect: the frontend can now generate its typed API client once, against a complete and stable contract, and every other in-flight and upcoming feature can build its screens against real request/response shapes instead of guessing or waiting on a backend PR.

Closes #15 (PH1.7 API surface). Builds on #10, #11, #12.

Type of Change

  • New feature

Breaking Changes

None.

Test Plan

Unit tests cover every hand-written stub endpoint: a caller without the right role gets a 403, a caller with the right role gets the expected "not implemented" response — never the other way round. The genuinely-working aggregates (vehicles, sites, catalogue, crews, people) are covered by the existing CRUD test suite. Full backend suite (unit + integration, real Postgres) is green, as are lint and strict type checks. Regenerated the committed API contract and confirmed the frontend's client-generation step runs against it and produces code that compiles cleanly.

Checklist

  • Conventional commit(s), one logical change per commit
  • Tests added/updated and passing
  • docs/ updated for any behavioural change (ADR added if a prior decision was reversed)
  • No hard deletes; no direct status updates outside polaris.domain
  • No business logic in routers/components
  • Migration included if the schema changed (one per PR max, reversible downgrade)
  • No new dependency without a reason in the commit body

Additional Context

A handful of request/response shapes aren't literally specified in the design doc (e.g. the FleetPulse ingest document, the manual-window body, the plan diff and dashboard responses) — these are reasonable first drafts, called out on the issue for whoever builds the real endpoint to confirm or adjust. One area (feedback reporting) isn't clearly claimed by any upcoming ticket yet, also flagged on the issue. The one CI acceptance criterion (a freshness check on the committed contract) can't be verified because no CI workflow exists in this repo yet; the contract is freshly regenerated so it's ready for that check whenever it's added.

🤖 Generated with Claude Code

https://claude.ai/code/session_013YioTVKBPoE6thZqbnTtnM

## Description This finishes the whole planning-tool API's shape: every endpoint from the API design (`docs/09-api.md`) now exists — with the right URL, method, request/response data, and who's allowed to call it — even though most of them don't do their real work yet (they answer "not implemented" until the ticket that builds that piece lands). Vehicles, sites, and the catalogue (service types, skills, reason codes), plus crews and people, are fully working already: list, create, edit, and (soft) delete, with paging, safe retries, and optimistic-concurrency editing all included for free. The practical effect: the frontend can now generate its typed API client once, against a complete and stable contract, and every other in-flight and upcoming feature can build its screens against real request/response shapes instead of guessing or waiting on a backend PR. ## Related Issues Closes #15 (PH1.7 API surface). Builds on #10, #11, #12. ## Type of Change - [x] New feature ## Breaking Changes None. ## Test Plan Unit tests cover every hand-written stub endpoint: a caller without the right role gets a 403, a caller with the right role gets the expected "not implemented" response — never the other way round. The genuinely-working aggregates (vehicles, sites, catalogue, crews, people) are covered by the existing CRUD test suite. Full backend suite (unit + integration, real Postgres) is green, as are lint and strict type checks. Regenerated the committed API contract and confirmed the frontend's client-generation step runs against it and produces code that compiles cleanly. ## Checklist - [x] Conventional commit(s), one logical change per commit - [x] Tests added/updated and passing - [x] `docs/` updated for any behavioural change (ADR added if a prior decision was reversed) - [x] No hard deletes; no direct status updates outside `polaris.domain` - [x] No business logic in routers/components - [x] Migration included if the schema changed (one per PR max, reversible downgrade) - [x] No new dependency without a reason in the commit body ## Additional Context A handful of request/response shapes aren't literally specified in the design doc (e.g. the FleetPulse ingest document, the manual-window body, the plan diff and dashboard responses) — these are reasonable first drafts, called out on the issue for whoever builds the real endpoint to confirm or adjust. One area (feedback reporting) isn't clearly claimed by any upcoming ticket yet, also flagged on the issue. The one CI acceptance criterion (a freshness check on the committed contract) can't be verified because no CI workflow exists in this repo yet; the contract is freshly regenerated so it's ready for that check whenever it's added. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_013YioTVKBPoE6thZqbnTtnM
Adds DTOs and routers for the first slice of the docs/09-api.md surface:
vehicles and sites get genuine crud_router-backed CRUD (list/get/create/
update/soft-delete with pagination, ETag and idempotency for free); the
read-only vehicle sub-resources (sites/windows/heatmap) and site
suitability endpoints are hand-written 501 stubs behind their documented
role, since they need domain logic that isn't built yet. Catalogue
(service-types/skills/reason-codes) is full crud_router CRUD, admin-write /
any-authenticated-read.

Part of issue #15 (PH1.7 API surface).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013YioTVKBPoE6thZqbnTtnM
Crews and people get genuine crud_router-backed CRUD. Jobs and shifts
can't use the generic factory even though they look CRUD-shaped: both
models use AuditColumns (transition lifecycle) rather than
SoftDeleteColumns, one column short of what the soft-delete Repository
needs (deleted_at unconditionally) - so every /jobs and /shifts endpoint,
plus the composite-PK crew_member sub-resource, is a hand-written 501
stub behind its documented role. Job/shift transitions and opportunities
are split into their own router modules matching the PH2+ ticket that
will own each one, per docs/12-implementation-plan.md.

Part of issue #15 (PH1.7 API surface).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013YioTVKBPoE6thZqbnTtnM
All 501 stubs behind their documented role, one router module per future
owner per docs/12-implementation-plan.md (T-E for versions/runs/active,
PH3.2 triage, PH3.3 recalculate, PH3.4 publish/discard, PH5.1 locks,
PH5.4 overrides, PH5.5 diff, PH5.9 rejections, PH4.1 assignments, T-E
tasks, T-B ingest) so no future ticket needs to touch a file another one
also edits. Finding/lock/replan-mode DTOs are typed against the closed
enums in polaris.contracts rather than plain str, matching the i18n
boundary those types exist for.

Part of issue #15 (PH1.7 API surface).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013YioTVKBPoE6thZqbnTtnM
Completes the docs/09-api.md surface: every documented path/method now
has a router with typed request/response DTOs and its documented role
enforced before a 501. GET /me/today is a new module alongside the
existing PH0.4 me/profile.py, left untouched. Notification.kind is typed
against the closed NotificationKind list in polaris.contracts.

Part of issue #15 (PH1.7 API surface).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013YioTVKBPoE6thZqbnTtnM
Commits the OpenAPI contract for every endpoint in docs/09-api.md now
that all routers exist. Verified npm run api:gen produces a schema.d.ts
that compiles standalone under strict TypeScript. Also updates the Sites
row in docs/09-api.md: it documented GET/PATCH only, but sites are wired
with the shared crud_router factory like every other master-data
aggregate, so POST/DELETE exist too (DELETE = soft) - the doc now says
so instead of undercounting what the committed contract has.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013YioTVKBPoE6thZqbnTtnM
bart merged commit c55d1f97d3 into main 2026-09-11 12:43:06 +00:00
bart deleted branch feature/api-surface 2026-09-11 12:43:06 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
patrick/Polaris!74
No description provided.