|
2 | 2 |
|
3 | 3 | This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
4 | 4 |
|
| 5 | +## What is CARE? |
| 6 | + |
| 7 | +CARE is a Digital Public Good building an open source EMR + Hospital Management system. This is the React frontend (React 19 + TypeScript + Vite). |
| 8 | + |
5 | 9 | ## Build/Lint/Test Commands |
6 | | -- `npm run dev`: Start development server |
7 | | -- `npm run build`: Build for production |
8 | | -- `npm run lint`: Run ESLint |
9 | | -- `npm run lint-fix`: Run ESLint with auto-fix |
10 | | -- `npm run format`: Format code with Prettier |
11 | | -- `npm run playwright:test`: Run Playwright tests in headless mode |
12 | | -- `npm run playwright:test:ui`: Run Playwright tests in interactive UI mode |
| 10 | + |
| 11 | +- `npm run dev` — Start dev server at http://localhost:4000 |
| 12 | +- `npm run build` — Production build (takes 2+ minutes, set timeout to 180s+) |
| 13 | +- `npm run lint` — Run ESLint (takes 85s+, set timeout to 120s+) |
| 14 | +- `npm run lint-fix` — ESLint with auto-fix |
| 15 | +- `npm run format` — Prettier formatting |
| 16 | +- `npm run playwright:test` — Run all Playwright E2E tests headlessly |
| 17 | +- `npm run playwright:test -- tests/auth/login.spec.ts` — Run a single test file |
| 18 | +- `npm run playwright:test -- -g "test name"` — Run tests matching a pattern |
| 19 | +- `npm run playwright:test:ui` — Interactive Playwright UI mode |
| 20 | + |
| 21 | +Playwright requires a local backend running (`REACT_CARE_API_URL=http://127.0.0.1:9000` in `.env.local`) and `npm run playwright:install` for browsers. |
13 | 22 |
|
14 | 23 | ## Code Style Guidelines |
15 | | -- **TypeScript**: Strict mode, ES2022 target, path aliases (`@/*` for src) |
| 24 | + |
| 25 | +- **TypeScript**: Strict mode, ES2022 target, path aliases (`@/*` → `src/*`, `@careConfig` → `care.config.ts`) |
16 | 26 | - **Formatting**: Double quotes, 2-space indent, semicolons required |
17 | | -- **Imports**: Order by 3rd-party → library → CAREUI → UI → components → hooks → utils → relative |
18 | | -- **Types**: Use `interface` for objects, avoid explicit `any`, proper nullability |
19 | | -- **Naming**: PascalCase for components/classes, camelCase for variables/functions |
20 | | -- **Components**: Organized by feature, maintain separation of concerns |
21 | | -- **Error Handling**: Use dedicated error handlers, TypeScript strict null checks |
| 27 | +- **Imports**: Order by 3rd-party → library → CAREUI → UI → components → hooks → utils → relative. Prettier plugin auto-sorts on format. |
| 28 | +- **Types**: Use `interface` for objects, avoid `any`, prefer maps over enums |
| 29 | +- **Naming**: PascalCase for component files (`AuthWizard.tsx`), camelCase for hooks/utils (`useAuth.ts`), kebab-case for directories |
| 30 | +- **Components**: Functional components only, named exports preferred, one component per file |
| 31 | +- **i18n**: All user-facing strings must use i18next. English translations go in `public/locale/en.json`. Non-English managed via Crowdin — do not edit directly. |
| 32 | + |
| 33 | +## Architecture |
| 34 | + |
| 35 | +### Routing (Raviger) |
| 36 | + |
| 37 | +Routes defined in `src/Routers/routes/` (e.g., `FacilityRoutes.tsx`, `PatientRoutes.tsx`). Combined in `src/Routers/AppRouter.tsx`. Three routers: `PublicRouter`, `PatientRouter`, `AppRouter` — selected by auth state. Plugin routes injected via `usePluginRoutes()`. |
| 38 | + |
| 39 | +```typescript |
| 40 | +const FacilityRoutes: AppRoutes = { |
| 41 | + "/facility/:facilityId/overview": ({ facilityId }) => <FacilityOverview facilityId={facilityId} />, |
| 42 | +}; |
| 43 | +``` |
| 44 | + |
| 45 | +Use `navigate()` from raviger for programmatic navigation. |
| 46 | + |
| 47 | +### API Layer (TanStack Query + custom wrappers) |
| 48 | + |
| 49 | +API routes defined in `src/types/{domain}/{domain}Api.ts` using typed route objects: |
| 50 | + |
| 51 | +```typescript |
| 52 | +export default { |
| 53 | + list: { |
| 54 | + path: "/api/v1/users/", |
| 55 | + method: HttpMethod.GET, |
| 56 | + TRes: Type<PaginatedResponse<UserReadMinimal>>(), |
| 57 | + }, |
| 58 | +} as const; |
| 59 | +``` |
| 60 | + |
| 61 | +Queries use `query()` wrapper from `src/Utils/request/query.ts`: |
| 62 | + |
| 63 | +```typescript |
| 64 | +const { data } = useQuery({ |
| 65 | + queryKey: ["users"], |
| 66 | + queryFn: query(userApi.list), |
| 67 | +}); |
| 68 | +// With path/query params: |
| 69 | +queryFn: query(userApi.get, { pathParams: { username }, queryParams: { search } }) |
| 70 | +``` |
| 71 | + |
| 72 | +Mutations use `mutate()` wrapper from `src/Utils/request/mutate.ts`: |
| 73 | + |
| 74 | +```typescript |
| 75 | +const { mutate } = useMutation({ |
| 76 | + mutationFn: mutate(userApi.create), |
| 77 | +}); |
| 78 | +``` |
| 79 | + |
| 80 | +Also available: `query.debounced()` and `query.paginated()` for specialized use cases. |
| 81 | + |
| 82 | +Errors handled globally — session expiry redirects to `/session-expired`, 400/406 show toast notifications. Use `silent: true` to suppress. |
| 83 | + |
| 84 | +### State Management |
| 85 | + |
| 86 | +- **TanStack Query** — Server state (API data caching, refetching) |
| 87 | +- **Jotai atoms** (`src/atoms/`) — Lightweight client state (user, nav, filters) |
| 88 | +- **React Context** (`src/context/`) — Permissions (`PermissionContext`), keyboard shortcuts |
| 89 | + |
| 90 | +### UI Components |
| 91 | + |
| 92 | +Built on **shadcn/uishadcn/ui** + **Radix UI primitives** + **Tailwind CSS v4** (shadcn/ui pattern): |
| 93 | +- `src/components/ui/` — Base UI primitives (Button, Dialog, Form, Select, etc.). Do not modify these directly. |
| 94 | +- `src/CAREUI/` — Custom healthcare icon library, use `lucide-react` unless you are explicitly asked to use CAREUI icons. |
| 95 | +- Forms use `react-hook-form` + `zod` validation with the custom `<Form>` component |
| 96 | + |
| 97 | +### Plugin System (Module Federation) |
| 98 | + |
| 99 | +Micro-frontend architecture via `@originjs/vite-plugin-federation`. Plugins configured via `REACT_ENABLED_APPS` env var. Plugin manifests define routes, components, tabs, and devices they provide. Key files: `src/PluginEngine.tsx`, `src/pluginTypes.ts`. |
| 100 | + |
| 101 | +### Auth Flow |
| 102 | + |
| 103 | +JWT tokens in localStorage. `AuthUserProvider` handles login/logout, token refresh (every 5 minutes), 2FA, and cross-tab session sync. Patient login uses separate OTP-based flow via `PatientRouter`. |
| 104 | + |
| 105 | +### Key Directories |
| 106 | + |
| 107 | +- `src/components/` — Feature-organized components (Auth, Facility, Patient, Encounter, Medicine, etc.) |
| 108 | +- `src/pages/` — Page components by feature (Admin, Appointments, Facility, Organization, Patient) |
| 109 | +- `src/types/` — Domain type definitions with corresponding `*Api.ts` route files |
| 110 | +- `src/Utils/request/` — API request infrastructure (query, mutate, error handling) |
| 111 | +- `src/hooks/` — Custom React hooks (auth, file management, plugins, etc.) |
| 112 | +- `src/Providers/` — Auth, history, patient user providers |
| 113 | +- `src/Routers/` — App routing and route definitions |
| 114 | + |
| 115 | +### Configuration |
| 116 | + |
| 117 | +`care.config.ts` centralizes runtime config (API URLs, feature flags, locale settings, plugin config). Environment variables prefixed with `REACT_`. |
| 118 | + |
| 119 | +## Git Workflow |
| 120 | + |
| 121 | +- Branch naming: `issues/{issue#}/{short-name}` |
| 122 | +- Default branch: `develop` (staging auto-deploys) |
| 123 | +- Pre-commit hooks via husky run Prettier and ESLint on staged files |
0 commit comments