Files
mimic-big/frontend
ux-frontend 140a34b81e
Some checks failed
ci / backend (lint + typecheck + unit tests) (push) Failing after 0s
ci / frontend (lint + typecheck + build + unit tests) (push) Failing after 0s
fix(frontend): align types + UI to backend contract (docs/api.md @ dd5c508)
Backend pushed the authoritative contract in docs/api.md and tightened
the error envelope via a global HTTPException handler (dd5c508). This
commit folds the frontend onto that contract — every drift flagged by
the code-reviewer MAJOR is closed.

Types (src/types/api.ts)
- User: `id` → `user_id`; `display_name` is `string | null`; add
  `permissions: string[]` and `groups: string[]`; drop `engagement_id`
  and `engagement_name` (not part of CurrentUser).
- Engagement: drop `name`, `client_name` is non-null `string`; status
  enum aligned to `draft | active | closed | archived`; `c2_type` is
  non-null `C2Type`; drop `created_at` (not in EngagementRead v1).
- EngagementCreate body: `client_name` required, plus optional
  `description`, `c2_type`, `start_date`, `end_date`. No `name`.
- Replace ApiError + ApiValidationError with a single uniform envelope:
  `{ error: string, message: string, details?: PydanticErrorItem[] }`,
  matching the new HTTPException handler. PydanticErrorItem is the
  per-field shape on 422 (`{ loc, msg, type }`).

Fetch client (src/lib/api.ts)
- `bodyAsApiError` now recognizes the uniform envelope by shape
  (error+message strings). Anything else returns null so callers fall
  back to a generic message — keeps us robust if the backend ever
  emits a non-JSON response.

Engagements API (src/screens/engagements/engagementsApi.ts)
- Drop the `{ items: [] }` envelope tolerance — backend serves a bare
  `Engagement[]`.
- Hit `/engagements/` with trailing slash explicitly; backend now sets
  `strict_slashes=False` but staying consistent with docs/api.md.

EngagementsPage
- Status tone map switched to the new enum (`draft → pending`,
  `closed → soc`).
- Drop "Name" column. `client_name` is the primary identifier; the
  description column replaces the now-meaningless name field.
- `c2_type` is non-null, so no nullable rendering path.

EngagementCreateDialog
- Drop `name` field. New required field is `client_name`; add a
  `c2_type` select (default `mythic`); brief textarea stays optional.
- `mapValidationErrors` now reads `body.details[*].loc` (last segment
  matches the form field) — direct alignment with the backend's new
  shape after dd5c508.
- 401 still surfaces "Session expirée"; 403 gains a dedicated message;
  other errors fall back to a capitalized backend `message` when
  available, then to a generic French string.

Sidebar
- Display fallback: `user.display_name ?? user.username` (now nullable).
- Drop the `ENG · {engagement_name}` line; show `user.username` (the
  email) as the secondary identity instead.

LoginPage
- Field label "Username" → "Email or username" so RT users with email
  accounts find the field semantically obvious (per docs/api.md note
  on the username/email mapping).

Tests (Vitest, 14 cases, all green)
- Refreshed fixtures to the new shapes (no more `name`, no
  `created_at`, status `draft`, envelopes carry `error`+`message`).
- New 422 test exercises the `details[*].loc` mapping shape.
- New 401 test on the dialog covers the top-of-form alert path.
2026-05-23 11:14:32 +02:00
..

Mimic frontend

React + TypeScript SPA for the Mimic BAS platform. Lives behind the existing RT reverse proxy (Caddy + TLS + IP allowlist) — see D-007.

Stack

  • React 19, TypeScript strict
  • Vite 8 (dev/build)
  • Tailwind 4 (semantic tokens in src/styles/theme.css)
  • TanStack Query 5 for server state
  • react-router-dom v7 for routing
  • Recharts for the report visualisations
  • Vitest + Testing Library for unit tests
  • Playwright for E2E (covered in sprint 1+)

Scripts

npm install
npm run dev          # vite dev server on :5173
npm run build        # tsc -b && vite build
npm run typecheck    # tsc -b --noEmit
npm run lint         # eslint . (strict TS + react-hooks + prettier)
npm run format       # prettier --write .
npm test             # vitest run
npm run e2e          # playwright test (needs npm run e2e:install once)

Layout

src/
├── components/
│   ├── brand/        # Wordmark (provisional, awaits PR3 charter)
│   ├── shell/        # AppShell, Sidebar, StatusRail
│   └── ui/           # Panel, Pill, Button — instrument-grade primitives
├── mocks/            # sprint 0 fixtures (no backend yet)
├── router/           # RootLayout helper
├── screens/          # one folder per top-level route
├── session/          # mock auth context (D-003 v1 hook-in point)
├── styles/           # theme.css (tokens), fonts.css, globals.css
└── types/            # cross-cutting type aliases

Design system status (provisional)

The token layer in src/styles/theme.css is structured to receive the RT graphic charter (PR3) without touching component code. Component CSS reads exclusively from semantic tokens (--accent-rt, --status-detected, …); swapping the underlying primitive palette is the only change required when PR3 lands.

Auth status (sprint 0)

The session context reads/writes a mock user in sessionStorage. No real auth yet. v1 will wire local username/password + bcrypt (D-003); v2 maps Keycloak OIDC claims onto the same role enum.

Fonts

IBM Plex (Sans / Sans Condensed / Mono), self-hosted under public/fonts/. Files are not yet vendored — see public/fonts/README.md. Until then the UI falls back to ui-sans-serif / ui-monospace.