From c7f9d9aa367f83c067b173ac88a8e18aa2f26cee Mon Sep 17 00:00:00 2001 From: BOHA Date: Sun, 7 Jun 2026 20:12:08 +0200 Subject: [PATCH] docs(claude): update for completed MUI migration + v2.0.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bring CLAUDE.md in line with the current codebase: - Tech Stack: add Material UI v7 (Emotion) to the frontend row. - Project Structure: ~105 .tsx (was 57), 49 models (was 32); add the ui/ kit, lib/ (React Query), theme.ts and GlobalStyles.tsx; fix contexts/ -> context/; correct the hooks list (drop the nonexistent useApiCall/useListData); refresh the components/ + __tests__ notes. - Testing: drop "coverage is minimal: only auth and numbering" — the suite is ~14 files / 152 tests across many areas. - Frontend Conventions: styling is MUI/Emotion (no .css files, use theme.vars), data layer is React Query, token responses carry expires_in. - "MUI Migration (in progress)" -> "Styling & MUI (complete, v2.0.0)": zero custom CSS; where styling lives (theme/GlobalStyles/kit); and the conventions learned (channel-alpha row tints not solid .light, solid tile + white-glyph icon badges, single mui-mode theme key, dialog scroll-lock). Removed the stale "data-theme drives MUI and legacy CSS". Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 56 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index d2d8f28..18cb893 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -14,7 +14,7 @@ Handles attendance, invoicing, leave/trips, projects, vehicles, and HR operation | ORM | Prisma 6.19.2 → MySQL | | Auth | JWT (HS256, 15 min) + TOTP 2FA (RFC 6238, otpauth) + bcryptjs | | Validation | Zod 4.3.6 | -| Frontend | React 18.3.1 + Vite 8.0.0 | +| Frontend | React 18.3.1 + Vite 8.0.0 + Material UI v7 (Emotion) | | Testing | Vitest 4.1.0 + Supertest | | PDF | Puppeteer 24.x | | Email | nodemailer 8.x | @@ -35,17 +35,21 @@ src/ ├── utils/ # totp.ts, pdf.ts, email.ts, audit.ts, formatters, etc. ├── config/ # env.ts (config singleton, Date.toJSON override) ├── types/ # index.ts (AuthData, JwtPayload, ApiResponse, re-exports from Prisma) -├── admin/ # React 18 frontend (57 .tsx files) +├── admin/ # React 18 + Material UI frontend (~105 .tsx files) │ ├── AdminApp.tsx # Router + lazy-loaded pages -│ ├── contexts/ # AuthContext, AlertContext -│ ├── components/ # Layout, modals, tables, editors +│ ├── theme.ts # MUI theme — light/dark color schemes, tokens, component defaults +│ ├── GlobalStyles.tsx # App-wide global styles via MUI (reset, typography, utilities) +│ ├── ui/ # MUI component kit (AppShell, Button, DataTable, Modal, …) — pages import from here +│ ├── context/ # AuthContext, AlertContext (ThemeContext lives in src/context/) +│ ├── components/ # Non-page components: RichEditor (Quill), PlanGrid, file manager, dashboard/ + warehouse/ widgets │ ├── pages/ # One file per page/feature -│ ├── hooks/ # useApiCall, useListData, useTableSort, etc. +│ ├── lib/ # React Query options & mutations (queries/) + shared label maps +│ ├── hooks/ # usePaginatedQuery, useTableSort, useDebounce, useReducedMotion, … │ └── utils/ # api.ts (fetch wrapper with token refresh), formatters, helpers -└── __tests__/ # Vitest tests (auth, numbering) +└── __tests__/ # Vitest tests (~14 files: auth, numbering, warehouse, plan, invoices, …) prisma/ -├── schema.prisma # 32 models, MySQL, snake_case columns +├── schema.prisma # 49 models, MySQL, snake_case columns └── migrations/ # Applied migrations dist/ # Compiled server (CommonJS, ES2022) @@ -236,7 +240,7 @@ if ("error" in body) return error(reply, body.error, 400); Tests live in `src/__tests__/`. They use Vitest + Supertest against a real test database (`.env.test`). -- Test coverage is minimal: only `auth` and `numbering` are tested. +- The suite spans ~14 files / 152 tests — auth, numbering, warehouse, plan, invoices, exchange-rates, schema coercion, NAS file manager, env, manual-create. Server-side only (no component tests yet). - Use `buildApp()` helper to spin up the Fastify instance for tests. - Tests use `vitest.config.ts` with `environment: 'node'` and 15s timeout. - **Do not mock Prisma** — tests hit a real database to catch schema/query bugs. @@ -250,9 +254,9 @@ When adding new features, add tests in `src/__tests__/`. Name test files `` via `useDialogScrollLock` (MUI only locks ``, and `html{overflow-x:hidden}` makes `` the scroll container); Modal/ConfirmDialog freeze title/label/loading through the close fade (derive-state-from-props) so nothing flashes during the transition. Login renders OUTSIDE the AppShell (sibling route). +**Where styling lives** + +- **Theme — `src/admin/theme.ts`:** `cssVariables` with `colorSchemeSelector: "[data-theme='%s']"`, light + dark `colorSchemes`, tokens, component defaults. Use **`theme.vars!.palette.*`** (the `vars` field is typed optional → `!`) so colours resolve per scheme; for alpha use the channel tokens — `rgba(${theme.vars!.palette.primary.mainChannel} / 0.12)`; for per-scheme one-offs use `theme.applyStyles("dark", { … })`. +- **Global rules — `src/admin/GlobalStyles.tsx`:** reset, typography, scrollbar, `::selection`, view-transition timing, and the utility classes (`.text-*`, `.flex-*`, `.mb-*`, …), all theme-aware. (The pre-React bootstrap spinner is inlined in `src/App.tsx` because it mounts before MUI.) +- **Component kit — `src/admin/ui/`:** AppShell, Button, Card, TextField, Select (string-based — convert ids at the boundary), DateField/MonthField/TimeField (date-fns v4, cs), Modal, ConfirmDialog (optional `children` + content freeze), DataTable (sortable + mobile card layout + `rowSx`/`rowDanger`/`rowInactive`), Pagination, Tabs/TabPanel, StatusChip, CheckboxField/SwitchField, Field, Alert, PageHeader, FilterBar, StatCard, ProgressBar, FileUpload, EmptyState, LoadingState, ThemeToggle, PageEnter (staggered page entrance), RichEditorRoot/RichTextView (Quill). Dev-only `/ui-kit` showcase route. + +**Building / editing pages** + +- Pages import from the **kit** (`src/admin/ui/`); reach for `@mui/material` (`styled`/`sx`) directly only for one-off layout or infra (theme, GlobalStyles, the Quill/Leaflet wrappers). +- Wrap a page's top-level sections in ``. Filters go in `` with **bare** controls (no `` label) at the standard widths. +- When refactoring, **preserve ALL data logic verbatim** (hooks, mutations, `invalidate` arrays, validation, permissions); change only presentation. + +**Conventions learned — don't regress** + +- **Status row tints** = subtle channel-alpha washes (`rgba(var(--mui-palette-X-mainChannel) / 0.12)`), NEVER a solid `.light` fill: `.light` is a light colour in BOTH schemes, so white dark-mode text on it is invisible. Voided/disabled rows = `opacity` + muted text. +- **Icon badges** = solid `X.main` tile + **white** glyph (not an `X.light` tile + `X.main` glyph — that's low-contrast). +- **Theme is single-source:** `src/context/ThemeContext.tsx` owns the `` attribute + the View-Transitions cross-fade, and persists under MUI's **`mui-mode`** localStorage key (the same key MUI reads on mount). Do NOT add a second theme key — that desyncs page vs toggle on refresh. +- **Dialogs** lock `` via `useDialogScrollLock` (MUI only locks ``, and `html{overflow-x:hidden}` makes `` the scroller); Modal/ConfirmDialog freeze title/label/loading through the close fade so nothing flashes. Login renders OUTSIDE AppShell. + +**Gates every change:** `npx tsc -b --noEmit` (NOT `-p tsconfig.json` — a vacuous solution file that checks nothing), `npm run build`, `npx vitest run`. ---