implementation-plan
API-001: GET /v1/ingresses — Feature Breakdown
Existing Code Analysis
Current Architecture Patterns:
- Go service with Huma v2, net/http, Prometheus metrics
- Projection pattern fed by client-go informers
- Middleware-based bearer auth; readiness/health endpoints
Code Integration Points:
internal/projection: compute host/path view and reachabilityinternal/api: request handling, ETag, sorting, schema mappinginternal/auth,internal/metrics,internal/health,internal/server
Compatibility Requirements:
- Maintain spec contracts: API-001; FR-001, FR-002, FR-003, FR-004, FR-005, FR-006, FR-007, FR-008; AC-001, AC-002, AC-003, AC-004, AC-005, AC-006, AC-007, AC-008
- Sorting by (host, path); strong ETag; 401 on missing/invalid bearer
Goal
Provide the portal-focused list of hosts with nested paths at GET /v1/ingresses, including deterministic sorting and cache validation, secured by bearer auth.
Scope: implement handler, mapping, ETag, sorting, tests, and OpenAPI wiring. Out of scope: pagination, detail-by-name, active reachability probes.
Requirements
Traceability to Spec and Plan:
| Ref Type | IDs |
|---|---|
| Spec FR | FR-001, FR-002, FR-003, FR-004, FR-007, FR-008 |
| Spec NFR | NFR-001, NFR-002, NFR-005 |
| Spec API | API-001 |
| Spec AC | AC-001, AC-002, AC-003, AC-004, AC-005, AC-008 |
| Plan TASK | TASK-010, TASK-011, TASK-012, TASK-013, TASK-014, TASK-050 |
Detailed feature requirements:
- Return top-level hosts array with nested paths (ADR-0001)
- Sort hosts/paths by (host, path)
- Compute strong ETag; honour If-None-Match
- Serve OpenAPI and UI via Huma
- Enforce bearer auth on /v1/*
Technical Considerations
System Architecture Overview
flowchart LR
subgraph API Layer
H[Huma Handler: GET /v1/ingresses]
M[Auth Middleware]
end
subgraph Domain Layer
P[Projection: Hosts + Paths]
R[ETag Calculator]
end
subgraph Data Layer
I[(Informers: Ingress/Endpoints/EndpointSlice)]
end
subgraph Observability
X[http_requests_total, duration hist, projection_size]
end
M --> H --> P
P --> R
I --> P
H --> X
Technology Stack: Go 1.25; Huma v2; client-go v0.34.x; Prometheus client_golang 1.23.x.
Integration Points: functions in internal/projection exposed to internal/api handler; ETag from projection resourceVersions map.
Deployment: no changes beyond standard deployment manifests.
Scalability: O(hosts) sort (and per-host O(paths)); informer-backed cache; low CPU.
API Design
- Endpoint: GET /v1/ingresses (API-001)
- Auth: Authorization: Bearer KEY
- Responses: 200 (HostsList), 304, 401, 500; headers: ETag, Cache-Control
Security & Performance
- Do not log secrets; measure p50/p99; ensure caching works via ETag (SEC-002, NFR-001, NFR-002)
– Work Items (Executable Tasks)
| ID | Title | Description | Files/Modules/Functions | Existing Code Integration | Traceability (Spec IDs) | Plan TASK IDs | AC IDs | Estimate | Dependencies | Owner | Status |
|---|---|---|---|---|---|---|---|---|---|---|---|
| WI-001 | Projection hosts view | Emit hosts[] with nested paths | internal/projection/projection.go | Extend projection | FR-001, FR-008 | TASK-010 | AC-001, AC-002 | 1d | @ | Completed | |
| WI-002 | Deterministic sorting | Sort by (host, path) | internal/projection/projection.go | Enhance list builder | FR-008 | TASK-011 | AC-002 | 0.5d | WI-001 | @ | Completed |
| WI-003 | API mapping schema | Map projection to response | internal/api/ingress_handler.go | Update handler | API-001, FR-001 | TASK-012 | AC-001 | 1d | WI-001 | @ | Completed |
| WI-004 | ETag + 304 logic | Compute ETag; honour If-None-Match | internal/api/ingress_handler.go | Extend handler | FR-002, FR-003 | TASK-013 | AC-003, AC-004 | 0.5d | WI-003 | @ | Completed |
| WI-005 | OpenAPI schema parity | Ensure OpenAPI matches HostsList | internal/api/huma_routes.go | Huma operation | FR-007 | TASK-014, TASK-050 | AC-008 | 0.5d | WI-003 | @ | Completed |
| WI-006 | Auth guard | Enforce bearer on /v1/* | internal/auth/middleware.go | Reuse middleware | FR-004 | TASK-020 | AC-005 | 0.5d | @ | Completed |
Definition of Done per WI includes unit tests and handler-level validation.
Tests
| ID | Type | Scope | Files | ACs | WIs |
|---|---|---|---|---|---|
| T-001 | Unit | Projection ETag and sort | internal/projection/projection_test.go | AC-002, AC-003 | WI-001, WI-002 |
| T-002 | Unit | Handler ETag/304 | internal/api/ingress_handler_test.go | AC-003, AC-004 | WI-004 |
| T-005 | Unit | Sorting helper | internal/api/sort_test.go | AC-002 | WI-002 |
| T-006 | Unit | Snapshot→HostsList mapping | internal/api/mapper_test.go | AC-001 | WI-003 |
| T-003 | Unit | Auth 401 | internal/auth/middleware_test.go | AC-005 | WI-006 |
| T-004 | Unit | OpenAPI served | internal/api/openapi_test.go | AC-008 | WI-005 |
Documentation Work Items
| ID | Type | Description | Files/Location | Spec DOC IDs | ACs | WIs |
|---|---|---|---|---|---|---|
| DOC-WI-001 | Reference | Update API reference with HostsList schema | docs/reference/ | DOC-003 | AC-008 | WI-005 |
Risks & Assumptions
- RISK-001: Sort instability could break ETag cache; mitigate with explicit sort and tests.
- ASM-001: No pagination required in MVP.
Quality Gates
- Build/test pass; unit tests green; smoke test GET /v1/ingresses returns 200 and schema-valid body when authorized.
Technology Stack (from Spec)
| Area | Selection | Version/Target |
|---|---|---|
| Language | Go | 1.25 |
| API framework | Huma v2 | v2.x |
| K8s client | client-go | v0.34.x |
| Metrics | Prometheus client_golang | 1.23.x |
Traceability Index
| Type | IDs |
|---|---|
| Spec | FR-001, FR-002, FR-003, FR-004, FR-007, FR-008, API-001, AC-001, AC-002, AC-003, AC-004, AC-005, AC-008 |
| Plan | TASK-010, TASK-011, TASK-012, TASK-013, TASK-014, TASK-020, TASK-050 |
| Breakdown | WI-001, WI-002, WI-003, WI-004, WI-005, T-001, T-002, T-003, T-004, DOC-WI-001 |
Progress
- 2025-09-15 — WI-001 Completed: initial hosts[] scaffolding via projection events; ETag unaffected. Files:
internal/projection/projection.go(no schema change; event insert/replace supports later mapping). Tests: existing ETag test covers changes. - 2025-09-15 — WI-002 Completed: deterministic sorting helper for hosts and paths. Files:
internal/api/sort.go. Tests:internal/api/sort_test.goadded and passing. - 2025-09-15 — WI-003 Completed: handler maps snapshot→HostsList with defensive merge; uses sorting; preserves ETag/304. Files:
internal/api/mapper.go,internal/api/mapper_test.go,internal/api/ingress_handler.go. - 2025-09-16 — WI-004 Completed: implemented strong ETag and If-None-Match 304 logic in list handler. Files:
internal/api/ingress_handler.go. Tests:internal/api/ingress_handler_test.go(TestListIngressesHandler_ETag) passing. Result: AC-003, AC-004 satisfied; TASK-013 aligned. - 2025-09-16 — WI-005 Completed: wired Huma v2 to serve OpenAPI and UI; registered list operation for schema parity. Files:
internal/api/huma_routes.go,internal/server/server.go. Tests:internal/api/openapi_test.goverifies /openapi.json includes /v1/ingresses. Result: AC-008 satisfied; TASK-014, TASK-050 aligned. - 2025-09-16 — WI-006 Completed: enforced bearer auth on /v1/* (ingresses) and validated with server-level test. Files:
internal/auth/middleware.go,internal/server/server.go,internal/server/server_auth_test.go. Result: AC-005 satisfied; TASK-020 aligned. - 2025-09-16 — DOC-WI-001 Completed: added API reference for API-001 with example and headers. Files:
docs/reference/api-001-ingresses-list.md. Result: AC-008 documentation present; DOC-003 aligned.