ADORSYS-GIS / ADORSYS-GIS/converse-frontends
[Epic]: Backend contract alignment and dev fidelity
- Lingua principale
- TypeScript
- Stelle
- 0
- Fork
- 0
- Merge medio
- 1h 49m
- PR unite (30g)
- 253
Descrizione
## Executive Summary
We want the console's server-owned catalogs (models, group-by dimensions, billing plans-adjacent
enums) to come from the server, and the dev wiremock harness to fail the way production fails,
because right now the client hardcodes lists the backend owns and the fixtures were authored from
the client's own assumptions instead of from the schema. This epic exists to solve the reason every
Epic 1/2 data-integrity and broken-action defect passed local development undetected: dev and
production diverge, and the wiremock fixtures actively agree with bugs like `status === 'pending'`
instead of catching them.
## Strategic Intent
The intent of this epic is to remove every place the console guesses at a server-owned catalog
instead of asking for it, and to make the dev fixture harness derive from `authz.cstack` /
`openapi/usage.backend.yaml` rather than from the console's own code, so a schema drift or a client
bug shows up in `pnpm --filter console dev` before it ships.
## Problem Statement
Today: `MODEL_OPTIONS` in the Overview rail is a single hardcoded `all` entry even though
`listModelCatalog` exists specifically to back a real selector
(`apps/console/src/containers/use-overview-screen.ts:67`,
`packages/authz-rpc/schema/authz.cstack:598`); the `group-by` URL param offers `project | model`
while the usage backend's `UsageGroupBy` enum is
`account_id | project_id | api_key_id | user_id | user_name | model | metric_name | signal_type`
(`apps/console/src/client/url-state.ts:105`, `openapi/usage.backend.yaml:114`); and a missing
`budgetUrl` config silently falls back to `backendUrl` so a misconfiguration 404s identically to a
real outage (`apps/console/src/server/env.ts:173`, `apps/console/src/server/proxy-target.ts:45-48`).
Separately, the wiremock fixtures that stand in for the backend in dev were authored to match the
client's incorrect assumptions rather than the schema — `"status": "pending"` instead of
`pending_review` (`wiremock/mappings/console-budget.json:20,41`), no `listBillingPlans` stub, no
`total` in list responses so paging is never exercised — and the codec mismatch is worse still: the
real backend is CBOR-only (#256) while wiremock answers plain JSON, so **no console screen has ever
been exercised against fixture data through the real client codec path**
(`apps/console/README.md:402-406`). Impact on users: none directly (this epic is prevention, not a
user-facing fix). Impact on developers/operations: every defect in Epic 1 and Epic 2 shipped past
local dev and code review because dev could not have caught it — the fixtures agreed with the bugs.
Impact on business/compliance: repeated pattern of "worked in dev, wrong in prod" erodes confidence
in the console's own test/dev signal.
## Desired Outcome
Every catalog the server owns (models, group-by dimensions) is fetched, not guessed, in the client.
Misconfiguration (missing budget backend) is reported distinctly from a real outage. The wiremock
fixtures' shapes and enum values derive from `authz.cstack`/`openapi/usage.backend.yaml`, so the
Epic 1 defects (wrong status literal, decided-inside-pending, no billing-plan stub, no pagination
total) would fail against these fixtures instead of passing. The codec gap between dev fixtures and
the CBOR-only backend is either closed or explicitly documented as a known, bounded limitation — no
implied coverage that doesn't exist. Dead client surface with no live backend support — the
`projectMembers` resource and the PDF export toggle — is removed.
## Scope (In / Out)
### In Scope
- Model filter wired to `listModelCatalog`.
- `group-by` URL param mapped to the real `UsageGroupBy` enum (or a documented, deliberate URL
contract change per ADR 0011).
- Distinguishing "budget backend not configured" from a real outage.
- Rewriting wiremock fixtures from `authz.cstack`.
- Deciding and documenting the CBOR-vs-JSON dev harness gap.
- Deleting dead resources/toggles with no live backend support (`projectMembers`, PDF toggle).
- Confirming the optimistic-locking (`If-Match`/`etag`) path is exercised once an edit path exists.
### Out of Scope
- Building the usage dashboards themselves (Epic 4).
- Building the `listBillingPlans` selector UI (Epic 2, Story 2.1).
- The Expo app retirement (Epic 5).
- Backend/schema changes (Epic 6 — cross-team).
## Source of truth (links)
- Schema: https://github.com/ADORSYS-GIS/converse-frontends/blob/main/packages/authz-rpc/schema/authz.cstack
- Usage OpenAPI contract: https://github.com/ADORSYS-GIS/converse-frontends/blob/main/openapi/usage.backend.yaml
- ADR 0009 (Decision 3): https://github.com/ADORSYS-GIS/converse-frontends/blob/main/docs/adr/0009-nextjs-console-replacement.md
- Console dev-harness README (CBOR/wiremock gap): https://github.com/ADORSYS-GIS/converse-frontends/blob/main/apps/console/README.md
## Stakeholders
Product Owner / Technical Lead / Delivery Owner: @stephane-segning. Engineering Team: console
delivery engineers (4 advanced + 2 senior).
## Key Assumptions
- `listModelCatalog` and the usage backend's `UsageGroupBy` enum are stable contracts as documented
today in `authz.cstack` / `openapi/usage.backend.yaml`.
- Rewriting wiremock fixtures from the schema is sufficient to catch the class of defect found in
Epic 1, without requiring a full CBOR-fixture rewrite in the same pass (that trade-off is decided
explicitly in Story 3.2's CBOR ticket, not assumed here).
## Constraints
**Estimation model** (applies to every ticket in this epic): points are XS=1, S=2, M=3, L=5, XL=8,
where one point ≈ half a dev-day for an advanced engineer, including tests, the governance PR, and
review turnaround. Team: 4 advanced + 2 senior = 6 delivery engineers; the scrum master carries no
delivery points. At a 70% focus factor a 2-week sprint ≈ 48 points. Epic points are the sum of its
tickets' points; stories are containers that carry the rolled-up number.
Technical constraint: the real backend is CBOR-only (#256); any fixture rewrite must either speak
CBOR or explicitly document that it does not.
## Risks
| Risk | Probability | Impact | Mitigation |
| --- | --- | --- | --- |
| Rewriting wiremock fixtures without also closing the CBOR gap gives false confidence again | Medium | High | Story 3.2 ships both tickets together, and the CBOR ticket's AC requires an explicit documented statement of what dev does/does not prove |
| `group-by` URL contract change breaks existing deep links | Low | Medium | ADR 0011 treats param names as product surface; the ticket requires the choice (mapping layer vs. contract change) to be recorded, not silently shipped |
| Removing `projectMembers`/the PDF toggle turns out to be premature | Low | Low | Ticket AC allows "explicitly justified in code comments" as an alternative to deletion |
## Success metrics
| Metric | Current | Target | Source |
| ------ | ------- | ------ | ------ |
| Hardcoded server-owned catalog literals in `apps/console/src/containers/*` | 2 (`MODEL_OPTIONS`, `group-by` union) | 0 | Code search |
| Wiremock fixture stubs whose shape/enum values are verified against `authz.cstack` | 0 documented | 100% of stubs used by console screens | `wiremock/mappings/*.json` review against schema |
| Console screens exercised against fixture data through the real CBOR client path | 0 (documented gap) | Decision recorded: CBOR fixtures shipped, or explicit "does not prove" statement in README | `apps/console/README.md` |
| Dead resources/toggles with no live backend support | 2 (`projectMembers`, PDF toggle) | 0 (removed) | Code search |
## Child User Stories
- Story 3.1 — The client stops hardcoding server-owned catalogs (P1, 6 pts)
- Story 3.2 — Dev fixtures mirror the schema, not the client (P1, 8 pts)
- Story 3.3 — Remove dead surface (P2, 4 pts)
Epic 3 total: 18 points.
> [!NOTE]
> **Scope correction (2026-08-27).** An earlier revision of this epic counted
> `apps/console/src/app/api/usage/[...path]` as a third piece of "dead surface" to remove. It is
> not dead and is **not** being phased out: it is the console's only path to the usage backend
> (ADR 0009 Decision 3), and #304 is its first consumer. Counting a route as dead because it has
> no caller *yet* was a framing error in this epic, not a plan. Corrected here, in #316, and in
> `docs/knowledge/architecture.md`.
## Human accountable owner
@stephane-segning
## AI Usage Declaration
Ticket decomposition
## Human verification completed
- [ ] Intent checked against source of truth
- [ ] Scope reviewed by Product Owner
- [ ] Technical feasibility reviewed by Technical Lead
- [ ] Risks reviewed
- [ ] Acceptance criteria reviewed
- [ ] No unverified AI claim remains
- [ ] I am the accountable owner and accept responsibility for this epic.
Guida per i contributori
Apri la guida per i contributori
Valutazione
Questa issue non è ancora stata valutata.