Claude-skill-registry frontend-flow
Ensures frontend code quality by enforcing Design System (9 ESLint rules), Storybook coverage, and 5-step verification pipeline. Use when creating/modifying React components in frontend/src/, especially shared/ where quality gates are mandatory. Triggers on "create component", "verify frontend", "storybook coverage", "перевір фронтенд", "frontend flow". Goal - all verification passes before task completion, knowledge captured in vault.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/frontend-flow" ~/.claude/skills/majiayu000-claude-skill-registry-frontend-flow && rm -rf "$T"
skills/data/frontend-flow/SKILL.mdFrontend Flow
Quality-first frontend development workflow for Pulse Radar.
Overview
┌─────────────────────────────────────────────────────────────┐ │ QUALITY-FOCUSED FRONTEND WORKFLOW │ │ │ │ 1. SESSION 2. DISCOVERY 3. IMPLEMENT 4. STORYBOOK │ │ ──────────── ──────────── ──────────── ──────────── │ │ Journal Storybook MCP Tokens Stories │ │ Beads Vault Search Patterns Screenshots │ │ Context AGENTS.md Design System Interaction │ │ │ │ 5. VERIFICATION (CRITICAL) 6. KNOWLEDGE │ │ ──────────────────────────── ──────────── │ │ TypeScript → ESLint → Tests Journal done │ │ Story check → Accessibility Capture │ │ ALL MUST PASS Beads update │ └─────────────────────────────────────────────────────────────┘
Principle: Quality over speed. Verification must pass before task completion.
Phase 1: Session & Context
Trigger: Starting frontend work
Actions:
- Start journal session:
/obsidian:journal session "Task title" - Get issue context:
bd show {issue} - Read previous handoff if exists
Goal: Establish context and enable progress tracking.
Phase 2: Discovery (CRITICAL!)
Trigger: BEFORE creating or modifying any component
Required checks:
# 1. Check existing components in Storybook storybook_list_components # 2. Get props API for similar components storybook_get_component_props componentId="..." # 3. Search knowledge vault /obsidian:search "relevant pattern" # 4. Read Design System rules frontend/AGENTS.md
Checkpoint: "Existing component found? → USE IT instead of creating new!"
Anti-pattern: Creating new component without Storybook check = quality violation.
→ See @references/discovery.md for detailed checklist.
Phase 3: Implementation (Design System)
Trigger: During code writing
Required rules:
| Rule | Use | Don't Use |
|---|---|---|
| Colors | | , |
| Patterns | | Manual composition |
| Icons | | heroicons, Radix icons |
| Touch | (44px) | (36px) |
| Spacing | , , | , (off-grid) |
| Icon buttons | | No label |
| Status | Icon + Text | Color only |
Related skills:
/frontend, /design-tokens
Phase 3.5: Component Portability (NEW!)
Trigger: When creating/modifying components in
shared/
Principle: Components in shared/ must be PORTABLE — work without API, store, router.
┌─────────────────────────────────────────────────────────────┐ │ PORTABLE COMPONENT = Pure Function │ │ │ │ Props → Component → UI │ │ │ │ ✅ No useQuery/useMutation inside │ │ ✅ No apiClient/fetch calls inside │ │ ✅ No useNavigate/useParams/useLocation │ │ ✅ No useStore (Zustand) directly │ │ ✅ All data via props │ │ ✅ Works in Storybook WITHOUT providers │ └─────────────────────────────────────────────────────────────┘
Anti-pattern (FORBIDDEN):
// ❌ NON-PORTABLE — violates CDD principles import { useQuery } from '@tanstack/react-query' import { apiClient } from '@/shared/lib/api' export function ActivityHeatmap() { const { data } = useQuery({ queryFn: () => apiClient.get('/activity') }) return <Heatmap data={data} /> }
Correct pattern (Presenter + Hook):
// ✅ PORTABLE PRESENTER — shared/components/ interface ActivityHeatmapProps { data: ActivityDataPoint[] isLoading?: boolean className?: string } export function ActivityHeatmap({ data, isLoading, className }: ActivityHeatmapProps) { if (isLoading) return <ActivityHeatmapSkeleton /> return <HeatmapRenderer data={data} className={className} /> } // Data hook — features/activity/hooks/ or page level export function useActivityData(timeRange: TimeRange) { return useQuery({ queryKey: ['activity', timeRange], queryFn: () => activityService.getActivity(timeRange) }) } // Page usage — composition function DashboardPage() { const { data, isLoading } = useActivityData('week') return <ActivityHeatmap data={data ?? []} isLoading={isLoading} /> }
Portability Checklist:
- No useQuery/useMutation in shared/components
- No apiClient/fetch imports in shared/components
- No useNavigate/useParams in shared/components
- All data passed via typed props interface
- Optional className prop for customization
- Works in Storybook without QueryClient/Router mocks
Verification command:
# Should return 0 violations grep -rE "useQuery|apiClient" src/shared/components --include="*.tsx" | grep -v test
Phase 3.6: Component Integration Decision (NEW!)
Trigger: When needing a new UI element
Decision Tree:
NEED NEW UI ELEMENT? │ ▼ ┌─────────────────────────────┐ │ 1. Check shared/ui/ │ → EXISTS → USE IT └─────────────────────────────┘ │ NOT FOUND ▼ ┌─────────────────────────────┐ │ 2. Check shared/components/ │ → EXISTS → USE IT └─────────────────────────────┘ │ NOT FOUND ▼ ┌─────────────────────────────┐ │ 3. Check shared/patterns/ │ → EXISTS → USE IT └─────────────────────────────┘ │ NOT FOUND ▼ ┌─────────────────────────────┐ │ 4. Check shadcn registry │ │ ui.shadcn.com/docs │ └─────────────────────────────┘ │ FOUND ┴ NOT FOUND │ │ ▼ ▼ EVALUATE BUILD in shared/components │ Fits 80%? ┬ YES → npx shadcn add → shared/ui │ └ NO → WRAP in shared/components
Where to put new component:
| Type | Location | Example |
|---|---|---|
| shadcn primitive | | Button, Dialog, Select |
| shadcn + customize | (modify) | Badge with new variant |
| Composition | | CardWithStatus, FormField |
| Business reusable | | SearchBar, TopicSelector |
| Feature-specific | | AtomCard, ProviderList |
| Page-specific | | DashboardStats |
Adding shadcn component example:
# 1. Check if exists grep -r "DatePicker\|Calendar" src/shared/ # 2. Add from shadcn npx shadcn@latest add calendar # 3. Create composition wrapper if needed # src/shared/components/DatePicker/index.tsx
Checkpoint: "Component location decided? Portability requirements clear?"
Phase 4: Storybook (Component Library)
Trigger: After creating/modifying component
Mandatory coverage:
| Location | Story Required? | Min Stories |
|---|---|---|
| Always | 4-6 |
| Always | 5-8 |
| Always | 4-6 |
| If >50 LOC or reused | 2-4 |
Actions:
- Create
with.stories.tsxtags: ['autodocs'] - Cover all variants, states, sizes
- Add interaction tests for clickable elements
- Capture screenshot:
storybook_capture_screenshot storyId="..."
Checkpoint: "Story created with full coverage?"
Related skill:
/storybook
Phase 5: Verification Pipeline (MOST IMPORTANT!)
Trigger: After code written, BEFORE considering task complete
Required pipeline (ALL steps!):
cd frontend # 1. TypeScript — type safety npx tsc --noEmit # 2. ESLint — Design System compliance (9 rules) npm run lint # 3. Unit tests — logic correctness npm run test:run # 4. Story coverage — documentation npm run story:check # 5. Accessibility (for shared/ components) npm run test:a11y
ESLint Design System Rules (all 9 — ERROR level):
| # | Rule | Ensures |
|---|---|---|
| 1 | | Semantic tokens only |
| 2 | | 4px grid system |
| 3 | | lucide-react only |
| 4 | | Named z-index tokens |
| 5 | | Font tokens only |
| 6 | | PageWrapper required |
| 7 | | Service classes |
| 8 | | API_ENDPOINTS config |
| 9 | | Autodocs tag |
If any step fails: Fix → Re-run pipeline → Don't proceed until ALL pass.
→ See @references/verification.md for troubleshooting.
Phase 6: Knowledge Capture
Trigger: After successful verification
Actions:
- Close journal session:
/obsidian:journal done - Add findings as wikilinks:
[[знання/паттерни/pattern-name]] - Capture learnings:
/obsidian:capture auto - Update Beads:
bd comments add {issue} "Progress: ..." - Generate handoff for next session
Learning categories:
— reusable approachesзнання/паттерни/
— architectural decisionsзнання/рішення/
— mistakes to avoidзнання/помилки/
→ See @references/documentation.md for templates.
Quality Gates
| Gate | Criterion | Blocking? |
|---|---|---|
| Discovery | Storybook checked BEFORE coding | Yes |
| Design System | Tokens instead of raw colors | Yes (ESLint blocks) |
| Storybook | Story for shared/ components | Yes |
| TypeScript | passes | Yes |
| ESLint | 9 Design System rules pass | Yes |
| Tests | Unit tests pass | Yes |
| Story Coverage | passes | Yes |
| Accessibility | for shared/ | Recommended |
| Knowledge | Learnings captured in vault | Recommended |
Principle: If verification fails → task NOT complete.
Quick Reference
Commands:
| Action | Command |
|---|---|
| Start Storybook | |
| TypeScript check | |
| ESLint | |
| ESLint fix | |
| Unit tests | |
| Story coverage | |
| A11y tests | |
Related skills:
| Skill | When to use |
|---|---|
| Architecture, state management |
| Story templates, interaction tests |
| Token API reference |
| Vitest, Playwright patterns |
Example
User: "Create TopicCard component" Claude follows frontend-flow: 1. [Session] /obsidian:journal session "TopicCard component" 2. [Discovery] BEFORE coding! → storybook_list_components → check existing cards → Found CardWithStatus — base structure exists! → /obsidian:search "card pattern" → found prior decisions 3. [Implementation] → Using @shared/tokens for colors → Using @shared/patterns/CardWithStatus as base → All icon buttons with aria-label → 44px touch targets 4. [Storybook] → TopicCard.stories.tsx with tags: ['autodocs'] → 5 stories: Default, Empty, Loading, Error, WithBadge → storybook_capture_screenshot 5. [Verification] ALL must pass! → npx tsc --noEmit ✅ → npm run lint ✅ (9 ESLint rules pass) → npm run test:run ✅ → npm run story:check ✅ → npm run test:a11y ✅ 6. [Knowledge] → /obsidian:journal done → Findings: [[знання/паттерни/topic-card-composition]] → /obsidian:capture auto
Key: Verification runs COMPLETELY before task is considered done.