# API Surface ## Health - `GET /health` ## Registry - `GET /assets` - `POST /assets` - `GET /registry/assets/{id}` - `PUT /registry/assets/{id}` - `DELETE /registry/assets/{id}` - `GET /components` - `POST /components` - `GET /registry/components/{id}` - `PUT /registry/components/{id}` Registry invariants: - Assets do not carry `project_id` in request/response contracts. - Registry `PUT` mutations are history-backed (event + snapshot + projection update), not direct projection writes. ## Ingest - `POST /ingest/hardware` - `POST /ingest/manual/csv` - `GET /ingest/manual/csv/jobs/{id}` Manual CSV ingest contract: - `POST /ingest/manual/csv` is asynchronous and returns `202 Accepted` with `job_id`. - Final result is read from `GET /ingest/manual/csv/jobs/{id}`. ## Timeline - `GET /assets/{id}/timeline` - `GET /components/{id}/timeline` - These routes now return the same structured **timeline cards** contract as history timeline endpoints (breaking change accepted). ## History API - `GET /api/history/jobs/{id}` - `GET /api/history/components/{id}/events` - `GET /api/history/assets/{id}/events` - `POST /api/history/components/{id}/apply` - `POST /api/history/assets/{id}/apply` - `GET /api/history/components/{id}/timeline` - `GET /api/history/assets/{id}/timeline` - `GET /api/history/components/{id}/timeline/cards/{card_id}/events` - `GET /api/history/assets/{id}/timeline/cards/{card_id}/events` - `GET /api/history/components/{id}/events/{timeline_event_id}/detail` - `GET /api/history/assets/{id}/events/{timeline_event_id}/detail` - `DELETE /api/history/components/{id}/events/{event_id}` - `DELETE /api/history/assets/{id}/events/{event_id}` - `POST /api/history/components/{id}/rollback` - `POST /api/history/assets/{id}/rollback` History API invariants: - `POST /api/history/*/apply` uses semantic dedupe (no-op changes do not create events/snapshots/timeline rows). - Delete/rollback/hard-restore are asynchronous and return `202 Accepted` with `job_id`. - Timeline endpoints are grouped by day by default (`UTC`, optional `tz` override). - Timeline endpoints return **cards** (single/dedup/bulk), not raw rows. - Timeline supports server-side filters via query parameters: `date_from`, `date_to`, `action`, `source`, `device`, `slot`, `part_number` (mapped to model), `serial`. - Card drilldown endpoint (`.../timeline/cards/{card_id}/events`) accepts `tz` and must use the same timezone as the timeline cards response used to render the card. - `DELETE .../events/{event_id}` is soft-delete + recompute enqueue (not physical delete). - `POST .../rollback` supports `compensating` and `hard_restore` modes. ## Failures - `GET /failures` - `POST /failures` ## UI Routes - `GET /ui` - `GET /ui/search` - `GET /ui/assets` - `GET /ui/assets/{id}` - `GET /ui/components` - `GET /ui/components/{id}` - `GET /ui/failures` - `GET /ui/ingest` - `GET /ui/ingest/manual-template.csv` ## CSV Export Contract Route: `GET /ui/ingest/manual-template.csv` Rules: - Encoding: UTF-8. - UTF-8 BOM is included at file start for Excel compatibility. - Delimiter: `;`. - Line endings: `\r\n`. - Escaping: RFC4180-compatible (fields with `;`, `"`, `\n`, `\r` are quoted; inner `"` is doubled). - Header row is always present. - Stable column order (deterministic, no map-driven order). - Exported header order: - `дата_осмотра` - `серийный_номер_сервера` - `вендор` - `p/n_устройства` - `s/n_устройства` - `локейшн_в_сервере` - `версия_прошивки` - `состояние_оборудования` - Identifier-like columns are exported with Excel-safe text protection (to preserve leading zeros/codes). - Empty values are exported as empty cells (no `null`/`undefined`). - HTTP headers: - `Content-Type: text/csv; charset=utf-8` - `Content-Disposition: attachment; filename="manual-import-template.csv"` ## Routing Notes - API router is registered in `internal/api/server.go`. - Registry, ingest, failures, asset/component pages, and UI routes are attached to `http.ServeMux`. - History API routes and background history worker are also wired from `internal/api/server.go`.