swe-workflow-skills 0.1.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/LICENSE +21 -0
- package/README.md +144 -0
- package/VERSION +1 -0
- package/bin/cli.mjs +44 -0
- package/catalog.json +225 -0
- package/commands/role.md +34 -0
- package/hooks/session-start.mjs +118 -0
- package/install.mjs +318 -0
- package/package.json +47 -0
- package/roles.json +194 -0
- package/scripts/resolve.mjs +296 -0
- package/skills/accessibility-design/SKILL.md +128 -0
- package/skills/accessibility-design/evals/evals.json +51 -0
- package/skills/accessibility-design/references/accessibility-patterns.md +321 -0
- package/skills/api-design/SKILL.md +144 -0
- package/skills/api-design/evals/evals.json +48 -0
- package/skills/api-design/references/rest-conventions.md +147 -0
- package/skills/api-design/templates/api-spec.md +156 -0
- package/skills/architecture-design/SKILL.md +86 -0
- package/skills/architecture-design/evals/evals.json +44 -0
- package/skills/architecture-design/references/clean-architecture.md +147 -0
- package/skills/architecture-design/references/component-principles.md +129 -0
- package/skills/architecture-design/references/principles.md +81 -0
- package/skills/architecture-design/references/solid-principles.md +106 -0
- package/skills/architecture-design/templates/adr.md +63 -0
- package/skills/architecture-documentation/SKILL.md +126 -0
- package/skills/architecture-documentation/evals/evals.json +44 -0
- package/skills/architecture-documentation/references/abstraction-levels.md +91 -0
- package/skills/architecture-documentation/references/diagram-tooling.md +141 -0
- package/skills/architecture-documentation/templates/architecture-doc.md +171 -0
- package/skills/bug-investigating/SKILL.md +133 -0
- package/skills/bug-investigating/evals/evals.json +56 -0
- package/skills/bug-investigating/references/common-bugs.md +62 -0
- package/skills/bug-investigating/references/debugging-patterns.md +94 -0
- package/skills/cicd-pipeline/SKILL.md +87 -0
- package/skills/cicd-pipeline/evals/evals.json +34 -0
- package/skills/cicd-pipeline/references/pipeline-patterns.md +206 -0
- package/skills/cicd-pipeline/templates/github-actions.md +206 -0
- package/skills/code-reviewing/SKILL.md +92 -0
- package/skills/code-reviewing/evals/evals.json +62 -0
- package/skills/code-reviewing/references/error-handling.md +108 -0
- package/skills/code-reviewing/references/review-checklist.md +144 -0
- package/skills/configuration-strategy/SKILL.md +109 -0
- package/skills/configuration-strategy/evals/evals.json +41 -0
- package/skills/configuration-strategy/references/config-patterns.md +161 -0
- package/skills/containerization/SKILL.md +90 -0
- package/skills/containerization/evals/evals.json +36 -0
- package/skills/containerization/references/dockerfile-patterns.md +168 -0
- package/skills/containerization/templates/dockerfile.md +154 -0
- package/skills/data-modeling/SKILL.md +83 -0
- package/skills/data-modeling/evals/evals.json +43 -0
- package/skills/data-modeling/references/conventions.md +57 -0
- package/skills/data-modeling/templates/schema.md +120 -0
- package/skills/dependency-impact-analysis/SKILL.md +113 -0
- package/skills/dependency-impact-analysis/evals/evals.json +41 -0
- package/skills/dependency-impact-analysis/references/impact-patterns.md +150 -0
- package/skills/dependency-management/SKILL.md +161 -0
- package/skills/dependency-management/evals/evals.json +48 -0
- package/skills/dependency-management/references/evaluation-checklist.md +127 -0
- package/skills/deployment-checklist/SKILL.md +132 -0
- package/skills/deployment-checklist/evals/evals.json +58 -0
- package/skills/deployment-checklist/references/pre-deploy-gates.md +91 -0
- package/skills/deployment-repo/SKILL.md +190 -0
- package/skills/deployment-repo/evals/evals.json +44 -0
- package/skills/deployment-repo/references/deployment-repo-patterns.md +258 -0
- package/skills/deployment-repo/references/version-compatibility.md +227 -0
- package/skills/deployment-repo/templates/deployment-repo-structure.md +226 -0
- package/skills/effort-estimation/SKILL.md +95 -0
- package/skills/effort-estimation/evals/evals.json +32 -0
- package/skills/effort-estimation/references/estimation-methods.md +154 -0
- package/skills/feature-planning/SKILL.md +84 -0
- package/skills/feature-planning/evals/evals.json +44 -0
- package/skills/feature-planning/templates/plan.md +55 -0
- package/skills/feature-planning/templates/task.md +26 -0
- package/skills/frontend-architecture/SKILL.md +154 -0
- package/skills/frontend-architecture/evals/evals.json +34 -0
- package/skills/frontend-architecture/references/component-patterns.md +264 -0
- package/skills/frontend-architecture/templates/folder-structure.md +203 -0
- package/skills/git-workflow/SKILL.md +127 -0
- package/skills/git-workflow/evals/evals.json +44 -0
- package/skills/git-workflow/references/conventions.md +142 -0
- package/skills/git-workflow/templates/pull-request.md +57 -0
- package/skills/gitops-delivery/SKILL.md +319 -0
- package/skills/gitops-delivery/evals/evals.json +44 -0
- package/skills/gitops-delivery/references/gitops-patterns.md +478 -0
- package/skills/gitops-delivery/templates/gitops-config.md +196 -0
- package/skills/incident-response/SKILL.md +130 -0
- package/skills/incident-response/evals/evals.json +55 -0
- package/skills/incident-response/references/communication-templates.md +134 -0
- package/skills/incident-response/references/severity-levels.md +77 -0
- package/skills/incident-response/templates/incident-timeline.md +57 -0
- package/skills/infrastructure-as-code/SKILL.md +86 -0
- package/skills/infrastructure-as-code/evals/evals.json +33 -0
- package/skills/infrastructure-as-code/references/iac-patterns.md +179 -0
- package/skills/infrastructure-as-code/templates/terraform-module.md +158 -0
- package/skills/metrics-and-okrs/SKILL.md +113 -0
- package/skills/metrics-and-okrs/evals/evals.json +33 -0
- package/skills/metrics-and-okrs/references/metric-catalog.md +90 -0
- package/skills/metrics-and-okrs/templates/okr-document.md +61 -0
- package/skills/ml-experiment-tracking/SKILL.md +96 -0
- package/skills/ml-experiment-tracking/evals/evals.json +32 -0
- package/skills/ml-experiment-tracking/references/tracking-tools.md +127 -0
- package/skills/ml-model-deployment/SKILL.md +106 -0
- package/skills/ml-model-deployment/evals/evals.json +34 -0
- package/skills/ml-model-deployment/references/serving-patterns.md +162 -0
- package/skills/ml-pipeline-design/SKILL.md +162 -0
- package/skills/ml-pipeline-design/evals/evals.json +34 -0
- package/skills/ml-pipeline-design/references/pipeline-components.md +174 -0
- package/skills/observability-design/SKILL.md +162 -0
- package/skills/observability-design/evals/evals.json +52 -0
- package/skills/observability-design/references/logging-patterns.md +229 -0
- package/skills/observability-design/references/slo-framework.md +151 -0
- package/skills/observability-design/templates/slo-document.md +80 -0
- package/skills/performance-optimization/SKILL.md +83 -0
- package/skills/performance-optimization/evals/evals.json +47 -0
- package/skills/performance-optimization/references/bottleneck-patterns.md +256 -0
- package/skills/performance-optimization/references/concurrency.md +101 -0
- package/skills/prd-writing/SKILL.md +109 -0
- package/skills/prd-writing/evals/evals.json +33 -0
- package/skills/prd-writing/references/prd-examples.md +132 -0
- package/skills/prd-writing/templates/prd.md +71 -0
- package/skills/prd-writing/templates/rfc.md +79 -0
- package/skills/project-documentation/SKILL.md +104 -0
- package/skills/project-documentation/evals/evals.json +48 -0
- package/skills/project-documentation/references/contributing-guide.md +100 -0
- package/skills/project-documentation/templates/changelog.md +59 -0
- package/skills/project-documentation/templates/readme.md +121 -0
- package/skills/project-proposal/SKILL.md +90 -0
- package/skills/project-proposal/evals/evals.json +31 -0
- package/skills/project-proposal/references/proposal-examples.md +140 -0
- package/skills/project-proposal/templates/proposal.md +76 -0
- package/skills/project-review/SKILL.md +111 -0
- package/skills/project-review/evals/evals.json +42 -0
- package/skills/refactoring/SKILL.md +90 -0
- package/skills/refactoring/evals/evals.json +44 -0
- package/skills/refactoring/references/transformations.md +132 -0
- package/skills/retrospective/SKILL.md +157 -0
- package/skills/retrospective/evals/evals.json +34 -0
- package/skills/retrospective/references/facilitation-guide.md +130 -0
- package/skills/retrospective/templates/post-mortem.md +121 -0
- package/skills/rollback-strategy/SKILL.md +116 -0
- package/skills/rollback-strategy/evals/evals.json +55 -0
- package/skills/rollback-strategy/references/rollback-patterns.md +125 -0
- package/skills/rollback-strategy/templates/rollback-plan.md +69 -0
- package/skills/security-audit/SKILL.md +146 -0
- package/skills/security-audit/evals/evals.json +66 -0
- package/skills/security-audit/references/owasp-top-10.md +167 -0
- package/skills/security-audit/templates/security-report.md +79 -0
- package/skills/skill-router/SKILL.md +171 -0
- package/skills/skill-router/evals/evals.json +39 -0
- package/skills/strategic-review/SKILL.md +106 -0
- package/skills/strategic-review/evals/evals.json +42 -0
- package/skills/strategic-review/templates/full-review-prompt.md +84 -0
- package/skills/tdd-workflow/SKILL.md +147 -0
- package/skills/tdd-workflow/evals/evals.json +58 -0
- package/skills/tdd-workflow/references/test-quality.md +71 -0
- package/skills/technical-debt-review/SKILL.md +113 -0
- package/skills/technical-debt-review/evals/evals.json +41 -0
- package/skills/technical-debt-review/references/debt-taxonomy.md +124 -0
- package/skills/technical-debt-review/templates/debt-audit.md +85 -0
- package/skills/test-data-strategy/SKILL.md +129 -0
- package/skills/test-data-strategy/evals/evals.json +49 -0
- package/skills/test-data-strategy/references/data-generation-patterns.md +341 -0
- package/skills/test-suite-design/SKILL.md +137 -0
- package/skills/test-suite-design/evals/evals.json +69 -0
- package/skills/test-suite-design/references/test-infrastructure.md +175 -0
- package/skills/test-suite-design/references/testing-pyramid.md +140 -0
- package/skills/ui-ux-design/SKILL.md +117 -0
- package/skills/ui-ux-design/evals/evals.json +35 -0
- package/skills/ui-ux-design/references/interaction-patterns.md +145 -0
- package/skills/ui-ux-design/templates/screen-spec.md +97 -0
- package/skills/verification-before-completion/SKILL.md +85 -0
- package/skills/verification-before-completion/evals/evals.json +53 -0
- package/skills/writing-skills/SKILL.md +87 -0
- package/skills/writing-skills/evals/evals.json +41 -0
- package/skills/writing-skills/references/pressure-testing.md +69 -0
- package/uninstall.mjs +182 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
# Accessibility Patterns
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
- Common component patterns
|
|
5
|
+
- Form accessibility
|
|
6
|
+
- Modal and dialog patterns
|
|
7
|
+
- Navigation patterns
|
|
8
|
+
- Image and media accessibility
|
|
9
|
+
- React-specific patterns
|
|
10
|
+
|
|
11
|
+
## Common Component Patterns
|
|
12
|
+
|
|
13
|
+
### Button
|
|
14
|
+
```html
|
|
15
|
+
<!-- GOOD: Native button — keyboard support, role, focus all built in -->
|
|
16
|
+
<button type="button" onClick={handleClick}>
|
|
17
|
+
Save Changes
|
|
18
|
+
</button>
|
|
19
|
+
|
|
20
|
+
<!-- GOOD: Button with loading state -->
|
|
21
|
+
<button type="button" disabled={isLoading} aria-busy={isLoading}>
|
|
22
|
+
{isLoading ? 'Saving...' : 'Save Changes'}
|
|
23
|
+
</button>
|
|
24
|
+
|
|
25
|
+
<!-- GOOD: Icon button with accessible label -->
|
|
26
|
+
<button type="button" aria-label="Delete item">
|
|
27
|
+
<TrashIcon aria-hidden="true" />
|
|
28
|
+
</button>
|
|
29
|
+
|
|
30
|
+
<!-- BAD: Div pretending to be a button — no keyboard, no role, no focus -->
|
|
31
|
+
<div className="btn" onClick={handleClick}>Save</div>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Link vs Button
|
|
35
|
+
- Use `<a>` for navigation (goes somewhere)
|
|
36
|
+
- Use `<button>` for actions (does something)
|
|
37
|
+
- Never use `<a href="#">` as a button — use a real `<button>`
|
|
38
|
+
|
|
39
|
+
### Toggle / Switch
|
|
40
|
+
```html
|
|
41
|
+
<button
|
|
42
|
+
role="switch"
|
|
43
|
+
aria-checked={isEnabled}
|
|
44
|
+
onClick={() => setIsEnabled(!isEnabled)}
|
|
45
|
+
>
|
|
46
|
+
Dark mode
|
|
47
|
+
</button>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Tabs
|
|
51
|
+
```html
|
|
52
|
+
<div role="tablist" aria-label="Account settings">
|
|
53
|
+
<button role="tab" aria-selected={activeTab === 'general'}
|
|
54
|
+
aria-controls="panel-general" id="tab-general">
|
|
55
|
+
General
|
|
56
|
+
</button>
|
|
57
|
+
<button role="tab" aria-selected={activeTab === 'security'}
|
|
58
|
+
aria-controls="panel-security" id="tab-security">
|
|
59
|
+
Security
|
|
60
|
+
</button>
|
|
61
|
+
</div>
|
|
62
|
+
<div role="tabpanel" id="panel-general" aria-labelledby="tab-general"
|
|
63
|
+
hidden={activeTab !== 'general'}>
|
|
64
|
+
General settings content...
|
|
65
|
+
</div>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Keyboard: Arrow keys between tabs, Tab moves focus into the active panel.
|
|
69
|
+
|
|
70
|
+
### Accordion
|
|
71
|
+
```html
|
|
72
|
+
<h3>
|
|
73
|
+
<button aria-expanded={isOpen} aria-controls="section-1">
|
|
74
|
+
FAQ Question
|
|
75
|
+
</button>
|
|
76
|
+
</h3>
|
|
77
|
+
<div id="section-1" role="region" hidden={!isOpen}>
|
|
78
|
+
Answer content...
|
|
79
|
+
</div>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Form Accessibility
|
|
83
|
+
|
|
84
|
+
### Labels
|
|
85
|
+
Every input MUST have an associated label. No exceptions.
|
|
86
|
+
|
|
87
|
+
```html
|
|
88
|
+
<!-- GOOD: Explicit label with htmlFor -->
|
|
89
|
+
<label htmlFor="email">Email address</label>
|
|
90
|
+
<input id="email" type="email" />
|
|
91
|
+
|
|
92
|
+
<!-- GOOD: Wrapping label (implicit association) -->
|
|
93
|
+
<label>
|
|
94
|
+
Email address
|
|
95
|
+
<input type="email" />
|
|
96
|
+
</label>
|
|
97
|
+
|
|
98
|
+
<!-- GOOD: aria-label for visually hidden label -->
|
|
99
|
+
<input type="search" aria-label="Search projects" />
|
|
100
|
+
|
|
101
|
+
<!-- BAD: Placeholder as label — disappears on focus, low contrast -->
|
|
102
|
+
<input type="email" placeholder="Email address" />
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Error messages
|
|
106
|
+
```html
|
|
107
|
+
<label htmlFor="email">Email address</label>
|
|
108
|
+
<input
|
|
109
|
+
id="email"
|
|
110
|
+
type="email"
|
|
111
|
+
aria-invalid={hasError}
|
|
112
|
+
aria-describedby={hasError ? "email-error" : undefined}
|
|
113
|
+
/>
|
|
114
|
+
{hasError && (
|
|
115
|
+
<p id="email-error" role="alert">
|
|
116
|
+
Please enter a valid email address
|
|
117
|
+
</p>
|
|
118
|
+
)}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Key: `aria-invalid` tells screen readers the field has an error. `aria-describedby` links the error message to the field. `role="alert"` announces the error immediately.
|
|
122
|
+
|
|
123
|
+
### Required fields
|
|
124
|
+
```html
|
|
125
|
+
<label htmlFor="name">
|
|
126
|
+
Name <span aria-hidden="true">*</span>
|
|
127
|
+
</label>
|
|
128
|
+
<input id="name" required aria-required="true" />
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The `*` is visual-only (`aria-hidden`). `aria-required` is the programmatic indicator.
|
|
132
|
+
|
|
133
|
+
### Form submission feedback
|
|
134
|
+
```html
|
|
135
|
+
<!-- Status region for form-level messages -->
|
|
136
|
+
<div aria-live="polite" role="status">
|
|
137
|
+
{submitSuccess && "Your changes have been saved."}
|
|
138
|
+
{submitError && "Failed to save. Please try again."}
|
|
139
|
+
</div>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Modal and Dialog Patterns
|
|
143
|
+
|
|
144
|
+
```html
|
|
145
|
+
<div
|
|
146
|
+
role="dialog"
|
|
147
|
+
aria-modal="true"
|
|
148
|
+
aria-labelledby="modal-title"
|
|
149
|
+
aria-describedby="modal-description"
|
|
150
|
+
>
|
|
151
|
+
<h2 id="modal-title">Delete Project</h2>
|
|
152
|
+
<p id="modal-description">
|
|
153
|
+
This will permanently delete "My Project" and all its data.
|
|
154
|
+
</p>
|
|
155
|
+
<button onClick={onCancel}>Cancel</button>
|
|
156
|
+
<button onClick={onConfirm}>Delete</button>
|
|
157
|
+
</div>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Required behaviors:**
|
|
161
|
+
1. Focus moves to the first focusable element when modal opens
|
|
162
|
+
2. Tab cycles within the modal (focus trap — focus cannot leave)
|
|
163
|
+
3. Escape key closes the modal
|
|
164
|
+
4. Focus returns to the triggering element when modal closes
|
|
165
|
+
5. Background content has `aria-hidden="true"` and `inert` while modal is open
|
|
166
|
+
|
|
167
|
+
### React focus trap implementation
|
|
168
|
+
```typescript
|
|
169
|
+
function useFocusTrap(ref: RefObject<HTMLElement>) {
|
|
170
|
+
useEffect(() => {
|
|
171
|
+
const element = ref.current;
|
|
172
|
+
if (!element) return;
|
|
173
|
+
|
|
174
|
+
const focusableSelector = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
|
|
175
|
+
const focusable = element.querySelectorAll(focusableSelector);
|
|
176
|
+
const first = focusable[0] as HTMLElement;
|
|
177
|
+
const last = focusable[focusable.length - 1] as HTMLElement;
|
|
178
|
+
|
|
179
|
+
first?.focus();
|
|
180
|
+
|
|
181
|
+
const handleKeyDown = (e: KeyboardEvent) => {
|
|
182
|
+
if (e.key === 'Tab') {
|
|
183
|
+
if (e.shiftKey && document.activeElement === first) {
|
|
184
|
+
e.preventDefault();
|
|
185
|
+
last?.focus();
|
|
186
|
+
} else if (!e.shiftKey && document.activeElement === last) {
|
|
187
|
+
e.preventDefault();
|
|
188
|
+
first?.focus();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
element.addEventListener('keydown', handleKeyDown);
|
|
194
|
+
return () => element.removeEventListener('keydown', handleKeyDown);
|
|
195
|
+
}, [ref]);
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Navigation Patterns
|
|
200
|
+
|
|
201
|
+
### Skip link (required for keyboard users)
|
|
202
|
+
```html
|
|
203
|
+
<!-- First element in the body -->
|
|
204
|
+
<a href="#main-content" className="sr-only focus:not-sr-only">
|
|
205
|
+
Skip to main content
|
|
206
|
+
</a>
|
|
207
|
+
<!-- ... header, nav ... -->
|
|
208
|
+
<main id="main-content">
|
|
209
|
+
Page content
|
|
210
|
+
</main>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
The skip link is visually hidden until focused (keyboard user presses Tab).
|
|
214
|
+
|
|
215
|
+
### Landmarks
|
|
216
|
+
```html
|
|
217
|
+
<header> <!-- banner landmark -->
|
|
218
|
+
<nav aria-label="Main navigation"> <!-- navigation landmark -->
|
|
219
|
+
...
|
|
220
|
+
</nav>
|
|
221
|
+
</header>
|
|
222
|
+
<main> <!-- main landmark -->
|
|
223
|
+
<section aria-label="Dashboard"> <!-- region landmark -->
|
|
224
|
+
...
|
|
225
|
+
</section>
|
|
226
|
+
</main>
|
|
227
|
+
<aside> <!-- complementary landmark -->
|
|
228
|
+
...
|
|
229
|
+
</aside>
|
|
230
|
+
<footer> <!-- contentinfo landmark -->
|
|
231
|
+
...
|
|
232
|
+
</footer>
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Screen reader users navigate by landmarks. Proper landmark structure lets them jump directly to the section they need.
|
|
236
|
+
|
|
237
|
+
### Breadcrumbs
|
|
238
|
+
```html
|
|
239
|
+
<nav aria-label="Breadcrumb">
|
|
240
|
+
<ol>
|
|
241
|
+
<li><a href="/">Home</a></li>
|
|
242
|
+
<li><a href="/projects">Projects</a></li>
|
|
243
|
+
<li><a href="/projects/123" aria-current="page">My Project</a></li>
|
|
244
|
+
</ol>
|
|
245
|
+
</nav>
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Image and Media Accessibility
|
|
249
|
+
|
|
250
|
+
### Images
|
|
251
|
+
```html
|
|
252
|
+
<!-- Informative image: describe what it shows -->
|
|
253
|
+
<img src="chart.png" alt="Revenue grew 25% from Q1 to Q2 2025" />
|
|
254
|
+
|
|
255
|
+
<!-- Decorative image: empty alt (don't omit alt entirely) -->
|
|
256
|
+
<img src="decoration.png" alt="" />
|
|
257
|
+
|
|
258
|
+
<!-- Complex image: describe + link to long description -->
|
|
259
|
+
<figure>
|
|
260
|
+
<img src="architecture.png" alt="System architecture overview" aria-describedby="arch-desc" />
|
|
261
|
+
<figcaption id="arch-desc">
|
|
262
|
+
The system consists of three services: API gateway, processing service, and database.
|
|
263
|
+
Requests flow from the gateway through the processor to the database.
|
|
264
|
+
</figcaption>
|
|
265
|
+
</figure>
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Video
|
|
269
|
+
- Provide captions (not just auto-generated)
|
|
270
|
+
- Provide a transcript for audio content
|
|
271
|
+
- Don't autoplay with sound
|
|
272
|
+
- Provide pause/stop controls
|
|
273
|
+
|
|
274
|
+
## React-Specific Patterns
|
|
275
|
+
|
|
276
|
+
### Route change announcements
|
|
277
|
+
Single-page apps don't trigger screen reader page announcements on navigation. Add an announcer:
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
function RouteAnnouncer() {
|
|
281
|
+
const location = useLocation();
|
|
282
|
+
const [announcement, setAnnouncement] = useState('');
|
|
283
|
+
|
|
284
|
+
useEffect(() => {
|
|
285
|
+
// Read the page title or a descriptive heading
|
|
286
|
+
const title = document.title || 'Page loaded';
|
|
287
|
+
setAnnouncement(title);
|
|
288
|
+
}, [location]);
|
|
289
|
+
|
|
290
|
+
return (
|
|
291
|
+
<div aria-live="assertive" aria-atomic="true" className="sr-only">
|
|
292
|
+
{announcement}
|
|
293
|
+
</div>
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Visually hidden utility (sr-only)
|
|
299
|
+
```css
|
|
300
|
+
.sr-only {
|
|
301
|
+
position: absolute;
|
|
302
|
+
width: 1px;
|
|
303
|
+
height: 1px;
|
|
304
|
+
padding: 0;
|
|
305
|
+
margin: -1px;
|
|
306
|
+
overflow: hidden;
|
|
307
|
+
clip: rect(0, 0, 0, 0);
|
|
308
|
+
white-space: nowrap;
|
|
309
|
+
border-width: 0;
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
Use for: skip links, form labels that are visually implied by context, additional screen reader context.
|
|
313
|
+
|
|
314
|
+
### ESLint plugin
|
|
315
|
+
Add `eslint-plugin-jsx-a11y` to catch common issues at development time:
|
|
316
|
+
```json
|
|
317
|
+
{
|
|
318
|
+
"extends": ["plugin:jsx-a11y/recommended"]
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
This catches: missing alt text, invalid ARIA attributes, non-interactive elements with click handlers, missing form labels, and more.
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: api-design
|
|
3
|
+
description: "Design RESTful and GraphQL APIs — endpoint naming, request/response contracts, error handling, pagination, versioning, auth patterns, OpenAPI specs. Triggers: design the API, API contract, REST API, GraphQL schema, error response format, pagination, API versioning, OpenAPI, swagger, endpoints. Use architecture-design for REST-vs-GraphQL or monolith-vs-microservices decisions."
|
|
4
|
+
model: sonnet
|
|
5
|
+
allowed-tools: Read, Grep, Glob, Write, Edit
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# API Design
|
|
9
|
+
|
|
10
|
+
Design APIs that are consistent, predictable, and easy to consume. A well-designed API is intuitive to use without reading documentation — but has great documentation anyway.
|
|
11
|
+
|
|
12
|
+
## Scope Boundary
|
|
13
|
+
|
|
14
|
+
This skill designs the **contract** (endpoints, request/response shapes, error formats, pagination). For higher-level decisions (REST vs GraphQL, API gateway, authentication strategy), use the `architecture-design` skill first, then return here to design the specifics.
|
|
15
|
+
|
|
16
|
+
## Workflow
|
|
17
|
+
|
|
18
|
+
### Step 1: Identify Resources and Operations
|
|
19
|
+
|
|
20
|
+
Start from the domain model, not the UI:
|
|
21
|
+
|
|
22
|
+
- **What are the resources?** (nouns: users, orders, products, comments)
|
|
23
|
+
- **What operations exist?** (CRUD + domain-specific: archive, publish, approve)
|
|
24
|
+
- **What are the relationships?** (user has orders, order contains items)
|
|
25
|
+
- **Who consumes this API?** (web app, mobile app, third-party, internal service)
|
|
26
|
+
|
|
27
|
+
Map each resource to its operations before choosing URLs or methods.
|
|
28
|
+
|
|
29
|
+
### Step 2: Design Endpoints
|
|
30
|
+
|
|
31
|
+
Apply RESTful naming conventions — see [references/rest-conventions.md](references/rest-conventions.md):
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
GET /api/v1/users → List users
|
|
35
|
+
POST /api/v1/users → Create user
|
|
36
|
+
GET /api/v1/users/:id → Get user
|
|
37
|
+
PATCH /api/v1/users/:id → Update user (partial)
|
|
38
|
+
DELETE /api/v1/users/:id → Delete user
|
|
39
|
+
|
|
40
|
+
# Nested resources (when the child only makes sense in parent context)
|
|
41
|
+
GET /api/v1/users/:id/orders → List user's orders
|
|
42
|
+
POST /api/v1/users/:id/orders → Create order for user
|
|
43
|
+
|
|
44
|
+
# Actions that don't map to CRUD
|
|
45
|
+
POST /api/v1/orders/:id/cancel → Cancel an order
|
|
46
|
+
POST /api/v1/users/:id/verify → Verify a user's email
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Present the endpoint list to the user and refine before designing schemas.
|
|
50
|
+
|
|
51
|
+
### Step 3: Define Request/Response Schemas
|
|
52
|
+
|
|
53
|
+
For each endpoint, define:
|
|
54
|
+
|
|
55
|
+
**Request**: Query parameters (for filtering/pagination), path parameters, request body with field types and validation rules.
|
|
56
|
+
|
|
57
|
+
**Response**: Status code, response body shape, included relationships.
|
|
58
|
+
|
|
59
|
+
Use consistent patterns across all endpoints — see [references/rest-conventions.md](references/rest-conventions.md) for standard shapes.
|
|
60
|
+
|
|
61
|
+
Key decisions to make with the user:
|
|
62
|
+
- **ID format**: Integer, UUID, or ULID? (be consistent)
|
|
63
|
+
- **Date format**: ISO 8601 always (`2025-03-05T14:30:00Z`)
|
|
64
|
+
- **Null vs absent**: Are missing fields returned as `null` or omitted?
|
|
65
|
+
- **Envelope or not**: `{ data: [...], meta: {...} }` vs flat response?
|
|
66
|
+
|
|
67
|
+
### Step 4: Standardize Error Responses
|
|
68
|
+
|
|
69
|
+
Every API error should use the same shape. Recommend this format:
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"error": {
|
|
74
|
+
"code": "VALIDATION_ERROR",
|
|
75
|
+
"message": "Human-readable description for developers",
|
|
76
|
+
"details": [
|
|
77
|
+
{
|
|
78
|
+
"field": "email",
|
|
79
|
+
"message": "Must be a valid email address"
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Map HTTP status codes consistently:
|
|
87
|
+
- `400` — Client sent invalid data (validation errors)
|
|
88
|
+
- `401` — Authentication required or invalid
|
|
89
|
+
- `403` — Authenticated but not authorized for this action
|
|
90
|
+
- `404` — Resource not found
|
|
91
|
+
- `409` — Conflict (duplicate, state violation)
|
|
92
|
+
- `422` — Valid syntax but semantically invalid (business rule violation)
|
|
93
|
+
- `429` — Rate limited
|
|
94
|
+
- `500` — Server error (never expose internals)
|
|
95
|
+
|
|
96
|
+
### Step 5: Design Pagination, Filtering, Sorting
|
|
97
|
+
|
|
98
|
+
For any list endpoint that could return many results:
|
|
99
|
+
|
|
100
|
+
**Pagination** (recommend cursor-based for most cases):
|
|
101
|
+
```
|
|
102
|
+
GET /api/v1/orders?cursor=abc123&limit=20
|
|
103
|
+
|
|
104
|
+
Response:
|
|
105
|
+
{
|
|
106
|
+
"data": [...],
|
|
107
|
+
"pagination": {
|
|
108
|
+
"next_cursor": "def456",
|
|
109
|
+
"has_more": true
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Filtering**: Use query parameters with clear naming:
|
|
115
|
+
```
|
|
116
|
+
GET /api/v1/orders?status=pending&created_after=2025-01-01
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Sorting**: Use a `sort` parameter with `-` prefix for descending:
|
|
120
|
+
```
|
|
121
|
+
GET /api/v1/orders?sort=-created_at,total
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Step 6: Define Authentication and Authorization
|
|
125
|
+
|
|
126
|
+
For each endpoint, specify:
|
|
127
|
+
- **Authentication**: Required? What scheme? (Bearer token, API key, session)
|
|
128
|
+
- **Authorization**: What roles/permissions can access this? Document per-endpoint.
|
|
129
|
+
- **Public endpoints**: Explicitly mark which endpoints don't require auth.
|
|
130
|
+
|
|
131
|
+
### Step 7: Produce the Specification
|
|
132
|
+
|
|
133
|
+
Output the API design as one of:
|
|
134
|
+
- **Markdown document** — for internal APIs and quick designs
|
|
135
|
+
- **OpenAPI 3.x spec** — for formal APIs, enables codegen and tooling
|
|
136
|
+
|
|
137
|
+
Use the template at [templates/api-spec.md](templates/api-spec.md) for markdown output.
|
|
138
|
+
|
|
139
|
+
## Principles Applied
|
|
140
|
+
|
|
141
|
+
- **KISS**: Prefer flat resource URLs over deeply nested ones. `/orders?user_id=123` is simpler than `/users/123/orders/456/items/789`.
|
|
142
|
+
- **DRY**: Standardize error format, pagination, and envelope structure once. Don't reinvent per-endpoint.
|
|
143
|
+
- **YAGNI**: Don't add filtering, sorting, or pagination until a list endpoint actually needs them. Add later when the need is real.
|
|
144
|
+
- **Functional Independence**: Each endpoint should do one thing. Avoid "Swiss army knife" endpoints that change behavior based on query parameters.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "api-design",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "I need to design the API for a blog platform. We have users, posts, comments, and tags. Posts can have multiple tags. Comments are threaded (replies to other comments). Users can be authors or admins. The frontend is a Next.js app. Design the REST API.",
|
|
7
|
+
"expected_output": "Should identify all resources, design endpoints with proper RESTful naming, define request/response schemas, standardize errors, and include pagination for list endpoints.",
|
|
8
|
+
"assertions": [
|
|
9
|
+
"Identifies all resources (users, posts, comments, tags)",
|
|
10
|
+
"Uses plural nouns in URLs (/posts, /comments, /tags)",
|
|
11
|
+
"Handles the M:N relationship for posts and tags appropriately",
|
|
12
|
+
"Designs threaded comments without excessive URL nesting",
|
|
13
|
+
"Defines standard error response format",
|
|
14
|
+
"Includes pagination for list endpoints",
|
|
15
|
+
"Specifies auth requirements per endpoint",
|
|
16
|
+
"Distinguishes author vs admin permissions",
|
|
17
|
+
"Produces a complete API specification document"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": 2,
|
|
22
|
+
"prompt": "design api endpoints for user registration, login, password reset, and profile management",
|
|
23
|
+
"expected_output": "Should design auth-related endpoints following security best practices, not expose sensitive information in responses, and use appropriate HTTP methods.",
|
|
24
|
+
"assertions": [
|
|
25
|
+
"POST for registration, login, and password reset (not GET)",
|
|
26
|
+
"Does not return password hash or sensitive data in responses",
|
|
27
|
+
"Includes email verification flow",
|
|
28
|
+
"Password reset uses a token-based flow (not sending password via email)",
|
|
29
|
+
"Login response includes token and token expiry",
|
|
30
|
+
"Profile endpoints require authentication",
|
|
31
|
+
"Standardized error responses for auth failures (401 vs 403)"
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"id": 3,
|
|
36
|
+
"prompt": "We have an existing API with these endpoints:\nGET /getUsers\nGET /getUserById?id=123\nPOST /createUser\nPOST /updateUser\nGET /deleteUser?id=123\n\nThis doesn't feel right. Can you redesign it following proper REST conventions?",
|
|
37
|
+
"expected_output": "Should identify specific violations (verbs in URLs, GET for delete, query params for identity) and redesign using proper REST conventions.",
|
|
38
|
+
"assertions": [
|
|
39
|
+
"Identifies that URLs use verbs instead of nouns",
|
|
40
|
+
"Identifies that DELETE uses GET method",
|
|
41
|
+
"Identifies that identity is in query params instead of path",
|
|
42
|
+
"Redesigns to: GET /users, GET /users/:id, POST /users, PATCH /users/:id, DELETE /users/:id",
|
|
43
|
+
"Explains WHY each change matters (not just 'this is the convention')",
|
|
44
|
+
"Notes that this is a breaking change requiring versioning or migration plan"
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# REST API Conventions
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
- URL naming rules
|
|
5
|
+
- HTTP methods mapping
|
|
6
|
+
- Standard response shapes
|
|
7
|
+
- Pagination patterns
|
|
8
|
+
- Versioning strategies
|
|
9
|
+
- HATEOAS (when to use it)
|
|
10
|
+
|
|
11
|
+
## URL Naming Rules
|
|
12
|
+
|
|
13
|
+
- Use **plural nouns** for resources: `/users`, `/orders`, `/products`
|
|
14
|
+
- Use **kebab-case** for multi-word resources: `/order-items`, `/payment-methods`
|
|
15
|
+
- Use **path parameters** for identity: `/users/:id`
|
|
16
|
+
- Use **query parameters** for filtering: `/users?role=admin`
|
|
17
|
+
- Use **verbs only for actions** that aren't CRUD: `/orders/:id/cancel`, `/reports/generate`
|
|
18
|
+
- **Max 2 levels** of nesting: `/users/:id/orders` is fine, `/users/:id/orders/:oid/items/:iid/comments` is too deep — flatten it
|
|
19
|
+
|
|
20
|
+
## HTTP Methods Mapping
|
|
21
|
+
|
|
22
|
+
| Method | Meaning | Idempotent | Safe | Request Body |
|
|
23
|
+
|--------|---------|------------|------|-------------|
|
|
24
|
+
| GET | Read resource(s) | Yes | Yes | No |
|
|
25
|
+
| POST | Create resource or trigger action | No | No | Yes |
|
|
26
|
+
| PUT | Full replace of resource | Yes | No | Yes |
|
|
27
|
+
| PATCH | Partial update of resource | Yes | No | Yes (partial) |
|
|
28
|
+
| DELETE | Remove resource | Yes | No | No (usually) |
|
|
29
|
+
|
|
30
|
+
**PUT vs PATCH**: PUT replaces the entire resource (client sends all fields). PATCH updates only the fields provided. For most APIs, PATCH is more practical and less error-prone. Use PUT only when the client genuinely manages the full state.
|
|
31
|
+
|
|
32
|
+
## Standard Response Shapes
|
|
33
|
+
|
|
34
|
+
### Single resource
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"data": {
|
|
38
|
+
"id": "usr_abc123",
|
|
39
|
+
"type": "user",
|
|
40
|
+
"name": "Jane Smith",
|
|
41
|
+
"email": "jane@example.com",
|
|
42
|
+
"created_at": "2025-03-05T14:30:00Z"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Collection
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"data": [
|
|
51
|
+
{ "id": "usr_abc123", "name": "Jane Smith" },
|
|
52
|
+
{ "id": "usr_def456", "name": "Bob Jones" }
|
|
53
|
+
],
|
|
54
|
+
"pagination": {
|
|
55
|
+
"next_cursor": "eyJpZCI6MTAwfQ",
|
|
56
|
+
"has_more": true,
|
|
57
|
+
"total_count": 342
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Created resource (201)
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"data": {
|
|
66
|
+
"id": "usr_ghi789",
|
|
67
|
+
"name": "New User",
|
|
68
|
+
"created_at": "2025-03-05T15:00:00Z"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
With `Location` header: `Location: /api/v1/users/usr_ghi789`
|
|
74
|
+
|
|
75
|
+
### Deleted (204)
|
|
76
|
+
No body. Status 204 No Content.
|
|
77
|
+
|
|
78
|
+
### Error
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"error": {
|
|
82
|
+
"code": "NOT_FOUND",
|
|
83
|
+
"message": "User with id 'usr_xyz' not found"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Pagination Patterns
|
|
89
|
+
|
|
90
|
+
### Cursor-based (recommended for most cases)
|
|
91
|
+
|
|
92
|
+
Client sends: `?cursor=abc&limit=20`
|
|
93
|
+
Server returns: `{ pagination: { next_cursor: "def", has_more: true } }`
|
|
94
|
+
|
|
95
|
+
Advantages: Stable under inserts/deletes, efficient with indexes.
|
|
96
|
+
Disadvantage: Can't jump to page N directly.
|
|
97
|
+
|
|
98
|
+
Cursor is usually a base64-encoded identifier (e.g., `btoa(JSON.stringify({id: lastId}))`). Treat it as opaque — clients should never construct cursors.
|
|
99
|
+
|
|
100
|
+
### Offset-based (for simple cases)
|
|
101
|
+
|
|
102
|
+
Client sends: `?page=3&per_page=20`
|
|
103
|
+
Server returns: `{ pagination: { page: 3, per_page: 20, total_count: 342, total_pages: 18 } }`
|
|
104
|
+
|
|
105
|
+
Advantages: Can jump to any page, easy to implement.
|
|
106
|
+
Disadvantage: Unstable when data changes between pages, slow for large offsets.
|
|
107
|
+
|
|
108
|
+
Use offset only when the dataset is small/stable and users need random page access.
|
|
109
|
+
|
|
110
|
+
## Versioning Strategies
|
|
111
|
+
|
|
112
|
+
| Strategy | Example | When to Use |
|
|
113
|
+
|----------|---------|-------------|
|
|
114
|
+
| URL path | `/api/v1/users` | Default. Clear, cacheable, easy to route. |
|
|
115
|
+
| Header | `Accept: application/vnd.api+json;version=2` | When URL path isn't desirable (rare). |
|
|
116
|
+
| Query param | `/api/users?version=1` | Avoid. Caching and routing are harder. |
|
|
117
|
+
|
|
118
|
+
Recommended: URL path versioning (`/api/v1/`). Only create v2 when breaking changes are necessary. Additive changes (new fields, new endpoints) don't require a new version.
|
|
119
|
+
|
|
120
|
+
**Breaking changes** that require a new version:
|
|
121
|
+
- Removing or renaming a field
|
|
122
|
+
- Changing a field's type
|
|
123
|
+
- Changing the meaning of a status code
|
|
124
|
+
- Removing an endpoint
|
|
125
|
+
|
|
126
|
+
**Non-breaking changes** (safe within same version):
|
|
127
|
+
- Adding a new field to a response
|
|
128
|
+
- Adding a new endpoint
|
|
129
|
+
- Adding a new query parameter
|
|
130
|
+
- Adding a new optional field to a request body
|
|
131
|
+
|
|
132
|
+
## HATEOAS
|
|
133
|
+
|
|
134
|
+
Hypermedia (links in responses) is useful for discoverability in public APIs:
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"data": { "id": "ord_123", "status": "pending" },
|
|
139
|
+
"links": {
|
|
140
|
+
"self": "/api/v1/orders/ord_123",
|
|
141
|
+
"cancel": "/api/v1/orders/ord_123/cancel",
|
|
142
|
+
"items": "/api/v1/orders/ord_123/items"
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
For internal APIs: skip it — your clients already know the URL structure. For public APIs: consider it — it makes the API more self-documenting.
|