CAVE Frontend
Table of Contents
Start Here
This section is for getting the app running quickly and making your first change with minimal setup friction.
Quick start
-
Use Node.js
20.19.0or later. Verify your local versions before installing dependencies:node --versionnpm --version -
Install dependencies:
cd clean-architecture-visualizer/frontendnpm install -
Start the frontend:
npm run dev -
Open http://localhost:5173.
Launching options
Option 1: Via the CLI (recommended)
From the project root that you wish to validate your adherence to clean architecture (or anywhere after npm link):
cave start
This will:
- Read the directory
- Start the Express server on port
3131 - Start the Vite dev server on port
5173in--mode backendand proxy it behind the Express server - Open your browser to
http://localhost:3131
Option 2: Run frontend only with mock data (MSW)
cd clean-architecture-visualizer/frontend
npm install
npm run dev
Option 3: Build and preview production output
cd clean-architecture-visualizer/frontend
npm install
npm run build
npm run preview
Role-based onboarding paths
Frontend feature dev path
- Start with
npm run dev. - Find placement using the file structure section below (
pages,components,api,actions). - Implement feature with shared types/constants in
src/lib. - Run
npm run type-check,npm run lint, and relevant tests.
Bugfix-only path
- Reproduce quickly with
npm run dev. - Add or update the smallest focused test (
test:unitfirst,test:e2eif user flow regression). - Fix the issue close to source (avoid broad refactors).
- Re-run checks before opening PR.
Docs/contributor path
- Run the app locally once to validate screenshots/steps.
- Update docs and command names exactly as defined in
package.jsonscripts. - Confirm new instructions are copy-paste runnable from the stated directory.
Common pitfalls
- Wrong folder path: run frontend commands from
clean-architecture-visualizer/frontend, notcave-docs. - Missing Playwright setup: run
npm run setupbefore the first e2e run on a new machine. - Backend mode confusion: use
npm run devfor mock-data frontend flow andnpm run dev:backendwhen you intend to connect to backend mode.
Daily Workflow
Command map
The following scripts are defined for development, testing, and quality checks:
| Command | Description |
|---|---|
npm run dev | Starts Vite dev server at http://localhost:5173. |
npm run dev:backend | Starts Vite in backend mode. |
npm run build | Runs TypeScript project build and production bundling. |
npm run preview | Serves the local production build for verification. |
npm run setup | Installs Playwright browsers for e2e tests. |
npm run lint | Runs ESLint with warnings treated as failures. |
npm run type-check | Runs TypeScript checks without emitting files. |
npm run test:unit | Executes Vitest unit tests. |
npm run test:e2e | Runs Playwright end-to-end tests. |
npm run test:e2e:ui | Runs Playwright tests in UI mode. |
npm run test:e2e:debug | Runs Playwright in debug mode. |
Suggested daily loop
- Pull latest changes and run
npm installif lockfile changed. - Start local dev with
npm run dev. - Implement changes in small commits.
- Before PR: run
npm run type-check,npm run lint, and relevant tests.
Testing and debugging
- Unit tests: use
npm run test:unitfor component logic and utilities. - End-to-end tests: use
npm run test:e2efor full user workflows. - Debugging e2e failures: use
npm run test:e2e:debugornpm run test:e2e:ui.
Standards and Architecture
Tech stack
The project uses:
- React + Vite for the app shell and build pipeline.
- Material UI for core UI components.
- TypeScript for type safety.
- React Query patterns in
actionsfor data workflows. - MSW for mock endpoint behavior during frontend-only development.
- Vitest and Playwright for unit and e2e testing.
Frontend file structure
The frontend app lives in clean-architecture-visualizer/frontend/src.
frontend/src/
actions/ # React Query hooks and action-level data logic
api/ # API clients and endpoint wrappers
assets/ # Static assets used by the app
components/ # Reusable UI components
hooks/ # Reusable React hooks
i18n/ # Translation setup and locale resources
lib/ # Shared types, constants, themes, and core frontend models
mocks/ # MSW handlers and mock data
pages/ # Route-level page components
styles/ # Shared/global style utilities
utils/ # Pure helper functions
App.tsx # Root app composition
main.tsx # Frontend entry point
Placement rules:
- Put route-level UI in
pages, and reusable pieces incomponents. - Put data fetching and server interaction in
apiplusactions(not in presentational components). - Put shared cross-feature definitions in
lib. - Put reusable hooks in
hooksand generic helpers inutils.
Reusable types and constants
Define reusable values once and import them where needed.
- If a type or constant is used in more than one file, place it in
src/lib. - Shared types go in
src/lib/types.ts. - Shared constants go in
src/lib/storageKeys.ts(and similar files insrc/libwhen needed). - Before creating new definitions, check
src/liband reuse existing definitions.
File naming conventions
- Use
index.tsxfor a component entry file andstyles.tsfor styled definitions. - Use
PascalCasefolder names for components and pages (for example:CodeViewer,CheckerMode). - Use
camelCasefor utility/lib files (for example:storageKeys.ts). - Use descriptive names for hooks and tests (for example:
useSomething.ts,ComponentName.test.tsx).
UI styling conventions
Using the MUI colour palette
Use theme palette values instead of hardcoded hex values whenever possible.
Recommended approach:
- Add or update palette tokens in the shared MUI theme.
- Reference tokens with
theme.palette.*in styled components. - Use semantic names (
primary,secondary,error,warning,success,info) rather than one-off colour values.
Example:
import { styled } from '@mui/material/styles';
export const Panel = styled('section')(({ theme }) => ({
backgroundColor: theme.palette.background.paper,
color: theme.palette.text.primary,
border: `1px solid ${theme.palette.divider}`,
}));
If a new colour is needed, prefer adding it to the theme first, then consuming it from components.
Component file separation: index.tsx plus styles.ts
For most reusable UI components, separate structure and logic from styling.
index.tsx: component logic, props, hooks, and JSX structure.styles.ts: styled wrappers and visual primitives.
Benefits:
- Keeps component logic readable.
- Makes style reuse and review easier.
- Reduces merge conflicts when one person changes logic and another changes styling.
Suggested pattern:
// index.tsx
import { Container, Title } from './styles';
type Props = {
title: string;
};
export default function FeatureCard({ title }: Props) {
return (
<Container>
<Title>{title}</Title>
</Container>
);
}
// styles.ts
import { styled } from '@mui/material/styles';
export const Container = styled('article')(({ theme }) => ({
backgroundColor: theme.palette.background.paper,
borderRadius: theme.shape.borderRadius,
padding: theme.spacing(2),
}));
export const Title = styled('h3')(({ theme }) => ({
color: theme.palette.text.primary,
margin: 0,
}));
Notes:
- Small one-file components are fine when separation adds unnecessary overhead.
- For larger components, default to this split to keep files maintainable.
Good examples in this codebase:
frontend/src/components/code/CodeViewer/index.tsxplusfrontend/src/components/code/CodeViewer/styles.tsfrontend/src/components/code/FileExplorer/index.tsxplusfrontend/src/components/code/FileExplorer/styles.tsfrontend/src/components/diagram/ViolationsSideBarContent/index.tsxplusfrontend/src/components/diagram/ViolationsSideBarContent/styles.tsfrontend/src/components/diagram/SideBar/index.tsxplusfrontend/src/components/diagram/SideBar/styles.tsfrontend/src/pages/CheckerMode/index.tsxplusfrontend/src/pages/CheckerMode/styles.ts
Accessibility
Build accessibility in by default:
- Use semantic HTML and MUI components that provide built-in accessibility support.
- Ensure interactive elements are keyboard accessible and have visible focus states.
- Add accessible names for controls (
aria-label,aria-labelledby, or visible text labels). - Keep color contrast readable; do not rely on color alone to communicate status.
- Provide alt text for meaningful images and icons, and hide decorative icons from screen readers.
- For dialogs, accordions, and navigation, verify correct ARIA relationships and focus behavior.
Quick check before merging:
- Navigate key flows using keyboard only (Tab, Shift+Tab, Enter, Space, Escape).
- Confirm screen reader labels are present for key actions.
- Validate error and success states are understandable without color cues.
- In Chrome, run Lighthouse accessibility analysis on page load.
- In Chrome DevTools, inspect text contrast in the color picker contrast indicator.
i18n
The frontend uses i18next with react-i18next and currently ships with English resources.
Where translation files live
- i18n setup:
frontend/src/i18n/config.ts - Locale files:
frontend/src/i18n/locales/en/*.json - Each JSON file is a namespace (for example:
home.json,checker.json,common.json).
How to add new translation keys
- Choose the correct namespace file in
frontend/src/i18n/locales/en. - Add the key in nested JSON form (group by feature/component).
- If you create a brand new namespace file, import it in
frontend/src/i18n/config.tsand register it inresources.en. - Use the key from components with
useTranslation('<namespace>').
Example JSON (frontend/src/i18n/locales/en/home.json):
{
"cards": {
"checker": {
"title": "Checker Mode",
"description": "Validate architecture violations in your project"
}
}
}
How to use useTranslation in components
import { useTranslation } from 'react-i18next';
export default function Example() {
const { t } = useTranslation('home');
return <h2>{t('cards.checker.title')}</h2>;
}
Current codebase patterns:
- Simple string translation with
t(...)in page/components. - Rich text translation with
<Trans />when markup is needed inside localized content.
i18n initialization notes
- Ensure
frontend/src/i18n/config.tsis imported by pages/components that require translations (existing pages already follow this pattern). fallbackLngis set toen.- Test mode supports
lng=cimodevia query parameter orVITE_TEST_MODE=truefor deterministic test text behavior.
Key naming guidelines
- Prefer feature-scoped keys such as
cards.checker.titleinstead of flat keys. - Keep key names stable and descriptive; update values more often than key identifiers.
- Reuse existing keys in
common.jsonfor shared labels/buttons before creating duplicates.