mirror of
https://github.com/azaion/ui.git
synced 2026-06-21 09:51:11 +00:00
[AZ-485] [AZ-486] Phase B Step 9: F4 barrels + F7 endpoints task specs
ci/woodpecker/push/build-arm Pipeline was successful
ci/woodpecker/push/build-arm Pipeline was successful
Closes Step 9 New Task cycle 1. Two refactor tasks created under epic AZ-447 to address architecture compliance baseline findings: - AZ-485 (5 pts) — F4 Public API barrels per component + STC-ARCH-01 - AZ-486 (5 pts) — F7 endpoint builders (endpoints.ts) + STC-ARCH-02 (depends on AZ-485; Jira "Blocks" link set) F1 (mission-planner duplication) deliberately deferred. Baseline routes it through 7+ Phase B port-group cycles requiring decompose pass into its own Epic; out of scope for new-task. _autodev_state.md advances to Step 10 (Implement), awaiting invocation for AZ-485 first. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -11,13 +11,18 @@
|
|||||||
| AZ-452 | C05 — `getApiBase()` accessor | AZ-447 | 3 | None |
|
| AZ-452 | C05 — `getApiBase()` accessor | AZ-447 | 3 | None |
|
||||||
| AZ-453 | C06 — `navigateToLoginImpl()` accessor | AZ-447 | 2 | None |
|
| AZ-453 | C06 — `navigateToLoginImpl()` accessor | AZ-447 | 2 | None |
|
||||||
| AZ-454 | C07 — Document `setToken/getToken` | AZ-447 | 1 | None |
|
| AZ-454 | C07 — Document `setToken/getToken` | AZ-447 | 1 | None |
|
||||||
|
| AZ-485 | C08 (Phase B) — Public API barrels + STC-ARCH-01 | AZ-447 | 5 | None |
|
||||||
|
| AZ-486 | C09 (Phase B) — Endpoint builders (endpoints.ts) + STC-ARCH-02 | AZ-447 | 5 | AZ-485 |
|
||||||
|
|
||||||
### Notes (AZ-447)
|
### Notes (AZ-447)
|
||||||
|
|
||||||
- Epic AZ-447 is the umbrella for the autodev existing-code Step 4 testability run (`01-testability-refactoring`).
|
- Epic AZ-447 is the umbrella for the autodev existing-code Step 4 testability run (`01-testability-refactoring`).
|
||||||
- AZ-448 and AZ-449 share `src/features/flights/flightPlanUtils.ts` and should land in one commit to avoid a mid-state where the URL still hardcodes a base while the key is externalized.
|
- AZ-448 and AZ-449 share `src/features/flights/flightPlanUtils.ts` and should land in one commit to avoid a mid-state where the URL still hardcodes a base while the key is externalized.
|
||||||
- Total: 14 complexity points across 7 tasks. **Status: closed** — all tasks done (see `_docs/04_refactoring/01-testability-refactoring/FINAL_report.md`).
|
- C01–C07 (AZ-448 … AZ-454) totalled 14 complexity points; closed in Phase A (see `_docs/04_refactoring/01-testability-refactoring/FINAL_report.md`).
|
||||||
- Every task fit the existing-code flow Step 4 allowed-change list (externalize hardcoded URLs/credentials, wrap globals in thin accessors, comment-only documentation). Deferred items are in `_docs/04_refactoring/01-testability-refactoring/deferred_to_refactor.md`.
|
- C08 (AZ-485) and C09 (AZ-486) are Phase B additions covering architecture baseline findings **F4** and **F7** — the two High/Medium baseline findings the Step 4 batch deferred. They share AZ-447 because they are mechanical testability refactors of the same shape; total 10 additional complexity points across the two tasks.
|
||||||
|
- AZ-486 depends on AZ-485 — `endpoints` ships through the `src/api` barrel introduced by AZ-485, and a "Blocks" link is set in Jira.
|
||||||
|
- **F1** (mission-planner duplication, Critical) is deliberately NOT in this epic. Per baseline routing it requires 7+ port-group Phase B feature cycles; it will be decomposed in a separate `/decompose` session and own its own Epic.
|
||||||
|
- Deferred Step 4 items remain in `_docs/04_refactoring/01-testability-refactoring/deferred_to_refactor.md` for traceability.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
# Public API barrels per component + deep-import migration
|
||||||
|
|
||||||
|
**Task**: AZ-485_refactor_public_api_barrels
|
||||||
|
**Name**: Add Public API barrels and migrate cross-component imports
|
||||||
|
**Description**: Introduce `index.ts` barrels for every component, narrow each component's Public API to the symbols listed in `module-layout.md`, replace every cross-component deep import with a barrel import, and add a static check that flags future deep imports. Closes architecture baseline finding **F4**.
|
||||||
|
**Complexity**: 5 points
|
||||||
|
**Dependencies**: None
|
||||||
|
**Component**: cross-cutting (00–10) — coordinated edit across `src/api/`, `src/auth/`, `src/components/`, `src/features/**/`, `src/hooks/`, `src/i18n/`, `src/App.tsx`, plus every test importer
|
||||||
|
**Tracker**: AZ-485
|
||||||
|
**Epic**: AZ-447
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
`_docs/02_document/architecture_compliance_baseline.md` Finding **F4** (High / Architecture): no component currently exposes a barrel `index.ts` (the sole barrel today is `src/types/index.ts`, owned by `00_foundation`). Cross-component imports use file-name granularity (`import { api } from '../api/client'`, `import { useFlight } from '../components/FlightContext'`, …). Consequence:
|
||||||
|
|
||||||
|
1. There is no enforceable Public API surface — every internal file is de-facto public.
|
||||||
|
2. Any internal split / rename inside a component is a breaking change to ~10 importers.
|
||||||
|
3. Phase 7 architecture compliance ("Public API respect") cannot fail in this codebase because everything is public.
|
||||||
|
4. The next time `module-layout.md` flags a Public-API drift, no static gate exists to catch it.
|
||||||
|
|
||||||
|
`module-layout.md` Layout Rules #3 records the same observation and lists this as a Step 4 testability candidate; Step 4 deferred it to Phase B (`_autodev_state.md::step_2_baseline_routing: per-finding-recommended`).
|
||||||
|
|
||||||
|
## Outcome
|
||||||
|
|
||||||
|
- Every component listed in `module-layout.md`'s "Per-Component Mapping" exposes its Public API through a barrel `index.ts` at the component root (10 new files; `src/types/index.ts` is unchanged).
|
||||||
|
- Every cross-component import in `src/**` and `tests/**` resolves through a component barrel — no remaining deep imports of another component's internal files. `mission-planner/**` is exempt (untouched per F1's deferred convergence plan).
|
||||||
|
- A static check (added to `scripts/run-tests.sh`) fails the static profile if any new `src/**` or `tests/**` file imports a non-barrel path from another component.
|
||||||
|
- `_docs/02_document/module-layout.md` Layout Rules #3 is rewritten to describe the post-change state ("Each component exposes its Public API via `src/<component>/index.ts`. Cross-component imports MUST use the barrel. The static gate `STC-ARCH-01` enforces this.").
|
||||||
|
- All existing fast + static profiles remain green after the migration.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
### Included
|
||||||
|
- Create 10 new barrels (`src/api/index.ts`, `src/auth/index.ts`, `src/components/index.ts`, `src/features/{login,flights,annotations,dataset,admin,settings}/index.ts`, `src/hooks/index.ts`, `src/i18n/index.ts`). Each barrel re-exports ONLY the symbols listed for that component in `module-layout.md`'s "Per-Component Mapping" → "Public API (de-facto)".
|
||||||
|
- Replace every cross-component deep import (~30 sites across `src/App.tsx`, every feature page that imports from another component, and every `tests/**` and colocated `*.test.tsx` that imports a production symbol from another component) with a barrel import.
|
||||||
|
- Add a new static check `STC-ARCH-01` to `scripts/run-tests.sh` that fails the static profile if any `src/**` or `tests/**` file (excluding the barrel itself, `mission-planner/**`, and intra-component imports) imports a non-barrel path from a different component.
|
||||||
|
- Update `_docs/02_document/module-layout.md` Layout Rules #3 to reflect the post-change state and add `STC-ARCH-01` to the Static Checks inventory (if such a list exists; otherwise document inline).
|
||||||
|
|
||||||
|
### Excluded
|
||||||
|
- `src/types/index.ts` is already a barrel — left unchanged.
|
||||||
|
- `mission-planner/**` — untouched (F1's deferred convergence plan; will be deleted in the final Phase B port cycle per the baseline).
|
||||||
|
- F2 (`07_dataset → 06_annotations` cross-feature edge for `CanvasEditor`) — `CanvasEditor` STAYS in the `06_annotations` barrel's Public API list (the cross-feature edge is grandfathered in `module-layout.md` and is closed by F2, not F4).
|
||||||
|
- F3 (`classColors.ts` physical/logical owner split) — the file remains physically under `src/features/annotations/`; F4 lists it in the `06_annotations` barrel for now. Physical move is F3's own task.
|
||||||
|
- New runtime behavior — this is a structural refactor only.
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
**AC-1: Every component has a barrel exposing only its Public API**
|
||||||
|
Given the post-change repo,
|
||||||
|
When `src/<component>/index.ts` is read for every component listed in `module-layout.md`,
|
||||||
|
Then the file exists, every named export matches a symbol in that component's "Public API (de-facto)" line in `module-layout.md`, and no internal-only file's symbol is re-exported.
|
||||||
|
|
||||||
|
**AC-2: No cross-component deep imports remain in production code**
|
||||||
|
Given the post-change repo,
|
||||||
|
When `ripgrep "^(import|export).*from\s+['\"]\.\.\/[a-z][^'\"]*\/[A-Za-z][^'\"]+['\"]" src/` is run, excluding intra-component paths (paths that resolve to the same component's owned directory),
|
||||||
|
Then no match is found.
|
||||||
|
|
||||||
|
**AC-3: No cross-component deep imports remain in tests**
|
||||||
|
Given the post-change repo,
|
||||||
|
When the same ripgrep is run across `tests/**`, `e2e/**`, and colocated `**/*.test.{ts,tsx}` files,
|
||||||
|
Then no match is found OUTSIDE the documented testability exemptions in `module-layout.md` "Blackbox Tests" entry (test infrastructure may import testability accessors like `setToken`, `setNavigateToLogin`, `AuthProvider`, and i18n directly per the existing exemption — those continue to use barrel paths now that the barrels re-export them).
|
||||||
|
|
||||||
|
**AC-4: Static gate STC-ARCH-01 fails on a newly-introduced deep import**
|
||||||
|
Given the post-change static profile,
|
||||||
|
When a synthetic test file is added that imports `'../api/client'` instead of `'../api'` (or equivalent for another component),
|
||||||
|
Then `bash scripts/run-tests.sh --static` exits non-zero with `STC-ARCH-01` named in the failure line.
|
||||||
|
|
||||||
|
**AC-5: Static gate STC-ARCH-01 passes on the migrated codebase**
|
||||||
|
Given the post-change repo,
|
||||||
|
When `bash scripts/run-tests.sh --static` runs,
|
||||||
|
Then it exits zero and the static report shows `STC-ARCH-01` as PASS.
|
||||||
|
|
||||||
|
**AC-6: Fast profile remains green**
|
||||||
|
Given the post-change repo,
|
||||||
|
When `bash scripts/run-tests.sh --fast` runs,
|
||||||
|
Then it reports the same PASS / SKIP / FAIL counts as the pre-change baseline (163 PASS / 13 SKIP / 0 FAIL per `_docs/03_implementation/test_run_report.md`), with zero new failures and zero regressions in skip-classification.
|
||||||
|
|
||||||
|
**AC-7: module-layout.md reflects the new convention**
|
||||||
|
Given the post-change repo,
|
||||||
|
When `_docs/02_document/module-layout.md` Layout Rules #3 is read,
|
||||||
|
Then it states "Each component exposes its Public API via `src/<component>/index.ts`. Cross-component imports MUST use the barrel. The static gate `STC-ARCH-01` enforces this." and the Verification Needed item referencing the missing barrels is removed (or marked closed by this task's tracker ID).
|
||||||
|
|
||||||
|
## Non-Functional Requirements
|
||||||
|
|
||||||
|
**Performance**
|
||||||
|
- Initial JS bundle gzipped size MUST remain ≤ 2 MB (existing `STC-PERF01`). Barrel re-exports tree-shake under Vite's production rollup, so no regression expected.
|
||||||
|
|
||||||
|
**Compatibility**
|
||||||
|
- No runtime behavior change. The fast + e2e suites are the contract; both stay green.
|
||||||
|
|
||||||
|
**Maintainability**
|
||||||
|
- Future internal renames inside a component MUST not require import-path edits outside that component (validated by AC-2/AC-3 + STC-ARCH-01).
|
||||||
|
|
||||||
|
## Unit Tests
|
||||||
|
|
||||||
|
| AC Ref | What to Test | Required Outcome |
|
||||||
|
|--------|--------------|------------------|
|
||||||
|
| AC-1 | Each barrel file re-exports only documented symbols | Re-export list matches `module-layout.md`'s Public API line for that component (test reads both files and compares) |
|
||||||
|
| AC-4 | Synthetic deep-import detection | `STC-ARCH-01` fails when a fixture file with a deep import is added |
|
||||||
|
| AC-5 | Static check on the real codebase | `STC-ARCH-01` passes |
|
||||||
|
|
||||||
|
## Blackbox Tests
|
||||||
|
|
||||||
|
| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References |
|
||||||
|
|--------|-------------------------|--------------|-------------------|----------------|
|
||||||
|
| AC-2 | Repo after migration | `ripgrep` for cross-component deep imports in `src/` | Zero matches | Maintainability |
|
||||||
|
| AC-3 | Repo after migration | `ripgrep` for cross-component deep imports in `tests/`, `e2e/`, colocated tests | Zero matches outside documented exemptions | Maintainability |
|
||||||
|
| AC-6 | Fast profile | `scripts/run-tests.sh --fast` | 163 PASS / 13 SKIP / 0 FAIL (matches `_docs/03_implementation/test_run_report.md`) | Compat |
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
|
||||||
|
- All 10 barrels + import migration + static check MUST land in ONE commit to keep mid-state green (partial migration breaks the static gate on intermediate commits). If commit size is impractical, split per-component but always under one PR atomic to merge.
|
||||||
|
- The barrel files are OWNED by each respective component (e.g. `src/api/index.ts` is OWNED by `01_api-transport` tasks); the static check addition to `scripts/run-tests.sh` is OWNED by `Blackbox Tests` per `module-layout.md`.
|
||||||
|
- No new dependencies. The static check uses `ripgrep` (already used elsewhere in `scripts/run-tests.sh`).
|
||||||
|
- `mission-planner/**` MUST be untouched.
|
||||||
|
|
||||||
|
## Risks & Mitigation
|
||||||
|
|
||||||
|
**Risk 1: A cohort import-path edit misses a transitive import path → fast suite goes red on TypeScript "module not found"**
|
||||||
|
- *Risk*: ~30 import statements across many files; mechanical edit can miss one.
|
||||||
|
- *Mitigation*: Run `bun tsc -b --noEmit` (or the project's `lint:tests` script) after every per-component batch; commit only when type-check is green. AC-6 (full fast profile) is the final gate.
|
||||||
|
|
||||||
|
**Risk 2: Vite tree-shaking regression — barrel re-exports drag in optional sub-modules**
|
||||||
|
- *Risk*: A barrel that re-exports rarely-used symbols can defeat tree-shaking and inflate the bundle.
|
||||||
|
- *Mitigation*: STC-PERF01 already caps gzipped bundle at 2 MB and runs in the static profile. The migration must keep that gate green. If bundle regresses, split the barrel into eager + lazy re-export blocks per Vite's recommendations.
|
||||||
|
|
||||||
|
**Risk 3: `CanvasEditor` cross-feature edge (F2) confuses the static check**
|
||||||
|
- *Risk*: `src/features/dataset/DatasetPage.tsx` legitimately imports `CanvasEditor` from `src/features/annotations/`. STC-ARCH-01 must allow this when it goes through the `06_annotations` barrel but flag the legacy direct path.
|
||||||
|
- *Mitigation*: After migration, the dataset import becomes `import { CanvasEditor } from '../annotations'` — passes the barrel-path check. F2's eventual `CanvasEditor` lift is independent of this task.
|
||||||
|
|
||||||
|
## Contract
|
||||||
|
|
||||||
|
This task produces the Public API contract for 10 components — the barrel re-export lists ARE the contract. The contract surface for each component is documented inline at `_docs/02_document/module-layout.md` "Per-Component Mapping" → "Public API (de-facto)"; this task does not create a new contract file but DOES update Layout Rules #3 to declare the barrel files as the canonical Public API surface (no longer "de-facto").
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
# Endpoint builders — replace hardcoded `/api/<service>/...` strings
|
||||||
|
|
||||||
|
**Task**: AZ-486_refactor_endpoint_builders
|
||||||
|
**Name**: Introduce `endpoints.ts` and replace hardcoded API paths
|
||||||
|
**Description**: Add `src/api/endpoints.ts` exporting typed endpoint builders, replace every hardcoded `/api/<service>/...` string literal in production code with the corresponding builder call, and add a static check that flags new string literals. Closes architecture baseline finding **F7**.
|
||||||
|
**Complexity**: 5 points
|
||||||
|
**Dependencies**: AZ-485_refactor_public_api_barrels (F4 lands first so `endpoints` ships through the `src/api` barrel)
|
||||||
|
**Component**: `01_api-transport` (owner of new file + barrel re-export) + every component that calls `api.*` or `createSSE`: `02_auth`, `03_shared-ui`, `06_annotations`, `07_dataset`, `08_admin`, `09_settings`, `05_flights`
|
||||||
|
**Tracker**: AZ-486
|
||||||
|
**Epic**: AZ-447
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
`_docs/02_document/architecture_compliance_baseline.md` Finding **F7** (Medium / Architecture): every `api.*()` and `createSSE()` callsite repeats `/api/<service>/<path>` as a string literal. ~25 hardcoded paths across 11 source files (`src/auth/AuthContext.tsx`, `src/api/client.ts`, `src/features/{admin,settings,annotations,dataset,flights}/**`, `src/components/{FlightContext,DetectionClasses}.tsx`).
|
||||||
|
|
||||||
|
Consequences (per ADR-006 Consequences and the baseline doc):
|
||||||
|
1. Every test fixture must duplicate paths — and MSW handlers, e2e stubs, and unit tests all drift independently.
|
||||||
|
2. Any nginx-route rename (ADR-006 prefix-strip changes) touches every feature.
|
||||||
|
3. There is no single source of truth for the wire-contract paths.
|
||||||
|
|
||||||
|
`module-layout.md` Verification Needed item references the same observation. Step 4 (testability) deferred this finding to Phase B per the per-finding routing decision.
|
||||||
|
|
||||||
|
## Outcome
|
||||||
|
|
||||||
|
- A new module `src/api/endpoints.ts` exports a typed `endpoints` object with function-form builders for every path in use today.
|
||||||
|
- Every callsite of `api.get/post/put/upload/del` and `subscribeSSE`/`createSSE` across `src/**` (excluding `src/api/endpoints.ts` itself and test files) uses an `endpoints.*` call — no string literals matching `/api/<service>/` remain in production code.
|
||||||
|
- The `endpoints` symbol is re-exported from `src/api/index.ts` (the F4 barrel).
|
||||||
|
- A new static check `STC-ARCH-02` fails the static profile if any production file (excluding `endpoints.ts`, tests, and MSW handlers) contains a string literal matching `/api/<service>/`.
|
||||||
|
- Unit tests assert each builder returns the contract-correct URL string.
|
||||||
|
- MSW handlers and e2e stubs continue to match the exact same URLs — no wire-contract change.
|
||||||
|
- `_docs/02_document/module-layout.md` adds `endpoints.ts` to the `01_api-transport` Public API and adds `STC-ARCH-02` to the static-check inventory.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
### Included
|
||||||
|
- New file `src/api/endpoints.ts` with the `endpoints` object — function form everywhere, e.g.:
|
||||||
|
- `endpoints.admin.authRefresh()` → `'/api/admin/auth/refresh'`
|
||||||
|
- `endpoints.admin.users()` → `'/api/admin/users'`
|
||||||
|
- `endpoints.admin.user(id)` → `` `/api/admin/users/${id}` ``
|
||||||
|
- `endpoints.flights.aircrafts()` → `'/api/flights/aircrafts'`
|
||||||
|
- `endpoints.flights.liveGps(flightId)` → `` `/api/flights/${flightId}/live-gps` ``
|
||||||
|
- `endpoints.annotations.classes()`, `endpoints.annotations.annotations()`, `endpoints.annotations.dataset()`, `endpoints.annotations.datasetBulkStatus()`, `endpoints.annotations.datasetClassDistribution()`, `endpoints.annotations.mediaBatch()`, `endpoints.annotations.settingsSystem()`, `endpoints.annotations.settingsDirectories()`, `endpoints.annotations.settingsUser()`, `endpoints.annotations.detection(query?)`, …
|
||||||
|
- Update `src/api/index.ts` (barrel from F4) to re-export `endpoints`.
|
||||||
|
- Replace ~25 hardcoded path literals in:
|
||||||
|
- `src/auth/AuthContext.tsx`
|
||||||
|
- `src/api/client.ts` (the refresh callsite)
|
||||||
|
- `src/features/admin/AdminPage.tsx`
|
||||||
|
- `src/features/settings/SettingsPage.tsx`
|
||||||
|
- `src/features/annotations/AnnotationsPage.tsx`
|
||||||
|
- `src/features/annotations/AnnotationsSidebar.tsx`
|
||||||
|
- `src/features/annotations/MediaList.tsx`
|
||||||
|
- `src/features/dataset/DatasetPage.tsx`
|
||||||
|
- `src/features/flights/FlightsPage.tsx`
|
||||||
|
- `src/components/FlightContext.tsx`
|
||||||
|
- `src/components/DetectionClasses.tsx`
|
||||||
|
- Add unit tests in `src/api/endpoints.test.ts` (one assertion per builder verifying the literal URL string — the test file IS the contract).
|
||||||
|
- Add static check `STC-ARCH-02` to `scripts/run-tests.sh` (ripgrep `'/api/[a-z-]+/'` across `src/**` excluding `endpoints.ts` and `*.test.{ts,tsx}` and `tests/**`).
|
||||||
|
- Update `_docs/02_document/module-layout.md` `01_api-transport` row to add `endpoints` to Public API and add `STC-ARCH-02` to the static-check inventory.
|
||||||
|
|
||||||
|
### Excluded
|
||||||
|
- F6 (introduce `src/shared/`) — `endpoints.ts` lives at `src/api/endpoints.ts` for now (under `01_api-transport`). When/if F6 lands later it can move to `src/shared/endpoints.ts` with no callsite change (barrel insulates callers).
|
||||||
|
- The base URL itself (`/api`) — `getApiBase()` already exists in `src/api/client.ts` and is handled separately. `endpoints.ts` returns paths starting with `/api/`; the client prepends the base.
|
||||||
|
- Tests and MSW handlers — tests CAN use `endpoints.*` for readability, but their hardcoded paths are not in scope of this task's deletion sweep. The static check explicitly exempts test paths.
|
||||||
|
- `mission-planner/**` — untouched (deferred per F1).
|
||||||
|
- Any change to wire-contract paths. The literal URL strings produced by builders MUST exactly match the strings currently in code (and exactly match what MSW/e2e stubs intercept today).
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
**AC-1: All current paths have builders**
|
||||||
|
Given the post-change `src/api/endpoints.ts`,
|
||||||
|
When the unit test enumerates every builder and asserts the produced URL,
|
||||||
|
Then every URL currently in source (per the F7 inventory above) is reproduced exactly — character-identical to today's literal.
|
||||||
|
|
||||||
|
**AC-2: No hardcoded `/api/<service>/` literals remain in production**
|
||||||
|
Given the post-change repo,
|
||||||
|
When `ripgrep "'/api/[a-z-]+/"` runs over `src/**` excluding `src/api/endpoints.ts`, `**/*.test.{ts,tsx}`, and `tests/**`,
|
||||||
|
Then zero matches are found.
|
||||||
|
|
||||||
|
**AC-3: Static gate STC-ARCH-02 fails on a synthetic literal**
|
||||||
|
Given the post-change static profile,
|
||||||
|
When a synthetic edit reintroduces `await api.get('/api/admin/users/me')` to any production file,
|
||||||
|
Then `bash scripts/run-tests.sh --static` exits non-zero with `STC-ARCH-02` named in the failure line.
|
||||||
|
|
||||||
|
**AC-4: Static gate STC-ARCH-02 passes on the migrated codebase**
|
||||||
|
Given the post-change repo,
|
||||||
|
When `bash scripts/run-tests.sh --static` runs,
|
||||||
|
Then it exits zero and the static report shows `STC-ARCH-02` as PASS.
|
||||||
|
|
||||||
|
**AC-5: Fast profile remains green**
|
||||||
|
Given the post-change repo,
|
||||||
|
When `bash scripts/run-tests.sh --fast` runs,
|
||||||
|
Then it reports the same PASS / SKIP / FAIL counts as the pre-change baseline (163 PASS / 13 SKIP / 0 FAIL plus the new `endpoints.test.ts` PASSes) with zero new failures and zero regressions.
|
||||||
|
|
||||||
|
**AC-6: Endpoint builders are exposed through the F4 barrel**
|
||||||
|
Given the post-change repo,
|
||||||
|
When any production file imports `{ endpoints }` from `'../api'` (or relative equivalent),
|
||||||
|
Then the import resolves through `src/api/index.ts` and `endpoints` is the typed object defined in `src/api/endpoints.ts`.
|
||||||
|
|
||||||
|
**AC-7: MSW handlers and e2e stubs continue to match**
|
||||||
|
Given the post-change repo,
|
||||||
|
When the fast and (deferred-but-runnable) e2e profiles run,
|
||||||
|
Then every MSW intercept hits its target unchanged — no "intercepted a request without a matching request handler" error appears, confirming character-identical URLs.
|
||||||
|
|
||||||
|
## Non-Functional Requirements
|
||||||
|
|
||||||
|
**Performance**
|
||||||
|
- Initial JS bundle gzipped size MUST remain ≤ 2 MB (existing `STC-PERF01`). The `endpoints` object is tree-shakeable per builder; impact ≤ 1 KB.
|
||||||
|
|
||||||
|
**Maintainability**
|
||||||
|
- A nginx-route rename (per ADR-006) requires editing one file (`endpoints.ts`) — validated by AC-2.
|
||||||
|
|
||||||
|
**Compatibility**
|
||||||
|
- Zero wire-contract change (validated by AC-1 character-equality + AC-7 MSW + e2e).
|
||||||
|
|
||||||
|
## Unit Tests
|
||||||
|
|
||||||
|
| AC Ref | What to Test | Required Outcome |
|
||||||
|
|--------|--------------|------------------|
|
||||||
|
| AC-1 | Every builder produces the contract-correct URL string | `endpoints.admin.authRefresh()` === `'/api/admin/auth/refresh'`; same for every builder, character-identical |
|
||||||
|
| AC-1 | Builders that take params interpolate correctly | `endpoints.admin.user('abc')` === `'/api/admin/users/abc'` |
|
||||||
|
| AC-3 | STC-ARCH-02 fails on synthetic deep-literal | Static profile non-zero, error names `STC-ARCH-02` |
|
||||||
|
| AC-4 | STC-ARCH-02 passes on migrated codebase | Static profile zero, STC-ARCH-02 PASS row |
|
||||||
|
| AC-6 | `endpoints` is re-exported from `src/api/index.ts` | `import { endpoints } from 'src/api'` resolves; the imported value is identical to the one in `src/api/endpoints.ts` |
|
||||||
|
|
||||||
|
## Blackbox Tests
|
||||||
|
|
||||||
|
| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References |
|
||||||
|
|--------|-------------------------|--------------|-------------------|----------------|
|
||||||
|
| AC-2 | Repo after migration | `ripgrep "'/api/[a-z-]+/"` over `src/` minus exemptions | Zero matches | Maintainability |
|
||||||
|
| AC-5 | Fast profile | `scripts/run-tests.sh --fast` | 163 PASS + new `endpoints.test.ts` PASSes / 13 SKIP / 0 FAIL | Compat |
|
||||||
|
| AC-7 | Fast profile | MSW unhandled-request gate | No "intercepted a request without a matching request handler" errors | Compat |
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
|
||||||
|
- Lands AFTER 01_refactor_public_api_barrels (F4). The `endpoints` symbol is re-exported from `src/api/index.ts` (the barrel); without F4, callsites would deep-import from `src/api/endpoints` and reintroduce the F4 violation.
|
||||||
|
- The literal URLs produced by builders MUST be character-identical to today's literals. AC-1 validates this in unit tests; AC-7 validates it against MSW handlers; the (deferred) e2e profile validates it against the suite-e2e nginx routes.
|
||||||
|
- All changes land in ONE commit (the static check would otherwise fail on intermediate commits).
|
||||||
|
- `mission-planner/**` MUST be untouched.
|
||||||
|
|
||||||
|
## Risks & Mitigation
|
||||||
|
|
||||||
|
**Risk 1: A path literal is missed and remains in source**
|
||||||
|
- *Risk*: 25 sites is enough for a manual edit to miss one. The miss would not show up in fast tests (MSW intercepts both styles); STC-ARCH-02 is the only gate that catches it.
|
||||||
|
- *Mitigation*: STC-ARCH-02 is the SINGLE source of truth for "no literals remain". The static profile is run BEFORE commit; commit is blocked if STC-ARCH-02 fails.
|
||||||
|
|
||||||
|
**Risk 2: An optional query-string param is missed in the builder API**
|
||||||
|
- *Risk*: e.g. `endpoints.annotations.detection()` may need to accept an optional `imageId` query string; missing the param forces the caller back to string concatenation, defeating the abstraction.
|
||||||
|
- *Mitigation*: Inventory the existing callsites BEFORE writing builders. Every callsite's full URL shape (path + query) must map cleanly to one builder. Document the inventory in the batch report.
|
||||||
|
|
||||||
|
**Risk 3: F6 lands later and `endpoints.ts` needs to move to `src/shared/endpoints.ts`**
|
||||||
|
- *Risk*: A future F6 task may move the file.
|
||||||
|
- *Mitigation*: Acceptable. Callers import from the `src/api` barrel (or whatever barrel ends up re-exporting `endpoints` after the move). A single barrel edit re-routes all consumers. This is exactly the benefit F4 was meant to provide.
|
||||||
|
|
||||||
|
## Contract
|
||||||
|
|
||||||
|
This task produces the wire-path contract for the UI ↔ nginx layer. The contract surface IS the `endpoints` object as exported from `src/api/endpoints.ts`. The accompanying unit test (`src/api/endpoints.test.ts`) asserts every URL string and serves as the contract documentation — any future path change MUST update both the builder and the test in the same commit.
|
||||||
|
|
||||||
|
A standalone contract file at `_docs/02_document/contracts/api-transport/endpoints.md` MAY be added in a follow-up task; for this task the test file is the authoritative contract per `module-layout.md`'s "code-derived documentation" pattern.
|
||||||
+11
-6
@@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
## Current Step
|
## Current Step
|
||||||
flow: existing-code
|
flow: existing-code
|
||||||
step: 9
|
step: 10
|
||||||
name: New Task
|
name: Implement
|
||||||
status: in_progress
|
status: not_started
|
||||||
sub_step:
|
sub_step:
|
||||||
phase: 1
|
phase: 0
|
||||||
name: gather-feature-description
|
name: awaiting-invocation
|
||||||
detail: ""
|
detail: "Step 9 closed; AZ-485 (F4 barrels) + AZ-486 (F7 endpoints) ready in todo/; AZ-485 first (AZ-486 depends on barrel)"
|
||||||
retry_count: 0
|
retry_count: 0
|
||||||
cycle: 1
|
cycle: 1
|
||||||
tracker: jira
|
tracker: jira
|
||||||
@@ -29,3 +29,8 @@ step_3_ac_gap_handling: rollback-to-6c (option A)
|
|||||||
`_docs/03_implementation/cumulative_review_batches_04-06_cycle1_report.md`,
|
`_docs/03_implementation/cumulative_review_batches_04-06_cycle1_report.md`,
|
||||||
`_docs/03_implementation/cumulative_review_batches_07-08_cycle1_report.md`
|
`_docs/03_implementation/cumulative_review_batches_07-08_cycle1_report.md`
|
||||||
(cycle close — Phase A wrap, no batch 9).
|
(cycle close — Phase A wrap, no batch 9).
|
||||||
|
- Phase B started. Step 9 (New Task) cycle 1 closed:
|
||||||
|
- AZ-485 (F4 — Public API barrels + STC-ARCH-01, 5 pts, no deps)
|
||||||
|
- AZ-486 (F7 — Endpoint builders + STC-ARCH-02, 5 pts, blocked by AZ-485)
|
||||||
|
- F1 (mission-planner convergence) deliberately not created — needs `/decompose` for 7+ port-group cycles in its own Epic.
|
||||||
|
- Step 10 (Implement) starts with AZ-485 — `Blackbox Tests` owns the static-check addition and the `tests/**` import-path migration; production component teams own their barrel files per `module-layout.md`.
|
||||||
|
|||||||
Reference in New Issue
Block a user