agentic-team-templates 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.
Files changed (103) hide show
  1. package/README.md +280 -0
  2. package/bin/cli.js +5 -0
  3. package/package.json +47 -0
  4. package/src/index.js +521 -0
  5. package/templates/_shared/code-quality.md +162 -0
  6. package/templates/_shared/communication.md +114 -0
  7. package/templates/_shared/core-principles.md +62 -0
  8. package/templates/_shared/git-workflow.md +165 -0
  9. package/templates/_shared/security-fundamentals.md +173 -0
  10. package/templates/blockchain/.cursorrules/defi-patterns.md +520 -0
  11. package/templates/blockchain/.cursorrules/gas-optimization.md +339 -0
  12. package/templates/blockchain/.cursorrules/overview.md +130 -0
  13. package/templates/blockchain/.cursorrules/security.md +318 -0
  14. package/templates/blockchain/.cursorrules/smart-contracts.md +364 -0
  15. package/templates/blockchain/.cursorrules/testing.md +415 -0
  16. package/templates/blockchain/.cursorrules/web3-integration.md +538 -0
  17. package/templates/blockchain/CLAUDE.md +389 -0
  18. package/templates/cli-tools/.cursorrules/architecture.md +412 -0
  19. package/templates/cli-tools/.cursorrules/arguments.md +406 -0
  20. package/templates/cli-tools/.cursorrules/distribution.md +546 -0
  21. package/templates/cli-tools/.cursorrules/error-handling.md +455 -0
  22. package/templates/cli-tools/.cursorrules/overview.md +136 -0
  23. package/templates/cli-tools/.cursorrules/testing.md +537 -0
  24. package/templates/cli-tools/.cursorrules/user-experience.md +545 -0
  25. package/templates/cli-tools/CLAUDE.md +356 -0
  26. package/templates/data-engineering/.cursorrules/data-modeling.md +367 -0
  27. package/templates/data-engineering/.cursorrules/data-quality.md +455 -0
  28. package/templates/data-engineering/.cursorrules/overview.md +85 -0
  29. package/templates/data-engineering/.cursorrules/performance.md +339 -0
  30. package/templates/data-engineering/.cursorrules/pipeline-design.md +280 -0
  31. package/templates/data-engineering/.cursorrules/security.md +460 -0
  32. package/templates/data-engineering/.cursorrules/testing.md +452 -0
  33. package/templates/data-engineering/CLAUDE.md +974 -0
  34. package/templates/devops-sre/.cursorrules/capacity-planning.md +653 -0
  35. package/templates/devops-sre/.cursorrules/change-management.md +584 -0
  36. package/templates/devops-sre/.cursorrules/chaos-engineering.md +651 -0
  37. package/templates/devops-sre/.cursorrules/disaster-recovery.md +641 -0
  38. package/templates/devops-sre/.cursorrules/incident-management.md +565 -0
  39. package/templates/devops-sre/.cursorrules/observability.md +714 -0
  40. package/templates/devops-sre/.cursorrules/overview.md +230 -0
  41. package/templates/devops-sre/.cursorrules/postmortems.md +588 -0
  42. package/templates/devops-sre/.cursorrules/runbooks.md +760 -0
  43. package/templates/devops-sre/.cursorrules/slo-sli.md +617 -0
  44. package/templates/devops-sre/.cursorrules/toil-reduction.md +567 -0
  45. package/templates/devops-sre/CLAUDE.md +1007 -0
  46. package/templates/documentation/.cursorrules/adr.md +277 -0
  47. package/templates/documentation/.cursorrules/api-documentation.md +411 -0
  48. package/templates/documentation/.cursorrules/code-comments.md +253 -0
  49. package/templates/documentation/.cursorrules/maintenance.md +260 -0
  50. package/templates/documentation/.cursorrules/overview.md +82 -0
  51. package/templates/documentation/.cursorrules/readme-standards.md +306 -0
  52. package/templates/documentation/CLAUDE.md +120 -0
  53. package/templates/fullstack/.cursorrules/api-contracts.md +331 -0
  54. package/templates/fullstack/.cursorrules/architecture.md +298 -0
  55. package/templates/fullstack/.cursorrules/overview.md +109 -0
  56. package/templates/fullstack/.cursorrules/shared-types.md +348 -0
  57. package/templates/fullstack/.cursorrules/testing.md +386 -0
  58. package/templates/fullstack/CLAUDE.md +349 -0
  59. package/templates/ml-ai/.cursorrules/data-engineering.md +483 -0
  60. package/templates/ml-ai/.cursorrules/deployment.md +601 -0
  61. package/templates/ml-ai/.cursorrules/model-development.md +538 -0
  62. package/templates/ml-ai/.cursorrules/monitoring.md +658 -0
  63. package/templates/ml-ai/.cursorrules/overview.md +131 -0
  64. package/templates/ml-ai/.cursorrules/security.md +637 -0
  65. package/templates/ml-ai/.cursorrules/testing.md +678 -0
  66. package/templates/ml-ai/CLAUDE.md +1136 -0
  67. package/templates/mobile/.cursorrules/navigation.md +246 -0
  68. package/templates/mobile/.cursorrules/offline-first.md +302 -0
  69. package/templates/mobile/.cursorrules/overview.md +71 -0
  70. package/templates/mobile/.cursorrules/performance.md +345 -0
  71. package/templates/mobile/.cursorrules/testing.md +339 -0
  72. package/templates/mobile/CLAUDE.md +233 -0
  73. package/templates/platform-engineering/.cursorrules/ci-cd.md +778 -0
  74. package/templates/platform-engineering/.cursorrules/developer-experience.md +632 -0
  75. package/templates/platform-engineering/.cursorrules/infrastructure-as-code.md +600 -0
  76. package/templates/platform-engineering/.cursorrules/kubernetes.md +710 -0
  77. package/templates/platform-engineering/.cursorrules/observability.md +747 -0
  78. package/templates/platform-engineering/.cursorrules/overview.md +215 -0
  79. package/templates/platform-engineering/.cursorrules/security.md +855 -0
  80. package/templates/platform-engineering/.cursorrules/testing.md +878 -0
  81. package/templates/platform-engineering/CLAUDE.md +850 -0
  82. package/templates/utility-agent/.cursorrules/action-control.md +284 -0
  83. package/templates/utility-agent/.cursorrules/context-management.md +186 -0
  84. package/templates/utility-agent/.cursorrules/hallucination-prevention.md +253 -0
  85. package/templates/utility-agent/.cursorrules/overview.md +78 -0
  86. package/templates/utility-agent/.cursorrules/token-optimization.md +369 -0
  87. package/templates/utility-agent/CLAUDE.md +513 -0
  88. package/templates/web-backend/.cursorrules/api-design.md +255 -0
  89. package/templates/web-backend/.cursorrules/authentication.md +309 -0
  90. package/templates/web-backend/.cursorrules/database-patterns.md +298 -0
  91. package/templates/web-backend/.cursorrules/error-handling.md +366 -0
  92. package/templates/web-backend/.cursorrules/overview.md +69 -0
  93. package/templates/web-backend/.cursorrules/security.md +358 -0
  94. package/templates/web-backend/.cursorrules/testing.md +395 -0
  95. package/templates/web-backend/CLAUDE.md +366 -0
  96. package/templates/web-frontend/.cursorrules/accessibility.md +296 -0
  97. package/templates/web-frontend/.cursorrules/component-patterns.md +204 -0
  98. package/templates/web-frontend/.cursorrules/overview.md +72 -0
  99. package/templates/web-frontend/.cursorrules/performance.md +325 -0
  100. package/templates/web-frontend/.cursorrules/state-management.md +227 -0
  101. package/templates/web-frontend/.cursorrules/styling.md +271 -0
  102. package/templates/web-frontend/.cursorrules/testing.md +311 -0
  103. package/templates/web-frontend/CLAUDE.md +399 -0
@@ -0,0 +1,311 @@
1
+ # Frontend Testing
2
+
3
+ Guidelines for testing frontend applications effectively.
4
+
5
+ ## Testing Philosophy
6
+
7
+ ### Test User Behavior, Not Implementation
8
+
9
+ Focus on what users see and do, not internal component details.
10
+
11
+ ```tsx
12
+ // Good: Test what user sees
13
+ test('shows error when form is invalid', async () => {
14
+ render(<LoginForm />);
15
+
16
+ await userEvent.click(screen.getByRole('button', { name: /submit/i }));
17
+
18
+ expect(screen.getByText(/email is required/i)).toBeInTheDocument();
19
+ });
20
+
21
+ // Bad: Test implementation details
22
+ test('sets hasError state to true', () => {
23
+ const { result } = renderHook(() => useLoginForm());
24
+
25
+ act(() => result.current.validate());
26
+
27
+ expect(result.current.hasError).toBe(true); // Testing internal state
28
+ });
29
+ ```
30
+
31
+ ### The Testing Trophy
32
+
33
+ Prioritize tests by confidence and cost:
34
+ 1. **Static Analysis** (TypeScript, ESLint) - Cheap, fast
35
+ 2. **Unit Tests** - Pure functions, utilities
36
+ 3. **Integration Tests** - Components working together
37
+ 4. **E2E Tests** - Critical user flows
38
+
39
+ ## Unit Tests
40
+
41
+ For pure functions and utilities.
42
+
43
+ ```ts
44
+ // utils/formatCurrency.test.ts
45
+ import { formatCurrency } from './formatCurrency';
46
+
47
+ describe('formatCurrency', () => {
48
+ it('formats USD correctly', () => {
49
+ expect(formatCurrency(1234.56, 'USD')).toBe('$1,234.56');
50
+ });
51
+
52
+ it('handles zero', () => {
53
+ expect(formatCurrency(0, 'USD')).toBe('$0.00');
54
+ });
55
+
56
+ it('handles negative values', () => {
57
+ expect(formatCurrency(-50, 'USD')).toBe('-$50.00');
58
+ });
59
+ });
60
+ ```
61
+
62
+ ## Component Tests
63
+
64
+ Test components as users interact with them.
65
+
66
+ ### Basic Component Test
67
+
68
+ ```tsx
69
+ import { render, screen } from '@testing-library/react';
70
+ import userEvent from '@testing-library/user-event';
71
+ import { Counter } from './Counter';
72
+
73
+ describe('Counter', () => {
74
+ it('increments when plus button is clicked', async () => {
75
+ const user = userEvent.setup();
76
+ render(<Counter initialValue={0} />);
77
+
78
+ await user.click(screen.getByRole('button', { name: /increment/i }));
79
+
80
+ expect(screen.getByText('1')).toBeInTheDocument();
81
+ });
82
+
83
+ it('calls onChange with new value', async () => {
84
+ const user = userEvent.setup();
85
+ const handleChange = vi.fn();
86
+ render(<Counter initialValue={0} onChange={handleChange} />);
87
+
88
+ await user.click(screen.getByRole('button', { name: /increment/i }));
89
+
90
+ expect(handleChange).toHaveBeenCalledWith(1);
91
+ });
92
+ });
93
+ ```
94
+
95
+ ### Testing Forms
96
+
97
+ ```tsx
98
+ describe('LoginForm', () => {
99
+ it('submits form with email and password', async () => {
100
+ const user = userEvent.setup();
101
+ const handleSubmit = vi.fn();
102
+ render(<LoginForm onSubmit={handleSubmit} />);
103
+
104
+ await user.type(screen.getByLabelText(/email/i), 'user@example.com');
105
+ await user.type(screen.getByLabelText(/password/i), 'password123');
106
+ await user.click(screen.getByRole('button', { name: /sign in/i }));
107
+
108
+ expect(handleSubmit).toHaveBeenCalledWith({
109
+ email: 'user@example.com',
110
+ password: 'password123',
111
+ });
112
+ });
113
+
114
+ it('shows validation errors', async () => {
115
+ const user = userEvent.setup();
116
+ render(<LoginForm onSubmit={vi.fn()} />);
117
+
118
+ await user.click(screen.getByRole('button', { name: /sign in/i }));
119
+
120
+ expect(screen.getByText(/email is required/i)).toBeInTheDocument();
121
+ expect(screen.getByText(/password is required/i)).toBeInTheDocument();
122
+ });
123
+ });
124
+ ```
125
+
126
+ ### Testing Async Operations
127
+
128
+ ```tsx
129
+ describe('UserProfile', () => {
130
+ it('shows loading state then user data', async () => {
131
+ render(<UserProfile userId="123" />);
132
+
133
+ // Loading state
134
+ expect(screen.getByText(/loading/i)).toBeInTheDocument();
135
+
136
+ // Wait for data
137
+ expect(await screen.findByText('John Doe')).toBeInTheDocument();
138
+ expect(screen.queryByText(/loading/i)).not.toBeInTheDocument();
139
+ });
140
+
141
+ it('shows error state on failure', async () => {
142
+ server.use(
143
+ rest.get('/api/users/:id', (req, res, ctx) => {
144
+ return res(ctx.status(500));
145
+ })
146
+ );
147
+
148
+ render(<UserProfile userId="123" />);
149
+
150
+ expect(await screen.findByText(/failed to load/i)).toBeInTheDocument();
151
+ });
152
+ });
153
+ ```
154
+
155
+ ## Accessibility Tests
156
+
157
+ ```tsx
158
+ import { axe, toHaveNoViolations } from 'jest-axe';
159
+
160
+ expect.extend(toHaveNoViolations);
161
+
162
+ describe('Button', () => {
163
+ it('has no accessibility violations', async () => {
164
+ const { container } = render(<Button>Click me</Button>);
165
+ const results = await axe(container);
166
+ expect(results).toHaveNoViolations();
167
+ });
168
+ });
169
+ ```
170
+
171
+ ## E2E Tests
172
+
173
+ For critical user journeys.
174
+
175
+ ```ts
176
+ // e2e/checkout.spec.ts
177
+ import { test, expect } from '@playwright/test';
178
+
179
+ test.describe('Checkout Flow', () => {
180
+ test('user can complete purchase', async ({ page }) => {
181
+ // Add item to cart
182
+ await page.goto('/products');
183
+ await page.click('[data-testid="product-1"] >> text=Add to Cart');
184
+
185
+ // Go to cart
186
+ await page.click('text=Cart (1)');
187
+ expect(page.url()).toContain('/cart');
188
+
189
+ // Proceed to checkout
190
+ await page.click('text=Checkout');
191
+
192
+ // Fill shipping info
193
+ await page.fill('[name="email"]', 'test@example.com');
194
+ await page.fill('[name="address"]', '123 Main St');
195
+
196
+ // Complete purchase
197
+ await page.click('text=Place Order');
198
+
199
+ // Verify success
200
+ await expect(page.locator('text=Order Confirmed')).toBeVisible();
201
+ });
202
+ });
203
+ ```
204
+
205
+ ## Mocking
206
+
207
+ ### Mock API Calls
208
+
209
+ ```tsx
210
+ import { rest } from 'msw';
211
+ import { setupServer } from 'msw/node';
212
+
213
+ const server = setupServer(
214
+ rest.get('/api/users', (req, res, ctx) => {
215
+ return res(ctx.json([
216
+ { id: 1, name: 'John' },
217
+ { id: 2, name: 'Jane' },
218
+ ]));
219
+ })
220
+ );
221
+
222
+ beforeAll(() => server.listen());
223
+ afterEach(() => server.resetHandlers());
224
+ afterAll(() => server.close());
225
+ ```
226
+
227
+ ### Mock Modules
228
+
229
+ ```tsx
230
+ vi.mock('./analytics', () => ({
231
+ trackEvent: vi.fn(),
232
+ }));
233
+
234
+ import { trackEvent } from './analytics';
235
+
236
+ test('tracks button click', async () => {
237
+ const user = userEvent.setup();
238
+ render(<TrackedButton />);
239
+
240
+ await user.click(screen.getByRole('button'));
241
+
242
+ expect(trackEvent).toHaveBeenCalledWith('button_click');
243
+ });
244
+ ```
245
+
246
+ ## Best Practices
247
+
248
+ ### Query Priority
249
+
250
+ Use queries in this order (most accessible first):
251
+ 1. `getByRole` - Accessible to everyone
252
+ 2. `getByLabelText` - Good for form fields
253
+ 3. `getByPlaceholderText` - Less ideal but okay
254
+ 4. `getByText` - For non-interactive content
255
+ 5. `getByTestId` - Last resort
256
+
257
+ ### Avoid Testing Implementation Details
258
+
259
+ ```tsx
260
+ // Bad: Testing internal state
261
+ expect(component.state.isOpen).toBe(true);
262
+
263
+ // Bad: Testing class names
264
+ expect(container.querySelector('.modal--open')).toBeInTheDocument();
265
+
266
+ // Good: Testing what user sees
267
+ expect(screen.getByRole('dialog')).toBeVisible();
268
+ ```
269
+
270
+ ### One Assertion Per Concept
271
+
272
+ ```tsx
273
+ // Good: Focused tests
274
+ it('shows user name', () => {
275
+ render(<UserCard user={mockUser} />);
276
+ expect(screen.getByText('John Doe')).toBeInTheDocument();
277
+ });
278
+
279
+ it('shows user email', () => {
280
+ render(<UserCard user={mockUser} />);
281
+ expect(screen.getByText('john@example.com')).toBeInTheDocument();
282
+ });
283
+
284
+ // Acceptable: Related assertions
285
+ it('shows user info', () => {
286
+ render(<UserCard user={mockUser} />);
287
+ expect(screen.getByText('John Doe')).toBeInTheDocument();
288
+ expect(screen.getByText('john@example.com')).toBeInTheDocument();
289
+ });
290
+ ```
291
+
292
+ ## Test Organization
293
+
294
+ ```
295
+ src/
296
+ ├── components/
297
+ │ └── Button/
298
+ │ ├── Button.tsx
299
+ │ └── Button.test.tsx # Co-located unit tests
300
+ ├── features/
301
+ │ └── auth/
302
+ │ └── __tests__/ # Feature integration tests
303
+ │ └── login.test.tsx
304
+ └── test/
305
+ ├── setup.ts # Test configuration
306
+ └── utils.tsx # Test utilities
307
+
308
+ e2e/
309
+ ├── auth.spec.ts # E2E tests
310
+ └── checkout.spec.ts
311
+ ```
@@ -0,0 +1,399 @@
1
+ # Web Frontend Development Guide
2
+
3
+ Comprehensive guidelines for building modern web frontend applications.
4
+
5
+ ---
6
+
7
+ ## Overview
8
+
9
+ This guide applies to:
10
+ - Single-page applications (SPAs)
11
+ - Server-rendered web applications
12
+ - Static sites with dynamic components
13
+ - Progressive web applications (PWAs)
14
+
15
+ ### Key Principles
16
+
17
+ 1. **User Experience First** - Fast, responsive, accessible
18
+ 2. **Component-Based Architecture** - Small, focused, reusable
19
+ 3. **Type Safety** - TypeScript for all new code
20
+ 4. **Progressive Enhancement** - Core functionality without JS
21
+
22
+ ### Project Structure
23
+
24
+ ```
25
+ src/
26
+ ├── components/ # Reusable UI components
27
+ │ ├── ui/ # Primitive components (Button, Input, Card)
28
+ │ └── features/ # Feature-specific components
29
+ ├── pages/ # Page/route components
30
+ ├── hooks/ # Custom hooks
31
+ ├── lib/ # Business logic, utilities
32
+ ├── types/ # TypeScript type definitions
33
+ ├── styles/ # Global styles, theme
34
+ └── assets/ # Static assets
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Component Patterns
40
+
41
+ ### Composition Over Inheritance
42
+
43
+ ```tsx
44
+ // Good: Composition
45
+ const UserCard = ({ user }: { user: User }) => (
46
+ <Card>
47
+ <Avatar src={user.avatar} />
48
+ <CardContent>
49
+ <UserName name={user.name} />
50
+ </CardContent>
51
+ </Card>
52
+ );
53
+
54
+ // Bad: Inheritance
55
+ class UserCard extends BaseCard { ... }
56
+ ```
57
+
58
+ ### Pure Components
59
+
60
+ Same props = same output. No side effects in render.
61
+
62
+ ```tsx
63
+ // Good: Pure
64
+ const Greeting = ({ name }: { name: string }) => (
65
+ <h1>Hello, {name}!</h1>
66
+ );
67
+
68
+ // Bad: Side effects
69
+ const Greeting = ({ name }) => {
70
+ document.title = name; // Side effect!
71
+ return <h1>Hello, {name}!</h1>;
72
+ };
73
+ ```
74
+
75
+ ### Props Interface
76
+
77
+ ```tsx
78
+ interface ButtonProps {
79
+ variant: 'primary' | 'secondary' | 'danger';
80
+ size?: 'sm' | 'md' | 'lg';
81
+ disabled?: boolean;
82
+ onClick: () => void;
83
+ children: React.ReactNode;
84
+ }
85
+
86
+ const Button = ({ variant, size = 'md', ...props }: ButtonProps) => ( ... );
87
+ ```
88
+
89
+ ### Conditional Rendering
90
+
91
+ ```tsx
92
+ // Early return for guards
93
+ const UserProfile = ({ user }: { user: User | null }) => {
94
+ if (!user) return <NotLoggedIn />;
95
+ return <Profile user={user} />;
96
+ };
97
+
98
+ // Ternary for simple conditions
99
+ const Status = ({ isActive }: { isActive: boolean }) => (
100
+ <span>{isActive ? 'Active' : 'Inactive'}</span>
101
+ );
102
+
103
+ // && for optional rendering
104
+ {message && <Alert>{message}</Alert>}
105
+ ```
106
+
107
+ ---
108
+
109
+ ## State Management
110
+
111
+ ### Principles
112
+
113
+ 1. **Lift State Only When Necessary** - Keep state close to where it's used
114
+ 2. **Derive Don't Duplicate** - Calculate from existing state
115
+ 3. **Immutable Updates** - Never mutate state directly
116
+
117
+ ### Local State
118
+
119
+ ```tsx
120
+ // Simple values
121
+ const [count, setCount] = useState(0);
122
+
123
+ // Complex state
124
+ const [state, dispatch] = useReducer(reducer, initialState);
125
+ ```
126
+
127
+ ### Shared State
128
+
129
+ ```tsx
130
+ // Context for global UI/auth/theme
131
+ const ThemeContext = createContext<Theme>('light');
132
+
133
+ const ThemeProvider = ({ children }) => {
134
+ const [theme, setTheme] = useState<Theme>('light');
135
+ return (
136
+ <ThemeContext.Provider value={{ theme, setTheme }}>
137
+ {children}
138
+ </ThemeContext.Provider>
139
+ );
140
+ };
141
+ ```
142
+
143
+ ### Immutable Updates
144
+
145
+ ```tsx
146
+ // Good
147
+ setItems(items => [...items, newItem]);
148
+ setUser(user => ({ ...user, name: newName }));
149
+
150
+ // Bad: Mutation
151
+ items.push(newItem);
152
+ setItems(items);
153
+ ```
154
+
155
+ ### Anti-Patterns
156
+
157
+ - **Prop Drilling**: Use context or composition
158
+ - **Over-Centralization**: Keep local state local
159
+ - **Stale Closures**: Use refs or functional updates
160
+
161
+ ---
162
+
163
+ ## Styling
164
+
165
+ ### Principles
166
+
167
+ - Consistency via design system
168
+ - Maintainability via component-scoped styles
169
+ - Mobile-first responsive design
170
+ - Performance-conscious CSS
171
+
172
+ ### Responsive Design
173
+
174
+ ```css
175
+ /* Base: Mobile */
176
+ .container { padding: 1rem; }
177
+
178
+ /* Tablet */
179
+ @media (min-width: 768px) {
180
+ .container { padding: 2rem; }
181
+ }
182
+
183
+ /* Desktop */
184
+ @media (min-width: 1024px) {
185
+ .container { padding: 3rem; max-width: 1200px; }
186
+ }
187
+ ```
188
+
189
+ ### CSS Custom Properties
190
+
191
+ ```css
192
+ :root {
193
+ --color-primary: #3b82f6;
194
+ --color-text: #1e293b;
195
+ --spacing-md: 1rem;
196
+ --radius-md: 0.5rem;
197
+ }
198
+
199
+ [data-theme="dark"] {
200
+ --color-text: #f1f5f9;
201
+ }
202
+ ```
203
+
204
+ ### Anti-Patterns
205
+
206
+ - Avoid `!important`
207
+ - Avoid inline styles for theming
208
+ - Avoid magic numbers
209
+
210
+ ---
211
+
212
+ ## Accessibility (a11y)
213
+
214
+ ### Semantic HTML
215
+
216
+ ```html
217
+ <!-- Good -->
218
+ <nav><ul><li><a href="/home">Home</a></li></ul></nav>
219
+ <main><article><h1>Title</h1></article></main>
220
+ <button onClick={fn}>Submit</button>
221
+
222
+ <!-- Bad -->
223
+ <div class="nav"><div onclick="...">Home</div></div>
224
+ ```
225
+
226
+ ### Keyboard Navigation
227
+
228
+ - All interactive elements must be keyboard accessible
229
+ - Visible focus indicators
230
+ - Skip links for main content
231
+ - Focus trapping for modals
232
+
233
+ ### ARIA
234
+
235
+ Use only when native HTML is insufficient:
236
+
237
+ ```tsx
238
+ <button aria-expanded={isOpen} aria-controls="menu">Menu</button>
239
+ <input aria-invalid={hasError} aria-describedby="error-msg" />
240
+ <div aria-live="polite">{statusMessage}</div>
241
+ ```
242
+
243
+ ### Forms
244
+
245
+ Every input needs a label:
246
+
247
+ ```tsx
248
+ <label htmlFor="email">Email</label>
249
+ <input id="email" type="email" />
250
+ ```
251
+
252
+ ### Color and Contrast
253
+
254
+ - Normal text: 4.5:1 contrast ratio
255
+ - Large text: 3:1 contrast ratio
256
+ - Don't rely on color alone
257
+
258
+ ### Testing Checklist
259
+
260
+ - [ ] Navigate with keyboard only
261
+ - [ ] Test with screen reader
262
+ - [ ] Check color contrast
263
+ - [ ] Verify focus indicators
264
+ - [ ] Test at 200% zoom
265
+
266
+ ---
267
+
268
+ ## Testing
269
+
270
+ ### Philosophy
271
+
272
+ Test user behavior, not implementation details.
273
+
274
+ ### Unit Tests (Pure Functions)
275
+
276
+ ```ts
277
+ describe('formatCurrency', () => {
278
+ it('formats USD correctly', () => {
279
+ expect(formatCurrency(1234.56, 'USD')).toBe('$1,234.56');
280
+ });
281
+ });
282
+ ```
283
+
284
+ ### Component Tests
285
+
286
+ ```tsx
287
+ import { render, screen } from '@testing-library/react';
288
+ import userEvent from '@testing-library/user-event';
289
+
290
+ test('shows error when form is invalid', async () => {
291
+ render(<LoginForm />);
292
+ await userEvent.click(screen.getByRole('button', { name: /submit/i }));
293
+ expect(screen.getByText(/email is required/i)).toBeInTheDocument();
294
+ });
295
+ ```
296
+
297
+ ### Accessibility Tests
298
+
299
+ ```tsx
300
+ import { axe, toHaveNoViolations } from 'jest-axe';
301
+
302
+ test('has no a11y violations', async () => {
303
+ const { container } = render(<Button>Click</Button>);
304
+ expect(await axe(container)).toHaveNoViolations();
305
+ });
306
+ ```
307
+
308
+ ### Query Priority
309
+
310
+ 1. `getByRole` - Most accessible
311
+ 2. `getByLabelText` - For form fields
312
+ 3. `getByText` - For content
313
+ 4. `getByTestId` - Last resort
314
+
315
+ ### E2E Tests (Critical Paths)
316
+
317
+ ```ts
318
+ test('user can complete purchase', async ({ page }) => {
319
+ await page.goto('/products');
320
+ await page.click('text=Add to Cart');
321
+ await page.click('text=Checkout');
322
+ await expect(page.locator('text=Order Confirmed')).toBeVisible();
323
+ });
324
+ ```
325
+
326
+ ---
327
+
328
+ ## Performance
329
+
330
+ ### Core Web Vitals
331
+
332
+ - **LCP** (Largest Contentful Paint): < 2.5s
333
+ - **FID/INP** (Interactivity): < 100ms / < 200ms
334
+ - **CLS** (Layout Shift): < 0.1
335
+
336
+ ### Code Splitting
337
+
338
+ ```tsx
339
+ const Dashboard = lazy(() => import('./pages/Dashboard'));
340
+
341
+ <Suspense fallback={<Loading />}>
342
+ <Dashboard />
343
+ </Suspense>
344
+ ```
345
+
346
+ ### Minimize Bundle Size
347
+
348
+ ```tsx
349
+ // Bad: Import entire library
350
+ import _ from 'lodash';
351
+
352
+ // Good: Import specific function
353
+ import debounce from 'lodash/debounce';
354
+ ```
355
+
356
+ ### Prevent Re-renders
357
+
358
+ ```tsx
359
+ // Memoize expensive components
360
+ const ExpensiveList = memo(({ items }) => ...);
361
+
362
+ // Memoize calculations
363
+ const sorted = useMemo(() => items.sort(...), [items]);
364
+
365
+ // Memoize callbacks
366
+ const handleClick = useCallback(() => ..., []);
367
+ ```
368
+
369
+ ### Virtualize Long Lists
370
+
371
+ Use virtualization libraries for lists with 100+ items.
372
+
373
+ ### Image Optimization
374
+
375
+ - Use modern formats (WebP, AVIF)
376
+ - Lazy load images
377
+ - Always specify dimensions
378
+
379
+ ### Performance Budgets
380
+
381
+ - JavaScript: < 200KB gzipped
382
+ - CSS: < 50KB gzipped
383
+ - LCP: < 2.5s
384
+
385
+ ---
386
+
387
+ ## Definition of Done
388
+
389
+ A frontend feature is complete when:
390
+
391
+ - [ ] Component renders correctly
392
+ - [ ] Responsive across breakpoints
393
+ - [ ] Keyboard navigable
394
+ - [ ] Screen reader accessible
395
+ - [ ] Loading and error states handled
396
+ - [ ] Tests written and passing
397
+ - [ ] No TypeScript errors
398
+ - [ ] Meets performance budgets
399
+ - [ ] Code reviewed and approved