@geraldmaron/construct 1.0.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/.env.example +69 -0
- package/LICENSE +21 -0
- package/README.md +344 -0
- package/agents/prompts/cx-accessibility.md +29 -0
- package/agents/prompts/cx-ai-engineer.md +31 -0
- package/agents/prompts/cx-architect.md +40 -0
- package/agents/prompts/cx-business-strategist.md +25 -0
- package/agents/prompts/cx-data-analyst.md +30 -0
- package/agents/prompts/cx-data-engineer.md +32 -0
- package/agents/prompts/cx-debugger.md +27 -0
- package/agents/prompts/cx-designer.md +33 -0
- package/agents/prompts/cx-devil-advocate.md +36 -0
- package/agents/prompts/cx-docs-keeper.md +50 -0
- package/agents/prompts/cx-engineer.md +36 -0
- package/agents/prompts/cx-evaluator.md +26 -0
- package/agents/prompts/cx-explorer.md +38 -0
- package/agents/prompts/cx-legal-compliance.md +25 -0
- package/agents/prompts/cx-operations.md +28 -0
- package/agents/prompts/cx-orchestrator.md +30 -0
- package/agents/prompts/cx-platform-engineer.md +25 -0
- package/agents/prompts/cx-product-manager.md +30 -0
- package/agents/prompts/cx-qa.md +42 -0
- package/agents/prompts/cx-rd-lead.md +25 -0
- package/agents/prompts/cx-release-manager.md +31 -0
- package/agents/prompts/cx-researcher.md +31 -0
- package/agents/prompts/cx-reviewer.md +36 -0
- package/agents/prompts/cx-security.md +37 -0
- package/agents/prompts/cx-sre.md +26 -0
- package/agents/prompts/cx-test-automation.md +35 -0
- package/agents/prompts/cx-trace-reviewer.md +76 -0
- package/agents/prompts/cx-ux-researcher.md +30 -0
- package/agents/registry.json +879 -0
- package/agents/teams.json +94 -0
- package/bin/construct +613 -0
- package/commands/build/feature.md +21 -0
- package/commands/build/fix.md +20 -0
- package/commands/design/access.md +19 -0
- package/commands/design/flow.md +16 -0
- package/commands/design/ui.md +18 -0
- package/commands/measure/experiment.md +18 -0
- package/commands/measure/metrics.md +18 -0
- package/commands/measure/results.md +18 -0
- package/commands/plan/api.md +19 -0
- package/commands/plan/challenge.md +18 -0
- package/commands/plan/decide.md +20 -0
- package/commands/plan/feature.md +49 -0
- package/commands/plan/requirements.md +24 -0
- package/commands/remember/context.md +26 -0
- package/commands/remember/handoff.md +19 -0
- package/commands/remember/runbook.md +20 -0
- package/commands/review/code.md +21 -0
- package/commands/review/quality.md +19 -0
- package/commands/review/security.md +16 -0
- package/commands/ship/ready.md +19 -0
- package/commands/ship/release.md +19 -0
- package/commands/ship/status.md +18 -0
- package/commands/understand/docs.md +22 -0
- package/commands/understand/research.md +22 -0
- package/commands/understand/this.md +23 -0
- package/commands/understand/why.md +18 -0
- package/commands/work/clean.md +32 -0
- package/commands/work/drive.md +69 -0
- package/commands/work/optimize-prompts.md +46 -0
- package/commands/work/parallel-review.md +40 -0
- package/db/migrations/001_init.sql +38 -0
- package/langfuse/docker-compose.yml +82 -0
- package/lib/audit-skills.mjs +118 -0
- package/lib/auto-docs.mjs +293 -0
- package/lib/cli-commands.mjs +409 -0
- package/lib/codex-config.mjs +114 -0
- package/lib/comment-lint.mjs +191 -0
- package/lib/completions.mjs +170 -0
- package/lib/context-state.mjs +99 -0
- package/lib/cost.mjs +213 -0
- package/lib/distill.mjs +403 -0
- package/lib/efficiency.mjs +139 -0
- package/lib/env-config.mjs +53 -0
- package/lib/eval-harness.mjs +59 -0
- package/lib/features.mjs +209 -0
- package/lib/headhunt.mjs +597 -0
- package/lib/hooks/adaptive-lint.mjs +112 -0
- package/lib/hooks/agent-tracker.mjs +50 -0
- package/lib/hooks/bootstrap-guard.mjs +90 -0
- package/lib/hooks/comment-lint.mjs +26 -0
- package/lib/hooks/config-protection.mjs +52 -0
- package/lib/hooks/console-warn.mjs +43 -0
- package/lib/hooks/context-window-recovery.mjs +90 -0
- package/lib/hooks/continuation-enforcer.mjs +72 -0
- package/lib/hooks/dep-audit.mjs +155 -0
- package/lib/hooks/drive-guard.mjs +89 -0
- package/lib/hooks/edit-accumulator.mjs +36 -0
- package/lib/hooks/edit-error-recovery.mjs +46 -0
- package/lib/hooks/edit-guard.mjs +109 -0
- package/lib/hooks/env-check.mjs +80 -0
- package/lib/hooks/guard-bash.mjs +83 -0
- package/lib/hooks/mcp-audit.mjs +57 -0
- package/lib/hooks/mcp-health-check.mjs +51 -0
- package/lib/hooks/mcp-task-scope.mjs +47 -0
- package/lib/hooks/model-fallback.mjs +105 -0
- package/lib/hooks/pre-compact.mjs +212 -0
- package/lib/hooks/pre-push-gate.mjs +129 -0
- package/lib/hooks/read-tracker.mjs +129 -0
- package/lib/hooks/registry-sync.mjs +23 -0
- package/lib/hooks/scan-secrets.mjs +76 -0
- package/lib/hooks/session-start.mjs +95 -0
- package/lib/hooks/stop-notify.mjs +191 -0
- package/lib/hooks/stop-typecheck.mjs +83 -0
- package/lib/hooks/task-completed-guard.mjs +43 -0
- package/lib/hooks/teammate-idle-guard.mjs +54 -0
- package/lib/hooks/workflow-guard.mjs +62 -0
- package/lib/host-capabilities.mjs +123 -0
- package/lib/init-docs.mjs +382 -0
- package/lib/mcp/server.mjs +1123 -0
- package/lib/mcp-catalog.json +243 -0
- package/lib/mcp-manager.mjs +433 -0
- package/lib/mcp-platform-config.mjs +104 -0
- package/lib/model-router.mjs +810 -0
- package/lib/opencode-config.mjs +44 -0
- package/lib/opencode-runtime-plugin.mjs +909 -0
- package/lib/opencode-telemetry.mjs +433 -0
- package/lib/orchestration-policy.mjs +258 -0
- package/lib/prompt-composer.mjs +196 -0
- package/lib/prompt-metadata.mjs +68 -0
- package/lib/review.mjs +429 -0
- package/lib/role-preload.mjs +52 -0
- package/lib/schemas/decision.json +50 -0
- package/lib/schemas/implementation.json +51 -0
- package/lib/schemas/review-report.json +32 -0
- package/lib/schemas/test-report.json +43 -0
- package/lib/server/index.mjs +334 -0
- package/lib/server/static/app.js +841 -0
- package/lib/server/static/index.html +820 -0
- package/lib/service-manager.mjs +225 -0
- package/lib/setup.mjs +319 -0
- package/lib/status.mjs +707 -0
- package/lib/storage/backend.mjs +44 -0
- package/lib/storage/embeddings.mjs +70 -0
- package/lib/storage/hybrid-query.mjs +184 -0
- package/lib/storage/sql-store.mjs +55 -0
- package/lib/storage/state-source.mjs +101 -0
- package/lib/storage/sync.mjs +164 -0
- package/lib/storage/vector-store.mjs +59 -0
- package/lib/telemetry/backends/langfuse.mjs +58 -0
- package/lib/telemetry/backends/noop.mjs +16 -0
- package/lib/telemetry/langfuse-ingest.mjs +108 -0
- package/lib/telemetry/langfuse-model-sync.mjs +270 -0
- package/lib/telemetry/team-rollup.mjs +143 -0
- package/lib/toolkit-env.mjs +30 -0
- package/lib/validator.mjs +181 -0
- package/lib/workflow-state.mjs +794 -0
- package/package.json +53 -0
- package/personas/construct.md +94 -0
- package/platforms/claude/CLAUDE.md +30 -0
- package/platforms/claude/settings.template.json +472 -0
- package/platforms/opencode/config.template.json +65 -0
- package/platforms/opencode/plugins/construct-fallback.js +5 -0
- package/platforms/opencode/sync-config.mjs +69 -0
- package/rules/common/agents.md +55 -0
- package/rules/common/code-review.md +129 -0
- package/rules/common/coding-style.md +95 -0
- package/rules/common/comments.md +139 -0
- package/rules/common/cx-agent-routing.md +61 -0
- package/rules/common/cx-skill-routing.md +11 -0
- package/rules/common/development-workflow.md +49 -0
- package/rules/common/git-workflow.md +29 -0
- package/rules/common/hooks.md +35 -0
- package/rules/common/patterns.md +36 -0
- package/rules/common/performance.md +71 -0
- package/rules/common/security.md +34 -0
- package/rules/common/testing.md +62 -0
- package/rules/golang/coding-style.md +37 -0
- package/rules/golang/hooks.md +22 -0
- package/rules/golang/patterns.md +50 -0
- package/rules/golang/security.md +39 -0
- package/rules/golang/testing.md +36 -0
- package/rules/python/coding-style.md +47 -0
- package/rules/python/hooks.md +24 -0
- package/rules/python/patterns.md +44 -0
- package/rules/python/security.md +35 -0
- package/rules/python/testing.md +43 -0
- package/rules/swift/coding-style.md +52 -0
- package/rules/swift/hooks.md +25 -0
- package/rules/swift/patterns.md +71 -0
- package/rules/swift/security.md +38 -0
- package/rules/swift/testing.md +50 -0
- package/rules/typescript/coding-style.md +204 -0
- package/rules/typescript/hooks.md +27 -0
- package/rules/typescript/patterns.md +57 -0
- package/rules/typescript/security.md +33 -0
- package/rules/typescript/testing.md +23 -0
- package/rules/web/coding-style.md +101 -0
- package/rules/web/design-quality.md +68 -0
- package/rules/web/hooks.md +125 -0
- package/rules/web/patterns.md +84 -0
- package/rules/web/performance.md +69 -0
- package/rules/web/security.md +62 -0
- package/rules/web/testing.md +60 -0
- package/rules/zh/README.md +113 -0
- package/rules/zh/agents.md +55 -0
- package/rules/zh/code-review.md +129 -0
- package/rules/zh/coding-style.md +53 -0
- package/rules/zh/development-workflow.md +49 -0
- package/rules/zh/git-workflow.md +29 -0
- package/rules/zh/hooks.md +35 -0
- package/rules/zh/patterns.md +36 -0
- package/rules/zh/performance.md +60 -0
- package/rules/zh/security.md +34 -0
- package/rules/zh/testing.md +34 -0
- package/skills/ai/agent-dev.md +102 -0
- package/skills/ai/llm-security.md +105 -0
- package/skills/ai/ml-ops.md +169 -0
- package/skills/ai/orchestration-workflow.md +87 -0
- package/skills/ai/prompt-and-eval.md +114 -0
- package/skills/ai/prompt-optimizer.md +114 -0
- package/skills/ai/rag-system.md +104 -0
- package/skills/architecture/api-design.md +100 -0
- package/skills/architecture/caching.md +101 -0
- package/skills/architecture/cloud-native.md +97 -0
- package/skills/architecture/message-queue.md +100 -0
- package/skills/architecture/security-arch.md +105 -0
- package/skills/development/cpp.md +127 -0
- package/skills/development/go.md +129 -0
- package/skills/development/java.md +134 -0
- package/skills/development/kotlin.md +140 -0
- package/skills/development/mobile-crossplatform.md +144 -0
- package/skills/development/python.md +109 -0
- package/skills/development/rust.md +127 -0
- package/skills/development/shell.md +127 -0
- package/skills/development/swift.md +129 -0
- package/skills/development/typescript.md +129 -0
- package/skills/devops/ci-cd.md +108 -0
- package/skills/devops/containerization.md +106 -0
- package/skills/devops/cost-optimization.md +105 -0
- package/skills/devops/data-engineering.md +181 -0
- package/skills/devops/database.md +95 -0
- package/skills/devops/dependency-management.md +91 -0
- package/skills/devops/devsecops.md +96 -0
- package/skills/devops/git-workflow.md +100 -0
- package/skills/devops/incident-response.md +167 -0
- package/skills/devops/monorepo.md +87 -0
- package/skills/devops/observability.md +103 -0
- package/skills/devops/performance.md +104 -0
- package/skills/devops/testing.md +104 -0
- package/skills/docs/adr-workflow.md +32 -0
- package/skills/docs/backlog-proposal-workflow.md +19 -0
- package/skills/docs/customer-profile-workflow.md +22 -0
- package/skills/docs/evidence-ingest-workflow.md +23 -0
- package/skills/docs/init-docs.md +160 -0
- package/skills/docs/init-project.md +50 -0
- package/skills/docs/prd-workflow.md +57 -0
- package/skills/docs/prfaq-workflow.md +25 -0
- package/skills/docs/product-intelligence-review.md +22 -0
- package/skills/docs/product-intelligence-workflow.md +62 -0
- package/skills/docs/product-signal-workflow.md +27 -0
- package/skills/docs/research-workflow.md +28 -0
- package/skills/docs/runbook-workflow.md +24 -0
- package/skills/exploration/repo-map.md +297 -0
- package/skills/frameworks/django.md +159 -0
- package/skills/frameworks/nextjs.md +148 -0
- package/skills/frameworks/react.md +132 -0
- package/skills/frameworks/spring-boot.md +165 -0
- package/skills/frontend-design/accessibility.md +153 -0
- package/skills/frontend-design/component-patterns.md +111 -0
- package/skills/frontend-design/engineering.md +122 -0
- package/skills/frontend-design/state-management.md +118 -0
- package/skills/frontend-design/ui-aesthetics.md +102 -0
- package/skills/frontend-design/ux-principles.md +126 -0
- package/skills/quality-gates/review-work.md +90 -0
- package/skills/quality-gates/verify-change.md +94 -0
- package/skills/quality-gates/verify-module.md +96 -0
- package/skills/quality-gates/verify-quality.md +93 -0
- package/skills/quality-gates/verify-security.md +95 -0
- package/skills/roles/architect.ai-systems.md +37 -0
- package/skills/roles/architect.data.md +37 -0
- package/skills/roles/architect.enterprise.md +37 -0
- package/skills/roles/architect.integration.md +37 -0
- package/skills/roles/architect.md +68 -0
- package/skills/roles/architect.platform.md +37 -0
- package/skills/roles/data-analyst.experiment.md +37 -0
- package/skills/roles/data-analyst.md +68 -0
- package/skills/roles/data-analyst.product-intelligence.md +37 -0
- package/skills/roles/data-analyst.product.md +37 -0
- package/skills/roles/data-analyst.telemetry.md +37 -0
- package/skills/roles/data-engineer.pipeline.md +37 -0
- package/skills/roles/data-engineer.vector-retrieval.md +37 -0
- package/skills/roles/data-engineer.warehouse.md +37 -0
- package/skills/roles/debugger.md +68 -0
- package/skills/roles/designer.accessibility.md +43 -0
- package/skills/roles/designer.md +68 -0
- package/skills/roles/engineer.ai.md +49 -0
- package/skills/roles/engineer.data.md +49 -0
- package/skills/roles/engineer.md +85 -0
- package/skills/roles/engineer.platform.md +49 -0
- package/skills/roles/operator.docs.md +43 -0
- package/skills/roles/operator.md +68 -0
- package/skills/roles/operator.release.md +43 -0
- package/skills/roles/operator.sre.md +43 -0
- package/skills/roles/orchestrator.md +66 -0
- package/skills/roles/product-manager.ai-product.md +37 -0
- package/skills/roles/product-manager.business-strategy.md +43 -0
- package/skills/roles/product-manager.enterprise.md +37 -0
- package/skills/roles/product-manager.growth.md +37 -0
- package/skills/roles/product-manager.md +67 -0
- package/skills/roles/product-manager.platform.md +37 -0
- package/skills/roles/product-manager.product.md +37 -0
- package/skills/roles/qa.ai-eval.md +37 -0
- package/skills/roles/qa.api-contract.md +37 -0
- package/skills/roles/qa.data-pipeline.md +37 -0
- package/skills/roles/qa.md +68 -0
- package/skills/roles/qa.test-automation.md +49 -0
- package/skills/roles/qa.web-ui.md +37 -0
- package/skills/roles/researcher.explorer.md +43 -0
- package/skills/roles/researcher.md +68 -0
- package/skills/roles/researcher.ux.md +43 -0
- package/skills/roles/reviewer.devil-advocate.md +43 -0
- package/skills/roles/reviewer.evaluator.md +43 -0
- package/skills/roles/reviewer.md +68 -0
- package/skills/roles/reviewer.trace.md +43 -0
- package/skills/roles/security.ai.md +37 -0
- package/skills/roles/security.appsec.md +37 -0
- package/skills/roles/security.cloud.md +37 -0
- package/skills/roles/security.legal-compliance.md +49 -0
- package/skills/roles/security.md +68 -0
- package/skills/roles/security.privacy.md +37 -0
- package/skills/roles/security.supply-chain.md +37 -0
- package/skills/routing.md +139 -0
- package/skills/security/blue-team.md +83 -0
- package/skills/security/code-audit.md +94 -0
- package/skills/security/pentest.md +84 -0
- package/skills/security/red-team.md +81 -0
- package/skills/security/threat-intel.md +89 -0
- package/skills/security/vuln-research.md +87 -0
- package/skills/utility/clean-code.md +165 -0
- package/sync-agents.mjs +899 -0
- package/templates/docs/adr.md +27 -0
- package/templates/docs/backlog-proposal.md +26 -0
- package/templates/docs/customer-profile.md +34 -0
- package/templates/docs/evidence-brief.md +37 -0
- package/templates/docs/incident-report.md +46 -0
- package/templates/docs/memo.md +27 -0
- package/templates/docs/meta-prd.md +56 -0
- package/templates/docs/one-pager.md +24 -0
- package/templates/docs/prd-business.md +61 -0
- package/templates/docs/prd-platform.md +62 -0
- package/templates/docs/prd.md +47 -0
- package/templates/docs/prfaq.md +31 -0
- package/templates/docs/product-intelligence-report.md +31 -0
- package/templates/docs/research-brief.md +29 -0
- package/templates/docs/rfc-platform.md +60 -0
- package/templates/docs/rfc.md +46 -0
- package/templates/docs/runbook.md +33 -0
- package/templates/docs/signal-brief.md +25 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
skills/frameworks/react.md — React — By default, components are **Server Components** — they run on the server, have
|
|
3
|
+
|
|
4
|
+
## Component Design ### Server vs Client Components (React 19 / Next.js App Router)
|
|
5
|
+
-->
|
|
6
|
+
# React
|
|
7
|
+
|
|
8
|
+
## Component Design
|
|
9
|
+
|
|
10
|
+
### Server vs Client Components (React 19 / Next.js App Router)
|
|
11
|
+
|
|
12
|
+
By default, components are **Server Components** — they run on the server, have no state, and can fetch data directly. Add `'use client'` only when you need interactivity, browser APIs, or hooks.
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
// Server Component — no directive needed
|
|
16
|
+
async function ItemList() {
|
|
17
|
+
const items = await db.items.findMany(); // direct DB access fine here
|
|
18
|
+
return <ul>{items.map(i => <Item key={i.id} {...i} />)}</ul>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Client Component — needs browser or state
|
|
22
|
+
'use client';
|
|
23
|
+
export function SearchBar({ onSearch }: { onSearch: (q: string) => void }) {
|
|
24
|
+
const [query, setQuery] = useState('');
|
|
25
|
+
...
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Push the `'use client'` boundary as far down the tree as possible.
|
|
30
|
+
|
|
31
|
+
### Composition over configuration
|
|
32
|
+
|
|
33
|
+
Prefer children and render props over proliferating boolean props:
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
// Avoid: <Modal showHeader closeButton title="..." />
|
|
37
|
+
// Prefer:
|
|
38
|
+
<Modal>
|
|
39
|
+
<Modal.Header onClose={close}>Title</Modal.Header>
|
|
40
|
+
<Modal.Body>...</Modal.Body>
|
|
41
|
+
</Modal>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## State Management
|
|
45
|
+
|
|
46
|
+
See decision matrix:
|
|
47
|
+
|
|
48
|
+
| Concern | Tool |
|
|
49
|
+
|---|---|
|
|
50
|
+
| Server state (fetching, caching) | TanStack Query / SWR |
|
|
51
|
+
| Global UI state | Zustand / Jotai |
|
|
52
|
+
| Form state | React Hook Form + Zod |
|
|
53
|
+
| URL state | `useSearchParams` / router |
|
|
54
|
+
| Component-local state | `useState` / `useReducer` |
|
|
55
|
+
|
|
56
|
+
Do not put server data in a client store — TanStack Query is the cache. Derive don't duplicate.
|
|
57
|
+
|
|
58
|
+
## Performance
|
|
59
|
+
|
|
60
|
+
### Memoization discipline
|
|
61
|
+
|
|
62
|
+
`useMemo` and `useCallback` add overhead if misapplied. Measure first:
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
// Justified: expensive computation, stable deps
|
|
66
|
+
const sorted = useMemo(() => expensiveSort(items), [items]);
|
|
67
|
+
|
|
68
|
+
// Unjustified: not expensive, adds indirection for nothing
|
|
69
|
+
const label = useMemo(() => `Hello ${name}`, [name]);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Concurrent features
|
|
73
|
+
|
|
74
|
+
- `useTransition` for non-urgent state updates (e.g., search filter)
|
|
75
|
+
- `useDeferredValue` to deprioritize expensive re-renders while keeping input responsive
|
|
76
|
+
- `<Suspense>` boundaries for async data; pair with streaming in App Router
|
|
77
|
+
|
|
78
|
+
### Code splitting
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
const HeavyChart = lazy(() => import('./HeavyChart'));
|
|
82
|
+
<Suspense fallback={<Spinner />}><HeavyChart /></Suspense>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Patterns
|
|
86
|
+
|
|
87
|
+
### Custom hooks extract logic, not JSX
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
// Good: encapsulates fetch + error + loading
|
|
91
|
+
export function useItems() {
|
|
92
|
+
return useQuery({ queryKey: ['items'], queryFn: fetchItems });
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Controlled vs uncontrolled
|
|
97
|
+
|
|
98
|
+
- Controlled: React owns value via `state` — use for forms with validation, derived fields
|
|
99
|
+
- Uncontrolled: DOM owns value via `ref` — use for file inputs and simple browser-owned fields
|
|
100
|
+
|
|
101
|
+
## Testing
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
import { render, screen } from '@testing-library/react';
|
|
105
|
+
import userEvent from '@testing-library/user-event';
|
|
106
|
+
|
|
107
|
+
test('submits search query', async () => {
|
|
108
|
+
const onSearch = vi.fn();
|
|
109
|
+
render(<SearchBar onSearch={onSearch} />);
|
|
110
|
+
await userEvent.type(screen.getByRole('searchbox'), 'react');
|
|
111
|
+
await userEvent.keyboard('{Enter}');
|
|
112
|
+
expect(onSearch).toHaveBeenCalledWith('react');
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
- Use `@testing-library/react` — test behavior, not implementation
|
|
117
|
+
- `userEvent` over `fireEvent` — simulates real user interactions
|
|
118
|
+
- Mock at the network boundary (`msw`) not the component boundary
|
|
119
|
+
|
|
120
|
+
## Tooling
|
|
121
|
+
|
|
122
|
+
- **Vite** for non-Next apps; fast HMR, native ESM
|
|
123
|
+
- **Biome** for lint + format in a single fast tool (replaces ESLint + Prettier)
|
|
124
|
+
- **TypeScript strict mode** — enables `noUncheckedIndexedAccess`, `strictNullChecks`, etc.
|
|
125
|
+
- React DevTools Profiler for recomposition analysis
|
|
126
|
+
|
|
127
|
+
## Common Pitfalls
|
|
128
|
+
|
|
129
|
+
- Stale closures in `useEffect` — include all reactive values in the dependency array or use `useEffectEvent` (React 19)
|
|
130
|
+
- `useEffect` for data fetching — use TanStack Query instead
|
|
131
|
+
- Direct DOM mutation inside render — causes tearing with concurrent mode
|
|
132
|
+
- Key prop as array index — breaks reconciliation on reorder/insert
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
skills/frameworks/spring-boot.md — Spring Boot — ```
|
|
3
|
+
|
|
4
|
+
## Project Structure ```
|
|
5
|
+
-->
|
|
6
|
+
# Spring Boot
|
|
7
|
+
|
|
8
|
+
## Project Structure
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
src/
|
|
12
|
+
├── main/
|
|
13
|
+
│ ├── kotlin/com/example/app/
|
|
14
|
+
│ │ ├── Application.kt ← @SpringBootApplication entry
|
|
15
|
+
│ │ ├── config/ ← @Configuration classes
|
|
16
|
+
│ │ ├── domain/ ← Entities, value objects
|
|
17
|
+
│ │ ├── repository/ ← Spring Data repositories
|
|
18
|
+
│ │ ├── service/ ← Business logic (@Service)
|
|
19
|
+
│ │ ├── web/ ← Controllers (@RestController)
|
|
20
|
+
│ │ │ ├── dto/ ← Request/response DTOs
|
|
21
|
+
│ │ │ └── advice/ ← @ControllerAdvice
|
|
22
|
+
│ │ └── security/ ← Security config
|
|
23
|
+
│ └── resources/
|
|
24
|
+
│ ├── application.yml
|
|
25
|
+
│ └── db/migration/ ← Flyway migrations
|
|
26
|
+
└── test/
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Layered Architecture
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
@RestController → @Service → @Repository → DB
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- **Controller**: validate input, delegate to service, map to DTO
|
|
36
|
+
- **Service**: business logic; transaction boundary; no JPA entities exposed outside layer
|
|
37
|
+
- **Repository**: data access only; query methods or `@Query`
|
|
38
|
+
- **Domain**: pure entities with business behavior; no Spring dependencies
|
|
39
|
+
|
|
40
|
+
Never inject repositories directly into controllers.
|
|
41
|
+
|
|
42
|
+
## REST Controllers
|
|
43
|
+
|
|
44
|
+
```kotlin
|
|
45
|
+
@RestController
|
|
46
|
+
@RequestMapping("/api/items")
|
|
47
|
+
class ItemController(private val itemService: ItemService) {
|
|
48
|
+
|
|
49
|
+
@GetMapping("/{id}")
|
|
50
|
+
fun getItem(@PathVariable id: UUID): ResponseEntity<ItemDto> =
|
|
51
|
+
itemService.findById(id)
|
|
52
|
+
?.let { ResponseEntity.ok(it.toDto()) }
|
|
53
|
+
?: ResponseEntity.notFound().build()
|
|
54
|
+
|
|
55
|
+
@PostMapping
|
|
56
|
+
@ResponseStatus(HttpStatus.CREATED)
|
|
57
|
+
fun createItem(@Valid @RequestBody req: CreateItemRequest): ItemDto =
|
|
58
|
+
itemService.create(req).toDto()
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Use `@Valid` + Bean Validation (`@NotBlank`, `@Size`, etc.) for input validation. Handle `MethodArgumentNotValidException` in `@ControllerAdvice`.
|
|
63
|
+
|
|
64
|
+
## JPA / Spring Data
|
|
65
|
+
|
|
66
|
+
```kotlin
|
|
67
|
+
@Entity
|
|
68
|
+
@Table(name = "items")
|
|
69
|
+
class Item(
|
|
70
|
+
@Id val id: UUID = UUID.randomUUID(),
|
|
71
|
+
@Column(nullable = false) var title: String,
|
|
72
|
+
@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "owner_id") val owner: User,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
interface ItemRepository : JpaRepository<Item, UUID> {
|
|
76
|
+
fun findByOwnerAndStatus(owner: User, status: Status): List<Item>
|
|
77
|
+
|
|
78
|
+
@Query("SELECT i FROM Item i JOIN FETCH i.owner WHERE i.id = :id")
|
|
79
|
+
fun findByIdWithOwner(id: UUID): Item?
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
- Default `FetchType.LAZY` for associations — never `EAGER`
|
|
84
|
+
- Use `JOIN FETCH` in queries when you need the association
|
|
85
|
+
- Enable `spring.jpa.open-in-view=false` — prevents lazy-loading in the web layer
|
|
86
|
+
- Use Flyway or Liquibase for schema migrations; never `ddl-auto=update` in production
|
|
87
|
+
|
|
88
|
+
## Transactions
|
|
89
|
+
|
|
90
|
+
```kotlin
|
|
91
|
+
@Service
|
|
92
|
+
@Transactional(readOnly = true) // default for the class
|
|
93
|
+
class ItemService(private val repo: ItemRepository) {
|
|
94
|
+
|
|
95
|
+
@Transactional // write override
|
|
96
|
+
fun create(req: CreateItemRequest): Item {
|
|
97
|
+
val item = Item(title = req.title, owner = currentUser())
|
|
98
|
+
return repo.save(item)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
- `@Transactional` on service layer, not repository or controller
|
|
104
|
+
- `readOnly = true` as class-level default; override on writes — signals no dirty-check needed
|
|
105
|
+
- Do not call `@Transactional` methods via `this` — Spring proxy won't intercept it
|
|
106
|
+
|
|
107
|
+
## Security (Spring Security 6)
|
|
108
|
+
|
|
109
|
+
```kotlin
|
|
110
|
+
@Configuration
|
|
111
|
+
@EnableWebSecurity
|
|
112
|
+
class SecurityConfig {
|
|
113
|
+
@Bean
|
|
114
|
+
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain = http
|
|
115
|
+
.csrf { it.disable() } // stateless JWT API
|
|
116
|
+
.sessionManagement { it.sessionCreationPolicy(STATELESS) }
|
|
117
|
+
.authorizeHttpRequests {
|
|
118
|
+
it.requestMatchers("/api/auth/**").permitAll()
|
|
119
|
+
.anyRequest().authenticated()
|
|
120
|
+
}
|
|
121
|
+
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter::class.java)
|
|
122
|
+
.build()
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
- JWT for stateless APIs; sessions for web apps with CSRF
|
|
127
|
+
- `@PreAuthorize("hasRole('ADMIN')")` for method-level authorization
|
|
128
|
+
- Never log authentication credentials or tokens
|
|
129
|
+
|
|
130
|
+
## Testing
|
|
131
|
+
|
|
132
|
+
```kotlin
|
|
133
|
+
@SpringBootTest(webEnvironment = RANDOM_PORT)
|
|
134
|
+
@AutoConfigureTestDatabase(replace = NONE) // use Testcontainers
|
|
135
|
+
class ItemControllerIT(@Autowired val restTemplate: TestRestTemplate) {
|
|
136
|
+
|
|
137
|
+
@Test
|
|
138
|
+
fun `POST items creates and returns 201`() {
|
|
139
|
+
val resp = restTemplate.postForEntity("/api/items",
|
|
140
|
+
CreateItemRequest(title = "Test"), ItemDto::class.java)
|
|
141
|
+
assertEquals(HttpStatus.CREATED, resp.statusCode)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
- `@WebMvcTest` for controller-only tests (fast, no DB)
|
|
147
|
+
- `@DataJpaTest` for repository tests against a real embedded or Testcontainers DB
|
|
148
|
+
- `@SpringBootTest` for integration tests — use Testcontainers for realistic DB
|
|
149
|
+
- `MockMvc` + `@AutoConfigureMockMvc` for HTTP-layer testing without a real port
|
|
150
|
+
|
|
151
|
+
## Performance
|
|
152
|
+
|
|
153
|
+
- Connection pool: `HikariCP` (default) — tune `maximumPoolSize` based on load testing
|
|
154
|
+
- N+1 queries: use `JOIN FETCH` or `@EntityGraph`; verify with `spring.jpa.show-sql=true` in dev
|
|
155
|
+
- Caching: `@Cacheable` + Spring Cache with Redis (`spring-boot-starter-data-redis`)
|
|
156
|
+
- Async: `@EnableAsync` + `@Async` on service methods for fire-and-forget; use `CompletableFuture<T>` return type
|
|
157
|
+
- Virtual threads (Spring Boot 3.2+): `spring.threads.virtual.enabled=true` for high-concurrency blocking I/O
|
|
158
|
+
|
|
159
|
+
## Common Pitfalls
|
|
160
|
+
|
|
161
|
+
- `LazyInitializationException` after transaction closes — resolve with `JOIN FETCH` or DTO projection
|
|
162
|
+
- `@Transactional` on private methods — Spring AOP proxy can't intercept; move to public
|
|
163
|
+
- Bean cycle injection — restructure or use `@Lazy`
|
|
164
|
+
- Returning JPA entities directly from controllers — exposes internal model; always map to DTOs
|
|
165
|
+
- `findAll()` without pagination on large tables — always use `Pageable`
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
skills/frontend-design/accessibility.md — Accessibility (WCAG 2.2 / Inclusive Design) — Target **WCAG 2.1 AA** as the minimum for any public-facing product. WCAG 2.2 AA
|
|
3
|
+
|
|
4
|
+
## Compliance Baseline Target **WCAG 2.1 AA** as the minimum for any public-facing product. WCAG 2.2 AA is the current standard (published October 2023) and req
|
|
5
|
+
-->
|
|
6
|
+
# Accessibility (WCAG 2.2 / Inclusive Design)
|
|
7
|
+
|
|
8
|
+
## Compliance Baseline
|
|
9
|
+
|
|
10
|
+
Target **WCAG 2.1 AA** as the minimum for any public-facing product. WCAG 2.2 AA is the current standard (published October 2023) and required by many regulatory frameworks (EU Web Accessibility Directive, ADA, Section 508).
|
|
11
|
+
|
|
12
|
+
## Semantic HTML First
|
|
13
|
+
|
|
14
|
+
Use the right element before reaching for ARIA:
|
|
15
|
+
|
|
16
|
+
```html
|
|
17
|
+
<!-- Avoid: div soup -->
|
|
18
|
+
<div class="btn" onclick="submit()">Submit</div>
|
|
19
|
+
|
|
20
|
+
<!-- Correct: semantic button -->
|
|
21
|
+
<button type="submit">Submit</button>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
ARIA augments semantics it can't add natively; it cannot fix broken semantics.
|
|
25
|
+
|
|
26
|
+
## ARIA Rules
|
|
27
|
+
|
|
28
|
+
1. If a native HTML element provides the required semantics, use it — do not add ARIA to a `<div>` when `<button>` exists.
|
|
29
|
+
2. Do not change native semantics: `<h2 role="button">` is invalid.
|
|
30
|
+
3. All interactive ARIA widgets must be keyboard-operable.
|
|
31
|
+
4. Do not hide focusable elements with `aria-hidden="true"`.
|
|
32
|
+
5. Every interactive element must have an accessible name.
|
|
33
|
+
|
|
34
|
+
Common patterns:
|
|
35
|
+
|
|
36
|
+
```html
|
|
37
|
+
<!-- Label associated via for/id -->
|
|
38
|
+
<label for="email">Email</label>
|
|
39
|
+
<input id="email" type="email" />
|
|
40
|
+
|
|
41
|
+
<!-- Icon button with visually hidden label -->
|
|
42
|
+
<button aria-label="Close dialog">
|
|
43
|
+
<svg aria-hidden="true">...</svg>
|
|
44
|
+
</button>
|
|
45
|
+
|
|
46
|
+
<!-- Live region for async updates -->
|
|
47
|
+
<div aria-live="polite" aria-atomic="true" id="status"></div>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Keyboard Navigation
|
|
51
|
+
|
|
52
|
+
Every interactive element must be reachable and operable by keyboard:
|
|
53
|
+
|
|
54
|
+
| Key | Expected behavior |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `Tab` / `Shift+Tab` | Move focus forward / backward |
|
|
57
|
+
| `Enter` | Activate links and buttons |
|
|
58
|
+
| `Space` | Activate buttons, toggle checkboxes |
|
|
59
|
+
| `Arrow keys` | Navigate within composite widgets (menus, tabs, sliders) |
|
|
60
|
+
| `Escape` | Close modals, dismiss menus |
|
|
61
|
+
|
|
62
|
+
Focus trap in modals:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
// Lock focus inside the modal when open
|
|
66
|
+
function trapFocus(modal: HTMLElement) {
|
|
67
|
+
const focusable = modal.querySelectorAll<HTMLElement>(
|
|
68
|
+
'a[href], button:not([disabled]), input, select, textarea, [tabindex]:not([tabindex="-1"])'
|
|
69
|
+
);
|
|
70
|
+
const first = focusable[0];
|
|
71
|
+
const last = focusable[focusable.length - 1];
|
|
72
|
+
modal.addEventListener('keydown', (e) => {
|
|
73
|
+
if (e.key === 'Tab') {
|
|
74
|
+
if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); }
|
|
75
|
+
else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); }
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Color & Contrast
|
|
82
|
+
|
|
83
|
+
| Text size | Minimum contrast (AA) | Enhanced (AAA) |
|
|
84
|
+
|---|---|---|
|
|
85
|
+
| Normal text (< 18pt / 14pt bold) | 4.5:1 | 7:1 |
|
|
86
|
+
| Large text (≥ 18pt / 14pt bold) | 3:1 | 4.5:1 |
|
|
87
|
+
| UI components / graphical objects | 3:1 | — |
|
|
88
|
+
|
|
89
|
+
Tools: Figma Contrast plugin, axe DevTools, APCA calculator for sophisticated use cases.
|
|
90
|
+
|
|
91
|
+
Do not convey information by color alone — add shape, pattern, or text.
|
|
92
|
+
|
|
93
|
+
## Motion
|
|
94
|
+
|
|
95
|
+
Respect `prefers-reduced-motion`:
|
|
96
|
+
|
|
97
|
+
```css
|
|
98
|
+
@media (prefers-reduced-motion: reduce) {
|
|
99
|
+
*, *::before, *::after {
|
|
100
|
+
animation-duration: 0.01ms !important;
|
|
101
|
+
transition-duration: 0.01ms !important;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
In JS animations (GSAP, Framer Motion):
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
110
|
+
if (!prefersReduced) gsap.to(el, { y: -20, duration: 0.3 });
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Images & Media
|
|
114
|
+
|
|
115
|
+
- Decorative images: `alt=""`
|
|
116
|
+
- Informative images: concise alt text describing the content, not "image of"
|
|
117
|
+
- Complex images (charts, diagrams): short alt + long description via `aria-describedby` or adjacent text
|
|
118
|
+
- Video: captions for dialogue/audio content; audio description for visual-only information
|
|
119
|
+
- Auto-playing media: provide pause control; do not autoplay with sound
|
|
120
|
+
|
|
121
|
+
## Forms
|
|
122
|
+
|
|
123
|
+
```html
|
|
124
|
+
<fieldset>
|
|
125
|
+
<legend>Shipping address</legend>
|
|
126
|
+
<label for="street">Street <span aria-hidden="true">*</span></label>
|
|
127
|
+
<input id="street" name="street" required aria-required="true"
|
|
128
|
+
aria-describedby="street-error" />
|
|
129
|
+
<span id="street-error" role="alert"></span>
|
|
130
|
+
</fieldset>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
- Group related fields in `<fieldset>` with `<legend>`
|
|
134
|
+
- Error messages: use `role="alert"` or `aria-live="assertive"` so screen readers announce them
|
|
135
|
+
- Required fields: `required` + `aria-required="true"`; indicate requirement visually and in text
|
|
136
|
+
|
|
137
|
+
## Testing Checklist
|
|
138
|
+
|
|
139
|
+
- [ ] Run `axe` or `Lighthouse Accessibility` — fix all violations
|
|
140
|
+
- [ ] Navigate entire flow with keyboard only
|
|
141
|
+
- [ ] Test with VoiceOver (macOS/iOS) or NVDA/JAWS (Windows)
|
|
142
|
+
- [ ] Verify color contrast meets 4.5:1 for body text
|
|
143
|
+
- [ ] Test with browser zoom at 200% — no horizontal scroll, no content loss
|
|
144
|
+
- [ ] Test with `prefers-reduced-motion: reduce` enabled
|
|
145
|
+
- [ ] All form errors are announced by screen reader
|
|
146
|
+
|
|
147
|
+
## Cognitive Load
|
|
148
|
+
|
|
149
|
+
- Plain language: grade 8 reading level or below for public-facing copy
|
|
150
|
+
- Consistent navigation: same elements in same place across pages
|
|
151
|
+
- Timeouts: warn before session expiry; allow extension
|
|
152
|
+
- Error recovery: clear error messages with actionable fix instructions
|
|
153
|
+
- No flashing content: nothing flashing more than 3 times/second (seizure risk)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
skills/frontend-design/component-patterns.md — Component Patterns — Use this skill when designing component architecture, building design systems, o
|
|
3
|
+
|
|
4
|
+
Use this skill when designing component architecture, building design systems, or structuring reusable UI. ## Component Hierarchy
|
|
5
|
+
-->
|
|
6
|
+
# Component Patterns
|
|
7
|
+
|
|
8
|
+
Use this skill when designing component architecture, building design systems, or structuring reusable UI.
|
|
9
|
+
|
|
10
|
+
## Component Hierarchy
|
|
11
|
+
|
|
12
|
+
### Atoms
|
|
13
|
+
- Smallest meaningful UI elements: button, input, label, icon, badge
|
|
14
|
+
- Self-contained: no dependencies on other components
|
|
15
|
+
- Accept props for variants: size, color, disabled state
|
|
16
|
+
- Fully accessible with ARIA attributes and keyboard support
|
|
17
|
+
|
|
18
|
+
### Molecules
|
|
19
|
+
- Combinations of atoms: search field (input + button), form group (label + input + error)
|
|
20
|
+
- Encapsulate a single interaction pattern
|
|
21
|
+
- Manage internal state for the interaction only
|
|
22
|
+
|
|
23
|
+
### Organisms
|
|
24
|
+
- Complex sections composed of molecules: navigation bar, card grid, data table
|
|
25
|
+
- May connect to data sources or global state
|
|
26
|
+
- Define layout and composition of their children
|
|
27
|
+
|
|
28
|
+
### Templates and Pages
|
|
29
|
+
- Templates define the layout structure without data
|
|
30
|
+
- Pages are templates filled with real content and connected to routing
|
|
31
|
+
|
|
32
|
+
## Composition Patterns
|
|
33
|
+
|
|
34
|
+
### Compound Components
|
|
35
|
+
- Related components share implicit state via context
|
|
36
|
+
- Parent owns state; children consume and render
|
|
37
|
+
- Gives consumers control over rendering while keeping logic centralized
|
|
38
|
+
|
|
39
|
+
### Render Props / Slots
|
|
40
|
+
- Component provides behavior; consumer provides rendering
|
|
41
|
+
- Useful for headless components: dropdown logic without markup opinion
|
|
42
|
+
- Keeps ARIA, keyboard, and focus management in the shared layer
|
|
43
|
+
|
|
44
|
+
### Container / Presentational
|
|
45
|
+
- Container: handles data fetching, state management, side effects
|
|
46
|
+
- Presentational: receives props, renders UI, stays pure
|
|
47
|
+
- Easier to test, reuse, and maintain
|
|
48
|
+
|
|
49
|
+
### Polymorphic Components
|
|
50
|
+
- `as` or `component` prop to render as different HTML elements
|
|
51
|
+
- A `Button` that renders as `<a>` for link-style buttons
|
|
52
|
+
- Preserves type safety with generics
|
|
53
|
+
|
|
54
|
+
## Props Design
|
|
55
|
+
|
|
56
|
+
- Required props: minimum needed for the component to function
|
|
57
|
+
- Optional props with sensible defaults
|
|
58
|
+
- Boolean props: avoid double negatives (`isDisabled` not `isNotEnabled`)
|
|
59
|
+
- Event handlers: `on` prefix (`onClick`, `onChange`)
|
|
60
|
+
- Children: use `children` prop or slots for composition
|
|
61
|
+
- Avoid prop drilling beyond two levels; use context or composition
|
|
62
|
+
|
|
63
|
+
## State Ownership
|
|
64
|
+
|
|
65
|
+
| State Type | Where to Manage |
|
|
66
|
+
|---|---|
|
|
67
|
+
| UI state (open, focused, hovered) | Component-local |
|
|
68
|
+
| Form state (values, validation, dirty) | Form library or parent component |
|
|
69
|
+
| Server state (API data, cache) | Data fetching library (TanStack Query, SWR) |
|
|
70
|
+
| URL state (filters, pagination, tab) | URL / router |
|
|
71
|
+
| Global state (theme, user, preferences) | Context or lightweight store |
|
|
72
|
+
|
|
73
|
+
- Lift state to the nearest common ancestor that needs it
|
|
74
|
+
- Derive values instead of storing computed state
|
|
75
|
+
- Single source of truth for each piece of state
|
|
76
|
+
|
|
77
|
+
## Design System Tokens
|
|
78
|
+
|
|
79
|
+
- **Color**: semantic names (text-primary, surface-elevated, border-subtle)
|
|
80
|
+
- **Typography**: scale steps (text-sm, text-base, text-lg, text-xl)
|
|
81
|
+
- **Spacing**: scale steps (space-1 through space-12)
|
|
82
|
+
- **Radius**: small, medium, large, full
|
|
83
|
+
- **Shadow**: elevation levels (shadow-sm, shadow-md, shadow-lg)
|
|
84
|
+
- Implement as CSS custom properties or theme objects
|
|
85
|
+
- Document every token with visual examples
|
|
86
|
+
|
|
87
|
+
## Accessibility Checklist
|
|
88
|
+
|
|
89
|
+
- [ ] Every interactive element is keyboard accessible
|
|
90
|
+
- [ ] Focus order matches visual order
|
|
91
|
+
- [ ] Focus indicators are visible
|
|
92
|
+
- [ ] ARIA roles, labels, and states are correct
|
|
93
|
+
- [ ] Color contrast meets WCAG AA
|
|
94
|
+
- [ ] Animations respect `prefers-reduced-motion`
|
|
95
|
+
- [ ] Screen reader announces state changes (live regions)
|
|
96
|
+
|
|
97
|
+
## Testing Components
|
|
98
|
+
|
|
99
|
+
- Unit test: logic, state transitions, prop handling
|
|
100
|
+
- Interaction test: click, type, keyboard navigation
|
|
101
|
+
- Visual regression: screenshot comparison at key breakpoints
|
|
102
|
+
- Accessibility audit: automated scanning plus manual keyboard test
|
|
103
|
+
- Storybook or equivalent for isolated component development and documentation
|
|
104
|
+
|
|
105
|
+
## Anti-Patterns
|
|
106
|
+
|
|
107
|
+
- God components that handle fetching, state, rendering, and styling
|
|
108
|
+
- Prop drilling through more than two intermediate components
|
|
109
|
+
- Tightly coupled components that cannot be used independently
|
|
110
|
+
- Rebuilding browser-native behavior (scrolling, focus management) poorly
|
|
111
|
+
- CSS leaking between components via global selectors
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
skills/frontend-design/engineering.md — Frontend Engineering — Use this skill when working on build tooling, bundling, rendering strategies, or
|
|
3
|
+
|
|
4
|
+
Use this skill when working on build tooling, bundling, rendering strategies, or frontend infrastructure. ## Build Tools
|
|
5
|
+
-->
|
|
6
|
+
# Frontend Engineering
|
|
7
|
+
|
|
8
|
+
Use this skill when working on build tooling, bundling, rendering strategies, or frontend infrastructure.
|
|
9
|
+
|
|
10
|
+
## Build Tools
|
|
11
|
+
|
|
12
|
+
| Tool | Strength |
|
|
13
|
+
|---|---|
|
|
14
|
+
| Vite | Fast dev server, ESM-native, good for most projects |
|
|
15
|
+
| Turbopack | Next.js integrated, incremental compilation |
|
|
16
|
+
| esbuild | Extremely fast bundling for libraries and tools |
|
|
17
|
+
| Webpack | Mature ecosystem, complex configuration |
|
|
18
|
+
| Rollup | Clean ESM output for libraries |
|
|
19
|
+
| Rspack | Webpack-compatible with Rust-based speed |
|
|
20
|
+
|
|
21
|
+
### Configuration Principles
|
|
22
|
+
- Start with framework defaults; customize only when needed
|
|
23
|
+
- Enable tree-shaking for unused code elimination
|
|
24
|
+
- Code-split by route and by heavy dependency
|
|
25
|
+
- Source maps in development; conditional in production (security vs debugging trade-off)
|
|
26
|
+
- Hashed filenames for cache busting
|
|
27
|
+
|
|
28
|
+
## Rendering Strategies
|
|
29
|
+
|
|
30
|
+
### Static Site Generation (SSG)
|
|
31
|
+
- Pre-render pages at build time
|
|
32
|
+
- Best for: marketing pages, blogs, documentation
|
|
33
|
+
- Fastest TTFB; cacheable at CDN edge
|
|
34
|
+
- Rebuild on content change or use incremental regeneration
|
|
35
|
+
|
|
36
|
+
### Server-Side Rendering (SSR)
|
|
37
|
+
- Render on each request
|
|
38
|
+
- Best for: dynamic content, personalized pages, SEO-critical content
|
|
39
|
+
- Higher TTFB than SSG; requires server infrastructure
|
|
40
|
+
- Hydration on the client for interactivity
|
|
41
|
+
|
|
42
|
+
### Client-Side Rendering (CSR)
|
|
43
|
+
- Render entirely in the browser
|
|
44
|
+
- Best for: authenticated apps, dashboards, tools behind login
|
|
45
|
+
- Fast after initial load; poor SEO without prerendering
|
|
46
|
+
- Show skeleton during initial data fetch
|
|
47
|
+
|
|
48
|
+
### Streaming SSR
|
|
49
|
+
- Send HTML progressively as components resolve
|
|
50
|
+
- Reduces TTFB by starting the response before all data is ready
|
|
51
|
+
- Suspense boundaries define streaming chunks
|
|
52
|
+
- Best for: pages with mixed fast and slow data sources
|
|
53
|
+
|
|
54
|
+
### Islands Architecture
|
|
55
|
+
- Static HTML with isolated interactive components (islands)
|
|
56
|
+
- Minimal JavaScript shipped; only interactive parts hydrate
|
|
57
|
+
- Best for: content-heavy sites with sparse interactivity
|
|
58
|
+
- Frameworks: Astro, Fresh
|
|
59
|
+
|
|
60
|
+
## Performance Budget
|
|
61
|
+
|
|
62
|
+
| Page Type | JS (gzipped) | CSS (gzipped) | LCP |
|
|
63
|
+
|---|---|---|---|
|
|
64
|
+
| Landing | <150KB | <30KB | <2.5s |
|
|
65
|
+
| App page | <300KB | <50KB | <3s |
|
|
66
|
+
| Microsite | <80KB | <15KB | <2s |
|
|
67
|
+
|
|
68
|
+
### Optimization Techniques
|
|
69
|
+
- Dynamic imports for below-the-fold and conditional features
|
|
70
|
+
- Preload critical resources: hero image, primary font
|
|
71
|
+
- Defer non-critical CSS and JavaScript
|
|
72
|
+
- Compress with Brotli (or gzip fallback)
|
|
73
|
+
- Image optimization: AVIF/WebP, explicit dimensions, lazy loading
|
|
74
|
+
|
|
75
|
+
## Module Federation
|
|
76
|
+
|
|
77
|
+
- Share dependencies across independently deployed micro-frontends
|
|
78
|
+
- Define clear ownership: one team per module
|
|
79
|
+
- Version shared dependencies carefully
|
|
80
|
+
- Fallback when a remote module is unavailable
|
|
81
|
+
- Use for: large organizations with multiple teams on one product
|
|
82
|
+
|
|
83
|
+
## Monorepo Patterns
|
|
84
|
+
|
|
85
|
+
- Nx, Turborepo, or PNPM workspaces for multi-package management
|
|
86
|
+
- Share configuration (ESLint, TypeScript, test setup) from root
|
|
87
|
+
- Affected-based CI: only build/test changed packages and dependents
|
|
88
|
+
- Consistent dependency versions across packages
|
|
89
|
+
- Publish internal packages with workspace protocol
|
|
90
|
+
|
|
91
|
+
## Developer Experience
|
|
92
|
+
|
|
93
|
+
- Hot module replacement for fast iteration
|
|
94
|
+
- TypeScript for type safety across the codebase
|
|
95
|
+
- Storybook for isolated component development
|
|
96
|
+
- Automated formatting and linting on save (Prettier, ESLint)
|
|
97
|
+
- Preview deployments on pull requests
|
|
98
|
+
|
|
99
|
+
## Testing Infrastructure
|
|
100
|
+
|
|
101
|
+
- Unit: Vitest or Jest for logic and utilities
|
|
102
|
+
- Component: Testing Library for interaction tests
|
|
103
|
+
- Visual regression: Playwright screenshots at key breakpoints
|
|
104
|
+
- E2E: Playwright or Cypress for critical user flows
|
|
105
|
+
- Accessibility: axe-core in CI, manual keyboard testing
|
|
106
|
+
- Run the full suite in CI; fast subset on pre-commit
|
|
107
|
+
|
|
108
|
+
## Deployment
|
|
109
|
+
|
|
110
|
+
- CDN for static assets with long-lived cache and content hashing
|
|
111
|
+
- Edge functions for dynamic personalization at the CDN layer
|
|
112
|
+
- Preview environments per pull request
|
|
113
|
+
- Feature flags for progressive rollout
|
|
114
|
+
- Rollback strategy: revert deploy or disable feature flag
|
|
115
|
+
|
|
116
|
+
## Anti-Patterns
|
|
117
|
+
|
|
118
|
+
- Bundling everything into one chunk (no code splitting)
|
|
119
|
+
- Importing entire libraries when only a function is needed
|
|
120
|
+
- Client-side rendering for SEO-critical pages
|
|
121
|
+
- No performance budget (unconstrained growth)
|
|
122
|
+
- Polyfilling for browsers no longer in the support matrix
|