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,366 @@
1
+ # Web Backend Development Guide
2
+
3
+ Comprehensive guidelines for building robust backend APIs and services.
4
+
5
+ ---
6
+
7
+ ## Overview
8
+
9
+ This guide applies to:
10
+ - RESTful APIs
11
+ - GraphQL APIs
12
+ - Microservices
13
+ - Backend-for-frontend (BFF) services
14
+
15
+ ### Key Principles
16
+
17
+ 1. **Security First** - Every input is hostile until validated
18
+ 2. **Reliability** - Handle errors gracefully, fail fast
19
+ 3. **Observability** - Log meaningfully, track metrics
20
+ 4. **Scalability** - Design for horizontal scaling
21
+
22
+ ### Project Structure
23
+
24
+ ```
25
+ src/
26
+ ├── routes/ # Route handlers/controllers
27
+ ├── services/ # Business logic
28
+ ├── repositories/ # Data access layer
29
+ ├── middleware/ # Request/response middleware
30
+ ├── lib/ # Shared utilities
31
+ ├── types/ # TypeScript definitions
32
+ ├── validation/ # Input validation schemas
33
+ └── config/ # Configuration management
34
+ ```
35
+
36
+ ---
37
+
38
+ ## API Design
39
+
40
+ ### RESTful Conventions
41
+
42
+ ```
43
+ GET /users # List users
44
+ POST /users # Create user
45
+ GET /users/:id # Get user
46
+ PUT /users/:id # Update user
47
+ DELETE /users/:id # Delete user
48
+ GET /users/:id/posts # Get user's posts
49
+ ```
50
+
51
+ ### HTTP Status Codes
52
+
53
+ **Success**: 200 OK, 201 Created, 204 No Content
54
+ **Client Errors**: 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 422 Validation Error, 429 Rate Limited
55
+ **Server Errors**: 500 Internal Error, 502 Bad Gateway, 503 Service Unavailable
56
+
57
+ ### Response Format
58
+
59
+ ```json
60
+ // Success
61
+ { "data": { "id": "123", "name": "John" } }
62
+
63
+ // Error
64
+ {
65
+ "error": {
66
+ "code": "VALIDATION_ERROR",
67
+ "message": "Validation failed",
68
+ "details": [{ "field": "email", "message": "Invalid format" }]
69
+ }
70
+ }
71
+
72
+ // Collection
73
+ {
74
+ "data": [...],
75
+ "pagination": { "page": 1, "limit": 20, "total": 150 }
76
+ }
77
+ ```
78
+
79
+ ### Query Parameters
80
+
81
+ - **Filtering**: `?role=admin&status=active`
82
+ - **Sorting**: `?sort=-createdAt` (prefix `-` for descending)
83
+ - **Pagination**: `?page=2&limit=20` or `?cursor=xyz&limit=20`
84
+ - **Fields**: `?fields=id,name,email`
85
+
86
+ ---
87
+
88
+ ## Database Patterns
89
+
90
+ ### Data Access Layer
91
+
92
+ ```ts
93
+ // repository/userRepository.ts
94
+ export const userRepository = {
95
+ async findById(id: string): Promise<User | null> {
96
+ return db.user.findUnique({ where: { id } });
97
+ },
98
+ async create(data: CreateUserInput): Promise<User> {
99
+ return db.user.create({ data });
100
+ },
101
+ };
102
+ ```
103
+
104
+ ### Transactions
105
+
106
+ ```ts
107
+ await db.$transaction(async (tx) => {
108
+ const order = await tx.order.create({ data: orderData });
109
+ await tx.inventory.update({ ... });
110
+ await tx.payment.create({ ... });
111
+ });
112
+ ```
113
+
114
+ ### Avoid N+1 Queries
115
+
116
+ ```ts
117
+ // Bad: N+1
118
+ const posts = await db.post.findMany();
119
+ for (const post of posts) {
120
+ post.author = await db.user.findUnique({ where: { id: post.authorId } });
121
+ }
122
+
123
+ // Good: Include
124
+ const posts = await db.post.findMany({ include: { author: true } });
125
+ ```
126
+
127
+ ### Use Indexes
128
+
129
+ ```sql
130
+ CREATE INDEX idx_users_email ON users(email);
131
+ CREATE INDEX idx_posts_user_created ON posts(user_id, created_at);
132
+ ```
133
+
134
+ ---
135
+
136
+ ## Authentication & Authorization
137
+
138
+ ### JWT Authentication
139
+
140
+ ```ts
141
+ const generateToken = (user: User): string => {
142
+ return jwt.sign(
143
+ { sub: user.id, email: user.email, role: user.role },
144
+ process.env.JWT_SECRET,
145
+ { expiresIn: '15m' }
146
+ );
147
+ };
148
+ ```
149
+
150
+ ### Authorization Middleware
151
+
152
+ ```ts
153
+ const requirePermission = (permission: string) => {
154
+ return (req, res, next) => {
155
+ const userPermissions = permissions[req.user.role] || [];
156
+ if (!userPermissions.includes(permission)) {
157
+ return res.status(403).json({ error: 'Forbidden' });
158
+ }
159
+ next();
160
+ };
161
+ };
162
+ ```
163
+
164
+ ### Password Security
165
+
166
+ - Hash with bcrypt (12+ rounds)
167
+ - Enforce minimum requirements
168
+ - Rate limit login attempts
169
+
170
+ ### Security Best Practices
171
+
172
+ - Short-lived access tokens + refresh tokens
173
+ - HTTP-only, Secure, SameSite cookies
174
+ - CSRF tokens for session-based auth
175
+ - Never log credentials
176
+
177
+ ---
178
+
179
+ ## Error Handling
180
+
181
+ ### Custom Error Classes
182
+
183
+ ```ts
184
+ class AppError extends Error {
185
+ constructor(
186
+ public statusCode: number,
187
+ public code: string,
188
+ message: string,
189
+ public details?: unknown
190
+ ) {
191
+ super(message);
192
+ }
193
+ }
194
+
195
+ class ValidationError extends AppError {
196
+ constructor(message: string, details?: ValidationDetail[]) {
197
+ super(422, 'VALIDATION_ERROR', message, details);
198
+ }
199
+ }
200
+
201
+ class NotFoundError extends AppError {
202
+ constructor(resource: string, id: string) {
203
+ super(404, 'NOT_FOUND', `${resource} with id ${id} not found`);
204
+ }
205
+ }
206
+ ```
207
+
208
+ ### Global Error Handler
209
+
210
+ ```ts
211
+ const errorHandler = (err: Error, req: Request, res: Response, next: NextFunction) => {
212
+ logger.error({ error: err.message, stack: err.stack, requestId: req.id });
213
+
214
+ if (err instanceof AppError) {
215
+ return res.status(err.statusCode).json({
216
+ error: { code: err.code, message: err.message, details: err.details },
217
+ });
218
+ }
219
+
220
+ res.status(500).json({
221
+ error: { code: 'INTERNAL_ERROR', message: 'An unexpected error occurred' },
222
+ });
223
+ };
224
+ ```
225
+
226
+ ### Result Types
227
+
228
+ ```ts
229
+ type Result<T, E = Error> = { ok: true; value: T } | { ok: false; error: E };
230
+
231
+ const findUser = async (id: string): Promise<Result<User, NotFoundError>> => {
232
+ const user = await db.user.findUnique({ where: { id } });
233
+ return user ? { ok: true, value: user } : { ok: false, error: new NotFoundError('User', id) };
234
+ };
235
+ ```
236
+
237
+ ---
238
+
239
+ ## Security
240
+
241
+ ### Input Validation
242
+
243
+ ```ts
244
+ import { z } from 'zod';
245
+
246
+ const CreateUserSchema = z.object({
247
+ email: z.string().email().max(255),
248
+ name: z.string().min(1).max(100),
249
+ role: z.enum(['user', 'admin']).default('user'),
250
+ });
251
+
252
+ const result = CreateUserSchema.safeParse(req.body);
253
+ if (!result.success) {
254
+ return res.status(422).json({ error: { details: result.error.errors } });
255
+ }
256
+ ```
257
+
258
+ ### Injection Prevention
259
+
260
+ ```ts
261
+ // SQL: Always use parameterized queries
262
+ const users = await db.query('SELECT * FROM users WHERE id = $1', [userId]);
263
+
264
+ // Command: Use execFile with array arguments
265
+ execFile('convert', [inputPath, '-resize', '800x600', outputPath]);
266
+ ```
267
+
268
+ ### Rate Limiting
269
+
270
+ ```ts
271
+ const authLimiter = rateLimit({
272
+ windowMs: 15 * 60 * 1000,
273
+ max: 5,
274
+ message: { error: 'Too many attempts' },
275
+ });
276
+
277
+ app.post('/login', authLimiter, loginHandler);
278
+ ```
279
+
280
+ ### Security Headers
281
+
282
+ ```ts
283
+ app.use(helmet({
284
+ contentSecurityPolicy: { ... },
285
+ hsts: { maxAge: 31536000, includeSubDomains: true },
286
+ }));
287
+ ```
288
+
289
+ ### Security Checklist
290
+
291
+ - [ ] All inputs validated
292
+ - [ ] Parameterized queries
293
+ - [ ] Rate limiting in place
294
+ - [ ] Auth required on protected routes
295
+ - [ ] Security headers configured
296
+ - [ ] Secrets not in code or logs
297
+ - [ ] HTTPS enforced
298
+ - [ ] Dependencies audited
299
+
300
+ ---
301
+
302
+ ## Testing
303
+
304
+ ### Unit Tests
305
+
306
+ ```ts
307
+ describe('calculateDiscount', () => {
308
+ it('applies percentage discount', () => {
309
+ expect(calculateDiscount(100, { type: 'percentage', value: 10 })).toBe(90);
310
+ });
311
+ });
312
+ ```
313
+
314
+ ### Integration Tests
315
+
316
+ ```ts
317
+ describe('userRepository', () => {
318
+ beforeEach(async () => await db.user.deleteMany());
319
+
320
+ it('creates a user', async () => {
321
+ const user = await userRepository.create({ email: 'test@example.com', name: 'Test' });
322
+ expect(user.id).toBeDefined();
323
+ });
324
+ });
325
+ ```
326
+
327
+ ### API Tests
328
+
329
+ ```ts
330
+ describe('POST /users', () => {
331
+ it('creates a new user', async () => {
332
+ const response = await request(app)
333
+ .post('/users')
334
+ .set('Authorization', `Bearer ${authToken}`)
335
+ .send({ email: 'new@test.com', name: 'New User' });
336
+
337
+ expect(response.status).toBe(201);
338
+ expect(response.body.data.email).toBe('new@test.com');
339
+ });
340
+
341
+ it('validates email format', async () => {
342
+ const response = await request(app)
343
+ .post('/users')
344
+ .set('Authorization', `Bearer ${authToken}`)
345
+ .send({ email: 'invalid', name: 'Test' });
346
+
347
+ expect(response.status).toBe(422);
348
+ });
349
+ });
350
+ ```
351
+
352
+ ---
353
+
354
+ ## Definition of Done
355
+
356
+ A backend feature is complete when:
357
+
358
+ - [ ] Endpoint works as specified
359
+ - [ ] Input validation implemented
360
+ - [ ] Error handling covers edge cases
361
+ - [ ] Authentication/authorization enforced
362
+ - [ ] Unit and integration tests passing
363
+ - [ ] API documentation updated
364
+ - [ ] No security vulnerabilities
365
+ - [ ] Logging in place for debugging
366
+ - [ ] Code reviewed and approved
@@ -0,0 +1,296 @@
1
+ # Accessibility (a11y)
2
+
3
+ Guidelines for building accessible web applications that work for everyone.
4
+
5
+ ## Core Principles
6
+
7
+ ### 1. Perceivable
8
+ Information must be presentable in ways users can perceive.
9
+
10
+ ### 2. Operable
11
+ UI components must be operable by all users.
12
+
13
+ ### 3. Understandable
14
+ Information and UI operation must be understandable.
15
+
16
+ ### 4. Robust
17
+ Content must be robust enough for assistive technologies.
18
+
19
+ ## Semantic HTML
20
+
21
+ Use the right element for the job.
22
+
23
+ ```html
24
+ <!-- Good: Semantic -->
25
+ <nav>
26
+ <ul>
27
+ <li><a href="/home">Home</a></li>
28
+ <li><a href="/about">About</a></li>
29
+ </ul>
30
+ </nav>
31
+
32
+ <main>
33
+ <article>
34
+ <h1>Article Title</h1>
35
+ <p>Content...</p>
36
+ </article>
37
+ </main>
38
+
39
+ <button onClick={handleClick}>Submit</button>
40
+
41
+ <!-- Bad: Div soup -->
42
+ <div class="nav">
43
+ <div class="nav-item" onclick="...">Home</div>
44
+ </div>
45
+
46
+ <div class="content">
47
+ <div class="title">Article Title</div>
48
+ </div>
49
+
50
+ <div class="button" onclick="...">Submit</div>
51
+ ```
52
+
53
+ ## Keyboard Navigation
54
+
55
+ ### All Interactive Elements Must Be Keyboard Accessible
56
+
57
+ ```tsx
58
+ // Good: Native button is keyboard accessible
59
+ <button onClick={handleClick}>Click me</button>
60
+
61
+ // If you must use a div (avoid if possible):
62
+ <div
63
+ role="button"
64
+ tabIndex={0}
65
+ onClick={handleClick}
66
+ onKeyDown={(e) => {
67
+ if (e.key === 'Enter' || e.key === ' ') {
68
+ handleClick();
69
+ }
70
+ }}
71
+ >
72
+ Click me
73
+ </div>
74
+ ```
75
+
76
+ ### Focus Management
77
+
78
+ ```tsx
79
+ // Visible focus indicators
80
+ button:focus {
81
+ outline: 2px solid var(--color-focus);
82
+ outline-offset: 2px;
83
+ }
84
+
85
+ // Focus trap for modals
86
+ const Modal = ({ isOpen, onClose, children }) => {
87
+ const firstFocusableRef = useRef();
88
+
89
+ useEffect(() => {
90
+ if (isOpen) {
91
+ firstFocusableRef.current?.focus();
92
+ }
93
+ }, [isOpen]);
94
+
95
+ // ... trap focus within modal
96
+ };
97
+ ```
98
+
99
+ ### Skip Links
100
+
101
+ ```html
102
+ <a href="#main-content" class="sr-only focus:not-sr-only">
103
+ Skip to main content
104
+ </a>
105
+
106
+ <main id="main-content">
107
+ ...
108
+ </main>
109
+ ```
110
+
111
+ ## ARIA
112
+
113
+ ### Use ARIA Only When Necessary
114
+
115
+ Native HTML is always preferred. ARIA supplements, not replaces.
116
+
117
+ ```html
118
+ <!-- Good: Native HTML -->
119
+ <button>Submit</button>
120
+ <nav>...</nav>
121
+ <main>...</main>
122
+
123
+ <!-- ARIA when custom components are unavoidable -->
124
+ <div role="tablist">
125
+ <button role="tab" aria-selected="true" aria-controls="panel-1">Tab 1</button>
126
+ <button role="tab" aria-selected="false" aria-controls="panel-2">Tab 2</button>
127
+ </div>
128
+ <div role="tabpanel" id="panel-1">Content 1</div>
129
+ ```
130
+
131
+ ### Common ARIA Patterns
132
+
133
+ ```tsx
134
+ // Loading state
135
+ <button aria-busy={isLoading} disabled={isLoading}>
136
+ {isLoading ? 'Loading...' : 'Submit'}
137
+ </button>
138
+
139
+ // Expanded/collapsed
140
+ <button aria-expanded={isOpen} aria-controls="menu">
141
+ Menu
142
+ </button>
143
+ <ul id="menu" hidden={!isOpen}>...</ul>
144
+
145
+ // Live regions for dynamic content
146
+ <div aria-live="polite" aria-atomic="true">
147
+ {statusMessage}
148
+ </div>
149
+
150
+ // Form errors
151
+ <input
152
+ aria-invalid={hasError}
153
+ aria-describedby={hasError ? 'email-error' : undefined}
154
+ />
155
+ {hasError && <span id="email-error">Please enter a valid email</span>}
156
+ ```
157
+
158
+ ## Forms
159
+
160
+ ### Labels
161
+
162
+ Every form input needs a label.
163
+
164
+ ```tsx
165
+ // Good: Explicit label
166
+ <label htmlFor="email">Email</label>
167
+ <input id="email" type="email" />
168
+
169
+ // Good: Implicit label
170
+ <label>
171
+ Email
172
+ <input type="email" />
173
+ </label>
174
+
175
+ // Bad: No label
176
+ <input type="email" placeholder="Email" />
177
+ ```
178
+
179
+ ### Error Messages
180
+
181
+ ```tsx
182
+ <div>
183
+ <label htmlFor="password">Password</label>
184
+ <input
185
+ id="password"
186
+ type="password"
187
+ aria-invalid={!!error}
188
+ aria-describedby={error ? 'password-error' : 'password-hint'}
189
+ />
190
+ <span id="password-hint">Must be at least 8 characters</span>
191
+ {error && (
192
+ <span id="password-error" role="alert">
193
+ {error}
194
+ </span>
195
+ )}
196
+ </div>
197
+ ```
198
+
199
+ ## Images
200
+
201
+ ### Alt Text
202
+
203
+ ```html
204
+ <!-- Informative image: Describe the content -->
205
+ <img src="chart.png" alt="Sales increased 25% from Q1 to Q2" />
206
+
207
+ <!-- Decorative image: Empty alt -->
208
+ <img src="decorative-border.png" alt="" />
209
+
210
+ <!-- Complex image: Longer description -->
211
+ <figure>
212
+ <img src="diagram.png" alt="System architecture diagram" />
213
+ <figcaption>
214
+ The system consists of three layers: presentation, business logic, and data.
215
+ </figcaption>
216
+ </figure>
217
+ ```
218
+
219
+ ## Color and Contrast
220
+
221
+ ### Minimum Contrast Ratios
222
+
223
+ - Normal text: 4.5:1
224
+ - Large text (18px+ or 14px+ bold): 3:1
225
+ - UI components and graphics: 3:1
226
+
227
+ ### Don't Rely on Color Alone
228
+
229
+ ```tsx
230
+ // Bad: Color only
231
+ <span style={{ color: 'red' }}>Error</span>
232
+
233
+ // Good: Color + icon + text
234
+ <span className="error">
235
+ <ErrorIcon aria-hidden="true" />
236
+ Error: Please fix the following issues
237
+ </span>
238
+ ```
239
+
240
+ ## Testing
241
+
242
+ ### Automated Testing
243
+
244
+ ```tsx
245
+ import { axe, toHaveNoViolations } from 'jest-axe';
246
+
247
+ expect.extend(toHaveNoViolations);
248
+
249
+ test('component has no accessibility violations', async () => {
250
+ const { container } = render(<MyComponent />);
251
+ const results = await axe(container);
252
+ expect(results).toHaveNoViolations();
253
+ });
254
+ ```
255
+
256
+ ### Manual Testing Checklist
257
+
258
+ - [ ] Navigate entire page with keyboard only
259
+ - [ ] Test with screen reader (NVDA, VoiceOver, JAWS)
260
+ - [ ] Check color contrast ratios
261
+ - [ ] Verify focus indicators are visible
262
+ - [ ] Test at 200% zoom
263
+ - [ ] Check with reduced motion preference
264
+
265
+ ## Common Anti-Patterns
266
+
267
+ ### Removing Focus Outlines
268
+
269
+ ```css
270
+ /* Never do this */
271
+ *:focus { outline: none; }
272
+
273
+ /* Do this instead */
274
+ *:focus { outline: 2px solid var(--focus-color); }
275
+ *:focus:not(:focus-visible) { outline: none; }
276
+ ```
277
+
278
+ ### Click-Only Handlers on Non-Interactive Elements
279
+
280
+ ```tsx
281
+ // Bad
282
+ <div onClick={handleClick}>Click me</div>
283
+
284
+ // Good
285
+ <button onClick={handleClick}>Click me</button>
286
+ ```
287
+
288
+ ### Missing Alternative Text
289
+
290
+ ```tsx
291
+ // Bad
292
+ <img src="logo.png" />
293
+
294
+ // Good
295
+ <img src="logo.png" alt="Company Name" />
296
+ ```