[AZ-447] autodev Steps 1-4 baseline: docs, tests, refactor specs

Captures the full output of autodev existing-code Phase A through
Step 4 (Code Testability Revision) for the Azaion UI workspace:

- Step 1 Document: _docs/02_document/ (FINAL_report, architecture,
  glossary, components/, modules/, diagrams/, system-flows,
  module-layout) plus _docs/00_problem/ + _docs/01_solution/ +
  _docs/legacy/ + _docs/how_to_test + README.
- Step 2 Architecture Baseline: architecture_compliance_baseline.md.
- Step 3 Test Spec: _docs/02_document/tests/ (environment,
  test-data, blackbox/performance/resilience/security/
  resource-limit tests, traceability-matrix), enum_spec_snapshot,
  expected_results/results_report.md (98 rows), plus the
  run-tests.sh + run-performance-tests.sh runners.
- Step 4 Code Testability Revision: 01-testability-refactoring/
  run dir (list-of-changes C01-C07, deferred_to_refactor,
  analysis/research_findings + refactoring_roadmap) and the 7
  child task specs AZ-448..AZ-454 under _docs/02_tasks/todo/
  plus _dependencies_table.md.
- _docs/_autodev_state.md pins the cursor at Step 4 / refactor
  Phase 4 entry so /autodev resumes cleanly.

Epic AZ-447 (UI testability gates) tracks the 7 child tasks that
will land in subsequent commits.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-11 00:38:49 +03:00
parent da0a5aa187
commit 510df68bcf
84 changed files with 13065 additions and 0 deletions
@@ -0,0 +1,101 @@
# Module: `src/auth/ProtectedRoute.tsx`
> **Source**: `src/auth/ProtectedRoute.tsx` (19 lines)
> **Topo batch**: B4 (depends on B3: `auth/AuthContext`)
## Purpose
A tiny route guard that gates its children behind an authenticated session.
While `AuthContext` is bootstrapping (`loading === true`) it shows a spinner;
when the bootstrap finishes with no user it redirects to `/login`; otherwise
it renders its children. Mounted exactly once in `App.tsx` between
`AuthProvider` and `FlightProvider` so every authenticated page benefits
from it. WPF parallel: the implicit "no LoginWindow open ⇒ MainWindow"
gate (`_docs/legacy/wpf-era.md` §4).
## Public interface
```ts
interface Props { children: ReactNode }
export default function ProtectedRoute(props: Props): JSX.Element
```
Always returns a `JSX.Element` — never `null`. The three rendered shapes
are:
1. Spinner (centered `<div>` with the orange ring) while `loading`.
2. `<Navigate to="/login" replace />` when `loading === false && user == null`.
3. `<>{children}</>` otherwise.
`replace` is intentional: it rewrites the history entry so the back
button does not return to a protected route the user was bounced off.
## Internal logic
- Single hook call: `const { user, loading } = useAuth()`. No local state.
- Branch order matters — `loading` is checked before `user` so a freshly
reloaded tab never renders the login redirect during the in-flight
refresh attempt. (See the open `AuthContext` bootstrap-vs-refresh
divergence flagged in `src__auth__AuthContext.md`; if that bug is
fixed the spinner duration becomes accurate.)
## Dependencies
- **Internal**: `./AuthContext``useAuth`.
- **External**: `react-router-dom` (`Navigate`), `react` (`ReactNode` type only).
## Consumers (intra-repo)
From the §7a dependency graph:
- `src/App.tsx` — wraps the entire authenticated route tree:
`AuthProvider → ProtectedRoute → FlightProvider → Header + nested Routes`.
Not used anywhere else; the SPA has a single protected zone.
## Data models
None.
## Configuration
The `/login` redirect target is hardcoded. Matches the public route
declared in `App.tsx`. If the public route is ever renamed, update both
sites.
The spinner uses Tailwind tokens `bg-az-bg`, `border-az-orange`
(defined in `src/index.css`).
## External integrations
None directly. Indirectly relies on whatever `AuthContext` calls during
bootstrap — currently `GET /api/admin/auth/refresh`.
## Security
- **No token check is duplicated here** — relies entirely on `AuthContext`.
The component cannot be confused into rendering protected children
before the bootstrap resolves because `loading` defaults to `true` in
`AuthProvider`.
- Backend authority is unchanged — this is a UI affordance only. Every
request the children make MUST also be enforced server-side.
- The redirect uses `Navigate`, so query params on the original URL are
lost. Acceptable today (no protected route relies on them); flag if a
future "deep-link after login" UX appears.
## Tests
None.
## Notes / open questions
- The spinner has no `role="status"` or accessible label — screen readers
hear nothing while the bootstrap runs. Cosmetic; flag for Step 4
verification against `_docs/ui_design/README.md` accessibility notes.
- No timeout on the `loading` state — if `AuthContext`'s bootstrap
somehow never resolves (e.g., the refresh endpoint hangs), the user
sees an infinite spinner. `client.ts` does not currently set a
request timeout either; flag jointly with Step 4.
- The `<>{children}</>` Fragment wrap is intentional: returning `children`
directly would make the type `ReactNode` rather than `JSX.Element` and
would not satisfy the route element slot in `react-router-dom@7`.