@react-spa-scaffold/mcp 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +423 -0
- package/dist/features/index.d.ts +5 -0
- package/dist/features/index.d.ts.map +1 -0
- package/dist/features/index.js +3 -0
- package/dist/features/index.js.map +1 -0
- package/dist/features/registry.d.ts +10 -0
- package/dist/features/registry.d.ts.map +1 -0
- package/dist/features/registry.js +508 -0
- package/dist/features/registry.js.map +1 -0
- package/dist/features/types.d.ts +45 -0
- package/dist/features/types.d.ts.map +1 -0
- package/dist/features/types.js +5 -0
- package/dist/features/types.js.map +1 -0
- package/dist/features/versions.d.ts +16 -0
- package/dist/features/versions.d.ts.map +1 -0
- package/dist/features/versions.js +46 -0
- package/dist/features/versions.js.map +1 -0
- package/dist/features/versions.json +5 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/resources/docs.d.ts +29 -0
- package/dist/resources/docs.d.ts.map +1 -0
- package/dist/resources/docs.js +105 -0
- package/dist/resources/docs.js.map +1 -0
- package/dist/resources/index.d.ts +2 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +2 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/server.d.ts +12 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +115 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/get-example.d.ts +51 -0
- package/dist/tools/get-example.d.ts.map +1 -0
- package/dist/tools/get-example.js +90 -0
- package/dist/tools/get-example.js.map +1 -0
- package/dist/tools/get-features.d.ts +30 -0
- package/dist/tools/get-features.d.ts.map +1 -0
- package/dist/tools/get-features.js +46 -0
- package/dist/tools/get-features.js.map +1 -0
- package/dist/tools/get-scaffold.d.ts +77 -0
- package/dist/tools/get-scaffold.d.ts.map +1 -0
- package/dist/tools/get-scaffold.js +153 -0
- package/dist/tools/get-scaffold.js.map +1 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/utils/docs.d.ts +14 -0
- package/dist/utils/docs.d.ts.map +1 -0
- package/dist/utils/docs.js +64 -0
- package/dist/utils/docs.js.map +1 -0
- package/dist/utils/examples.d.ts +27 -0
- package/dist/utils/examples.d.ts.map +1 -0
- package/dist/utils/examples.js +399 -0
- package/dist/utils/examples.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/paths.d.ts +28 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +40 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/scaffold.d.ts +50 -0
- package/dist/utils/scaffold.d.ts.map +1 -0
- package/dist/utils/scaffold.js +500 -0
- package/dist/utils/scaffold.js.map +1 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +19 -0
- package/dist/version.js.map +1 -0
- package/package.json +63 -0
- package/templates/.bundled +0 -0
- package/templates/CLAUDE.md +145 -0
- package/templates/docs/API_REFERENCE.md +58 -0
- package/templates/docs/ARCHITECTURE.md +185 -0
- package/templates/docs/CODING_STANDARDS.md +53 -0
- package/templates/docs/COMPONENT_GUIDELINES.md +301 -0
- package/templates/docs/E2E_TESTING.md +116 -0
- package/templates/docs/INTERNATIONALIZATION.md +67 -0
- package/templates/docs/TESTING.md +259 -0
- package/templates/docs/WORKFLOW.md +170 -0
- package/templates/src/App.tsx +42 -0
- package/templates/src/components/layout/Header.tsx +19 -0
- package/templates/src/components/layout/index.ts +1 -0
- package/templates/src/components/shared/ErrorBoundary/ErrorBoundary.tsx +104 -0
- package/templates/src/components/shared/ErrorBoundary/index.ts +1 -0
- package/templates/src/components/shared/LanguageSwitcher/LanguageSwitcher.tsx +45 -0
- package/templates/src/components/shared/LanguageSwitcher/index.ts +1 -0
- package/templates/src/components/shared/SEO/SEO.tsx +55 -0
- package/templates/src/components/shared/SEO/index.ts +1 -0
- package/templates/src/components/shared/ThemeToggle/ThemeToggle.tsx +41 -0
- package/templates/src/components/shared/ThemeToggle/index.ts +1 -0
- package/templates/src/components/shared/index.ts +4 -0
- package/templates/src/components/ui/button.tsx +48 -0
- package/templates/src/components/ui/dropdown-menu.tsx +228 -0
- package/templates/src/components/ui/form-error.tsx +95 -0
- package/templates/src/components/ui/loading.tsx +58 -0
- package/templates/src/components/ui/skeleton.tsx +52 -0
- package/templates/src/components/ui/sonner.tsx +34 -0
- package/templates/src/components/ui/spinner.tsx +40 -0
- package/templates/src/components/ui/visually-hidden.tsx +51 -0
- package/templates/src/contexts/mobileContext.tsx +66 -0
- package/templates/src/contexts/queryContext.tsx +28 -0
- package/templates/src/hooks/index.ts +7 -0
- package/templates/src/hooks/useContactForm.ts +33 -0
- package/templates/src/hooks/useExampleQuery.ts +20 -0
- package/templates/src/hooks/useLanguage.ts +23 -0
- package/templates/src/hooks/useMediaQuery.ts +53 -0
- package/templates/src/hooks/useThemeEffect.ts +31 -0
- package/templates/src/hooks/useTouchSizes.ts +16 -0
- package/templates/src/i18n/config.ts +11 -0
- package/templates/src/i18n/detectLanguage.ts +57 -0
- package/templates/src/i18n/index.ts +20 -0
- package/templates/src/i18n/loadCatalog.ts +30 -0
- package/templates/src/index.css +98 -0
- package/templates/src/lib/api.ts +142 -0
- package/templates/src/lib/config.ts +15 -0
- package/templates/src/lib/constants.ts +8 -0
- package/templates/src/lib/env.ts +53 -0
- package/templates/src/lib/format.ts +119 -0
- package/templates/src/lib/index.ts +24 -0
- package/templates/src/lib/routes.ts +11 -0
- package/templates/src/lib/storage.ts +91 -0
- package/templates/src/lib/storageKeys.ts +10 -0
- package/templates/src/lib/utils.ts +6 -0
- package/templates/src/lib/validations.ts +39 -0
- package/templates/src/locales/de.po +65 -0
- package/templates/src/locales/en.po +65 -0
- package/templates/src/locales/es.po +65 -0
- package/templates/src/main.tsx +107 -0
- package/templates/src/mocks/fixtures/index.ts +1 -0
- package/templates/src/mocks/fixtures/todos.ts +40 -0
- package/templates/src/mocks/handlers/index.ts +7 -0
- package/templates/src/mocks/handlers/todos.ts +59 -0
- package/templates/src/mocks/index.ts +3 -0
- package/templates/src/mocks/node.ts +9 -0
- package/templates/src/pages/Home.tsx +27 -0
- package/templates/src/pages/NotFound.tsx +28 -0
- package/templates/src/pages/index.ts +2 -0
- package/templates/src/stores/index.ts +2 -0
- package/templates/src/stores/preferencesStore.ts +85 -0
- package/templates/src/test/index.ts +8 -0
- package/templates/src/test/mocks.ts +17 -0
- package/templates/src/test/providers.tsx +54 -0
- package/templates/src/test-setup.ts +54 -0
- package/templates/src/types/api.ts +31 -0
- package/templates/src/types/index.ts +2 -0
- package/templates/src/types/preferences.ts +5 -0
- package/templates/src/vite-env.d.ts +10 -0
- package/templates/tests/unit/components/ErrorBoundary.test.tsx +193 -0
- package/templates/tests/unit/components/Header.test.tsx +33 -0
- package/templates/tests/unit/components/LanguageSwitcher.test.tsx +40 -0
- package/templates/tests/unit/components/Loading.test.tsx +76 -0
- package/templates/tests/unit/components/SEO.test.tsx +80 -0
- package/templates/tests/unit/components/ThemeToggle.test.tsx +62 -0
- package/templates/tests/unit/contexts/mobileContext.test.tsx +54 -0
- package/templates/tests/unit/hooks/useContactForm.test.ts +60 -0
- package/templates/tests/unit/hooks/useExampleQuery.test.tsx +94 -0
- package/templates/tests/unit/hooks/useLanguage.test.tsx +75 -0
- package/templates/tests/unit/hooks/useMediaQuery.test.ts +57 -0
- package/templates/tests/unit/hooks/useThemeEffect.test.ts +42 -0
- package/templates/tests/unit/i18n/detectLanguage.test.ts +40 -0
- package/templates/tests/unit/i18n/loadCatalog.test.ts +70 -0
- package/templates/tests/unit/lib/api.test.ts +142 -0
- package/templates/tests/unit/lib/format.test.ts +100 -0
- package/templates/tests/unit/lib/storage.test.ts +90 -0
- package/templates/tests/unit/lib/utils.test.ts +19 -0
- package/templates/tests/unit/lib/validations.test.ts +56 -0
- package/templates/tests/unit/stores/preferencesStore.test.ts +75 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
AI assistant guidance for this React 19 + TypeScript + Vite 7 codebase. See [README.md](README.md) for project overview and tech rationale.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm run dev # Dev server at localhost:5173
|
|
9
|
+
npm run build # Production build (typecheck + bundle)
|
|
10
|
+
npm run typecheck # TypeScript only
|
|
11
|
+
npm run lint # ESLint check
|
|
12
|
+
npm run lint:fix # ESLint auto-fix
|
|
13
|
+
npm run format # Prettier format
|
|
14
|
+
npm run test # Vitest once
|
|
15
|
+
npm run test:watch # Vitest watch mode
|
|
16
|
+
npm run test:coverage # Coverage (80% threshold)
|
|
17
|
+
npm run e2e # Playwright E2E
|
|
18
|
+
npm run i18n:extract # Extract translations to .po
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Project Structure
|
|
22
|
+
|
|
23
|
+
See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for full structure and data flow.
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
src/
|
|
27
|
+
├── components/ # ui/ (primitives), layout/, shared/ (features)
|
|
28
|
+
├── contexts/ # React Context providers
|
|
29
|
+
├── hooks/ # Custom hooks
|
|
30
|
+
├── lib/ # api, routes, config, utils, format, storage
|
|
31
|
+
├── pages/ # Lazy-loaded route components
|
|
32
|
+
├── stores/ # Zustand stores
|
|
33
|
+
└── types/ # TypeScript definitions
|
|
34
|
+
|
|
35
|
+
tests/unit/ # Vitest (mirrors src/)
|
|
36
|
+
e2e/ # Playwright tests
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Code Patterns
|
|
40
|
+
|
|
41
|
+
**Imports**: Always use `@/` path alias
|
|
42
|
+
|
|
43
|
+
**Components**: Named exports + `Props` interface. Pages use default exports for lazy loading.
|
|
44
|
+
|
|
45
|
+
**TypeScript**: `type` for unions, `interface` for objects
|
|
46
|
+
|
|
47
|
+
**State hierarchy**: Zustand (persisted) → TanStack Query (server) → Context (UI) → useState (local)
|
|
48
|
+
|
|
49
|
+
See [docs/CODING_STANDARDS.md](docs/CODING_STANDARDS.md) and [docs/COMPONENT_GUIDELINES.md](docs/COMPONENT_GUIDELINES.md).
|
|
50
|
+
|
|
51
|
+
## UI Components (Shadcn/UI)
|
|
52
|
+
|
|
53
|
+
This project uses **Shadcn/UI** with radix-nova style. Components live in `src/components/ui/`.
|
|
54
|
+
|
|
55
|
+
### Adding New Components
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npx shadcn@latest add button # Single component
|
|
59
|
+
npx shadcn@latest add dialog card input # Multiple components
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Pattern**: Import directly (no barrel exports for UI):
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
import { Button } from '@/components/ui/button';
|
|
66
|
+
import { cn } from '@/lib/utils';
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## MCP Servers (PREFER OVER WebSearch)
|
|
70
|
+
|
|
71
|
+
Use MCP servers for documentation lookup. They provide **structured, version-accurate data** directly from source—faster and more reliable than web scraping.
|
|
72
|
+
|
|
73
|
+
### Why MCP over WebSearch?
|
|
74
|
+
|
|
75
|
+
- **Accuracy**: MCP fetches from official sources, not potentially outdated blog posts
|
|
76
|
+
- **Version-aware**: Gets docs for the exact library version you're using
|
|
77
|
+
- **Structured**: Returns code snippets, types, and examples in consistent format
|
|
78
|
+
- **Faster**: Direct API calls vs parsing HTML from search results
|
|
79
|
+
|
|
80
|
+
### Shadcn MCP (UI Components)
|
|
81
|
+
|
|
82
|
+
| Need | Tool |
|
|
83
|
+
| ------------------- | ------------------------------------------------ |
|
|
84
|
+
| Find component | `mcp__shadcn__search_items_in_registries` |
|
|
85
|
+
| View component code | `mcp__shadcn__view_items_in_registries` |
|
|
86
|
+
| Usage examples | `mcp__shadcn__get_item_examples_from_registries` |
|
|
87
|
+
| CLI add command | `mcp__shadcn__get_add_command_for_items` |
|
|
88
|
+
|
|
89
|
+
### Context7 MCP (All 3rd Party Libraries)
|
|
90
|
+
|
|
91
|
+
Use for **any npm package** documentation—not just React libraries:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
resolve-library-id → get-library-docs
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Examples**:
|
|
98
|
+
|
|
99
|
+
- `react-hook-form` - Form validation patterns
|
|
100
|
+
- `@tanstack/react-query` - Query/mutation usage
|
|
101
|
+
- `zustand` - Store patterns
|
|
102
|
+
- `zod` - Schema validation
|
|
103
|
+
- `date-fns` - Date formatting
|
|
104
|
+
- `msw` - Mock service worker setup
|
|
105
|
+
|
|
106
|
+
### Decision Flow
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
Need UI component? → Shadcn MCP
|
|
110
|
+
Need library docs? → Context7 MCP (any npm package)
|
|
111
|
+
Need general info? → WebSearch (fallback only)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Translations (CRITICAL)
|
|
115
|
+
|
|
116
|
+
All user-facing text MUST have translator comments. ESLint enforces this.
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
<Trans comment="Dashboard heading">Welcome back</Trans>;
|
|
120
|
+
t({ message: 'Close', comment: 'Close button' });
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
See [docs/INTERNATIONALIZATION.md](docs/INTERNATIONALIZATION.md).
|
|
124
|
+
|
|
125
|
+
## Testing
|
|
126
|
+
|
|
127
|
+
See [docs/TESTING.md](docs/TESTING.md) and [docs/E2E_TESTING.md](docs/E2E_TESTING.md).
|
|
128
|
+
|
|
129
|
+
Tests in `tests/unit/` mirror `src/` structure. 80% coverage required.
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
133
|
+
import { screen, renderHook } from '@testing-library/react';
|
|
134
|
+
import { render, mockMatchMedia, server } from '@/test';
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
MSW handlers auto-reset after each test.
|
|
138
|
+
|
|
139
|
+
## Common Gotchas
|
|
140
|
+
|
|
141
|
+
1. **Node.js >= 22.0.0** required (check `.nvmrc`)
|
|
142
|
+
2. **Conventional commits** enforced by commitlint
|
|
143
|
+
3. **Context hooks throw** outside provider (e.g., `useMobileContext()`)
|
|
144
|
+
4. **Barrel exports** in each directory via `index.ts`
|
|
145
|
+
5. **UI components** import directly: `@/components/ui/button` (no barrel)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# API Reference
|
|
2
|
+
|
|
3
|
+
Quick reference for what's available. For architectural decisions, see [Architecture Guide](./ARCHITECTURE.md).
|
|
4
|
+
|
|
5
|
+
## Utilities (`lib/`)
|
|
6
|
+
|
|
7
|
+
| Module | Purpose | When to Use |
|
|
8
|
+
| ---------------- | --------------------- | ------------------------------------------------------------------- |
|
|
9
|
+
| `api.ts` | HTTP client | Any API calls - handles errors, timeouts, JSON. Includes API_CONFIG |
|
|
10
|
+
| `config.ts` | App configuration | Access APP_CONFIG, SENTRY_CONFIG |
|
|
11
|
+
| `env.ts` | Environment variables | Type-safe `env.VITE_*` access |
|
|
12
|
+
| `format.ts` | Formatters | Dates, numbers, currency, bytes - all locale-aware |
|
|
13
|
+
| `routes.ts` | Route constants | Type-safe navigation, avoid magic strings |
|
|
14
|
+
| `storage.ts` | localStorage wrapper | SSR-safe, typed storage with error handling |
|
|
15
|
+
| `storageKeys.ts` | Storage key constants | Centralized key management |
|
|
16
|
+
| `utils.ts` | Common utilities | `cn()` for Tailwind class merging |
|
|
17
|
+
|
|
18
|
+
### Key Pattern: API Client
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { api } from '@/lib/api';
|
|
22
|
+
|
|
23
|
+
const data = await api.get<User[]>('/users');
|
|
24
|
+
// Throws ApiClientError on failure (check .status for HTTP code)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Hooks (`hooks/`)
|
|
28
|
+
|
|
29
|
+
| Hook | Purpose | When to Use |
|
|
30
|
+
| ------------------------------ | --------------------- | ------------------------------------ |
|
|
31
|
+
| `useMediaQuery` | Track media query | Custom responsive logic |
|
|
32
|
+
| `useIsMobile` / `useIsDesktop` | Viewport checks | Conditional rendering by screen size |
|
|
33
|
+
| `useLanguage` | Locale state | Language switcher components |
|
|
34
|
+
| `useThemeEffect` | Theme sync | Apply theme to document |
|
|
35
|
+
| `useTouchSizes` | Touch-friendly sizing | Mobile-optimized UI |
|
|
36
|
+
|
|
37
|
+
### Key Pattern: Context Hooks
|
|
38
|
+
|
|
39
|
+
Context hooks throw if used outside their provider:
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
const { isMobile } = useMobileContext();
|
|
43
|
+
// Throws if not wrapped in <MobileProvider>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Contexts (`contexts/`)
|
|
47
|
+
|
|
48
|
+
| Context | Provider | Purpose |
|
|
49
|
+
| --------------- | ---------------- | ---------------------------------------- |
|
|
50
|
+
| `mobileContext` | `MobileProvider` | Viewport detection (isMobile, isDesktop) |
|
|
51
|
+
|
|
52
|
+
## Stores (`stores/`)
|
|
53
|
+
|
|
54
|
+
| Store | Purpose | Persisted? |
|
|
55
|
+
| ------------------ | ------------------------------ | ------------------ |
|
|
56
|
+
| `preferencesStore` | User preferences (theme, etc.) | Yes (localStorage) |
|
|
57
|
+
|
|
58
|
+
Access via Zustand hooks - see store files for available actions.
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Architecture Guide
|
|
2
|
+
|
|
3
|
+
High-level architecture and key decisions. For API details, see [API Reference](./API_REFERENCE.md).
|
|
4
|
+
|
|
5
|
+
## Tech Stack
|
|
6
|
+
|
|
7
|
+
| Layer | Technology | Why |
|
|
8
|
+
| -------------- | ------------------------ | ------------------------------------------- |
|
|
9
|
+
| Framework | React 19 + TypeScript | Largest ecosystem, concurrent features |
|
|
10
|
+
| Build | Vite 7 | 10-100x faster than Webpack, native ESM |
|
|
11
|
+
| Routing | React Router 7 | De facto standard, lazy loading support |
|
|
12
|
+
| Styling | Tailwind CSS 4 | No runtime cost, scales with team size |
|
|
13
|
+
| State | Zustand + TanStack Query | Minimal boilerplate, separation of concerns |
|
|
14
|
+
| Forms | React Hook Form + Zod | Minimal re-renders, type-safe validation |
|
|
15
|
+
| i18n | Lingui | Smaller runtime, compile-time extraction |
|
|
16
|
+
| Testing | Vitest + Playwright | Fast, Vite-native, true cross-browser |
|
|
17
|
+
| Error Tracking | Sentry | Industry standard, lazy-loaded |
|
|
18
|
+
|
|
19
|
+
## Project Structure
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
src/
|
|
23
|
+
├── components/
|
|
24
|
+
│ ├── layout/ # Page structure (Header)
|
|
25
|
+
│ ├── shared/ # Feature components (ThemeToggle, LanguageSwitcher)
|
|
26
|
+
│ └── ui/ # Primitives (Button, Spinner) - shadcn/ui
|
|
27
|
+
├── contexts/ # React Context providers
|
|
28
|
+
├── hooks/ # Custom React hooks
|
|
29
|
+
├── i18n/ # Internationalization setup
|
|
30
|
+
├── lib/ # Utilities, API client, config, routes
|
|
31
|
+
├── locales/ # Translation files (.po)
|
|
32
|
+
├── mocks/ # MSW handlers and fixtures
|
|
33
|
+
├── pages/ # Route page components
|
|
34
|
+
├── stores/ # Zustand stores
|
|
35
|
+
├── test/ # Test utilities and providers
|
|
36
|
+
└── types/ # Shared TypeScript definitions
|
|
37
|
+
|
|
38
|
+
tests/unit/ # Vitest tests (mirrors src/ structure)
|
|
39
|
+
e2e/ # Playwright end-to-end tests
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Why This Structure?
|
|
43
|
+
|
|
44
|
+
- **components/ui/**: Primitives from shadcn/ui. Direct imports (`@/components/ui/button`) because shadcn recommends against barrel exports for tree-shaking.
|
|
45
|
+
- **components/shared/**: Feature components with barrel exports. Each feature folder contains component + index.ts.
|
|
46
|
+
- **lib/**: Pure utilities with no React dependencies. Can be tested without rendering.
|
|
47
|
+
- **pages/**: One component per route. Default exports enable lazy loading.
|
|
48
|
+
|
|
49
|
+
## Data Flow
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
53
|
+
│ App Entry │
|
|
54
|
+
│ main.tsx → Providers → App.tsx → Routes → Pages │
|
|
55
|
+
└─────────────────────────────────────────────────────────────┘
|
|
56
|
+
│
|
|
57
|
+
┌────────────────────┼────────────────────┐
|
|
58
|
+
▼ ▼ ▼
|
|
59
|
+
┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
60
|
+
│ Zustand │ │ TanStack │ │ Context │
|
|
61
|
+
│ Stores │ │ Query │ │ Providers│
|
|
62
|
+
└──────────┘ └──────────┘ └──────────┘
|
|
63
|
+
│ │ │
|
|
64
|
+
Persisted Server State UI State
|
|
65
|
+
Preferences (API Cache) (Mobile, etc)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Key Architectural Decisions
|
|
69
|
+
|
|
70
|
+
### 1. Provider Hierarchy
|
|
71
|
+
|
|
72
|
+
Providers wrap the app in this specific order:
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
<StrictMode>
|
|
76
|
+
<QueryProvider>
|
|
77
|
+
{' '}
|
|
78
|
+
{/* TanStack Query - outermost for global cache */}
|
|
79
|
+
<I18nProvider>
|
|
80
|
+
{' '}
|
|
81
|
+
{/* Lingui - translations available everywhere */}
|
|
82
|
+
<BrowserRouter>
|
|
83
|
+
{' '}
|
|
84
|
+
{/* React Router - routing context */}
|
|
85
|
+
<MobileProvider>
|
|
86
|
+
{' '}
|
|
87
|
+
{/* Viewport - depends on router for SSR */}
|
|
88
|
+
<ErrorBoundary>
|
|
89
|
+
<App />
|
|
90
|
+
<Toaster />
|
|
91
|
+
</ErrorBoundary>
|
|
92
|
+
</MobileProvider>
|
|
93
|
+
</BrowserRouter>
|
|
94
|
+
</I18nProvider>
|
|
95
|
+
</QueryProvider>
|
|
96
|
+
</StrictMode>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Why this order?**
|
|
100
|
+
|
|
101
|
+
- QueryProvider outermost so cache persists across route changes
|
|
102
|
+
- I18nProvider before Router so route components can use translations
|
|
103
|
+
- MobileProvider inside Router for potential SSR viewport detection
|
|
104
|
+
- ErrorBoundary innermost to catch errors in App without breaking providers
|
|
105
|
+
|
|
106
|
+
### 2. State Management Separation
|
|
107
|
+
|
|
108
|
+
| Use Case | Solution | Location | Why |
|
|
109
|
+
| --------------------- | ------------------- | ----------------- | ----------------------------- |
|
|
110
|
+
| User preferences | Zustand + persist | `stores/` | Survives refresh, syncs tabs |
|
|
111
|
+
| Server/async data | TanStack Query | `hooks/use*Query` | Automatic caching, refetching |
|
|
112
|
+
| Shared UI state | React Context | `contexts/` | Prop drilling avoidance |
|
|
113
|
+
| Component-local state | useState/useReducer | Component file | Simplest solution |
|
|
114
|
+
|
|
115
|
+
**Key invariant**: Server state (TanStack Query) and client state (Zustand) never overlap. If data comes from an API, use Query. If it's user preference, use Zustand.
|
|
116
|
+
|
|
117
|
+
### 3. Lazy Loading Strategy
|
|
118
|
+
|
|
119
|
+
Pages are lazy-loaded to reduce initial bundle size:
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
// App.tsx
|
|
123
|
+
const HomePage = lazy(() => import('@/pages/Home').then((m) => ({ default: m.HomePage })));
|
|
124
|
+
|
|
125
|
+
// Routes
|
|
126
|
+
<Suspense fallback={<PageSkeleton />}>
|
|
127
|
+
<Routes>
|
|
128
|
+
<Route path={ROUTES.HOME} element={<HomePage />} />
|
|
129
|
+
</Routes>
|
|
130
|
+
</Suspense>;
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Why pages only?**
|
|
134
|
+
|
|
135
|
+
- Pages are the largest units and least likely to be needed immediately
|
|
136
|
+
- UI components are small and frequently reused—overhead of lazy loading outweighs benefit
|
|
137
|
+
- Shared components may be needed before Suspense resolves
|
|
138
|
+
|
|
139
|
+
### 4. Error Handling Layers
|
|
140
|
+
|
|
141
|
+
| Layer | Mechanism | Catches |
|
|
142
|
+
| ---------- | -------------- | ----------------------- |
|
|
143
|
+
| Component | ErrorBoundary | React render errors |
|
|
144
|
+
| API | ApiClientError | Network/HTTP errors |
|
|
145
|
+
| Global | window.onerror | Uncaught exceptions |
|
|
146
|
+
| Production | Sentry | All errors with context |
|
|
147
|
+
|
|
148
|
+
**Key invariant**: Errors should never silently fail. Every error either:
|
|
149
|
+
|
|
150
|
+
- Shows user feedback (toast, error UI)
|
|
151
|
+
- Logs to console (development)
|
|
152
|
+
- Reports to Sentry (production)
|
|
153
|
+
|
|
154
|
+
### 5. Translation Enforcement
|
|
155
|
+
|
|
156
|
+
All user-facing text must have translator comments. This is enforced by ESLint.
|
|
157
|
+
|
|
158
|
+
**Why mandatory comments?**
|
|
159
|
+
|
|
160
|
+
- Translators lack code context—"Close" could be adjective or verb
|
|
161
|
+
- Comments appear in PO files, reducing translation errors
|
|
162
|
+
- ESLint catches missing comments before merge
|
|
163
|
+
|
|
164
|
+
## Import Conventions
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
// UI primitives: direct import (no barrel)
|
|
168
|
+
import { Button } from '@/components/ui/button';
|
|
169
|
+
|
|
170
|
+
// Shared components: barrel export
|
|
171
|
+
import { ThemeToggle } from '@/components/shared';
|
|
172
|
+
|
|
173
|
+
// Utilities
|
|
174
|
+
import { api } from '@/lib/api';
|
|
175
|
+
import { render } from '@/test';
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Related Docs
|
|
179
|
+
|
|
180
|
+
- [API Reference](./API_REFERENCE.md) - Utilities, hooks, and common patterns
|
|
181
|
+
- [Component Guidelines](./COMPONENT_GUIDELINES.md) - React component blueprint
|
|
182
|
+
- [Coding Standards](./CODING_STANDARDS.md) - TypeScript and state patterns
|
|
183
|
+
- [Testing](./TESTING.md) - Unit testing guidelines
|
|
184
|
+
- [E2E Testing](./E2E_TESTING.md) - Playwright patterns
|
|
185
|
+
- [Internationalization](./INTERNATIONALIZATION.md) - Lingui i18n setup
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Coding Standards
|
|
2
|
+
|
|
3
|
+
See [Architecture Guide](./ARCHITECTURE.md) for project structure and [Component Guidelines](./COMPONENT_GUIDELINES.md) for the complete React component blueprint.
|
|
4
|
+
|
|
5
|
+
## TypeScript
|
|
6
|
+
|
|
7
|
+
Use `type` for unions, `interface` for object shapes:
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
type Theme = 'light' | 'dark' | 'system';
|
|
11
|
+
|
|
12
|
+
interface User {
|
|
13
|
+
id: string;
|
|
14
|
+
name: string;
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## State Management
|
|
19
|
+
|
|
20
|
+
See [Architecture Guide](./ARCHITECTURE.md#state-management) for when to use each solution.
|
|
21
|
+
|
|
22
|
+
### Query Hooks
|
|
23
|
+
|
|
24
|
+
Extract the fetcher function:
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
async function fetchTodos(): Promise<Todo[]> {
|
|
28
|
+
return api.get<Todo[]>('/todos');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function useTodosQuery() {
|
|
32
|
+
return useQuery({
|
|
33
|
+
queryKey: ['todos'],
|
|
34
|
+
queryFn: fetchTodos,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Context Hooks
|
|
40
|
+
|
|
41
|
+
Throw if used outside their provider:
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
const MyContext = createContext<MyValue | null>(null);
|
|
45
|
+
|
|
46
|
+
export function useMyContext() {
|
|
47
|
+
const context = useContext(MyContext);
|
|
48
|
+
if (!context) {
|
|
49
|
+
throw new Error('useMyContext must be used within MyProvider');
|
|
50
|
+
}
|
|
51
|
+
return context;
|
|
52
|
+
}
|
|
53
|
+
```
|