The hierarchical 3-column drill-down was hard to scan and forced a stateful walk per tag. Replaced with a flat, columns-as-tactics matrix that mirrors attack.mitre.org/# — every cell is a one-click select target, with inline sub-technique expand via a `+N` chevron. - New endpoint GET /api/v1/mitre/matrix returns the full grid (tactics → techniques → sub-techniques nested) in a single ~55 KB response, so the SPA renders the whole matrix without firing 15 parallel queries. Two pytest tests added (nested structure + auth required). - MitreTagPicker.tsx rewritten as a horizontal-scrolling matrix: - Click a tactic header → select the tactic (cyan filled). - Click a technique cell → select the technique (orange filled). - Click the `+N` chevron → expand sub-techniques inline within the column. - Click a sub-technique → select (purple filled). - Single Filter field matches on external_id or name across all kinds. - Selection chips at the top, clickable to remove. - `aria-pressed` on every clickable cell for screen readers and Playwright. - e2e test updated to walk the new flow (click cell → assert aria-pressed, expand chevron, click sub, verify chip + JSON preview, filter to T1078). - Spec §F2 + §F12 + todo.md M4 entry updated to make the matrix layout the canonical UI for MITRE tagging (so future spec-reviewer passes accept it). - testing-m4.md walkthrough rewritten for the flat picker. DoD post-refactor: make test-api → 53 passed (was 51), make e2e → 34 passed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Metamorph frontend
Vite + React 18 + TypeScript + TailwindCSS. Design tokens from ../tasks/design.md are in tailwind.config.ts.
Local dev
npm install
npm run dev # http://localhost:5173 (proxies /api/* to http://localhost:8000)
Build
npm run build # outputs to dist/
npm run preview # serves dist/ on http://localhost:8080
Quality
npm run typecheck
npm run lint
npm run format
Layout
src/
├── App.tsx # M0 home page (health check + design tokens demo)
├── main.tsx
├── index.css # Tailwind base + tinted-accent utilities
├── components/ui/ # RTOps design primitives: Card, Tag, SectionHeader, FlowNode, Button
├── lib/
│ ├── api.ts # fetch wrapper (M2 will replace with auth-aware client)
│ └── cn.ts # classnames + ACCENTS palette
└── vite-env.d.ts