
frontend-flow
by djimontyp
SKILL.md
name: frontend-flow description: 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.
Frontend 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 | @shared/tokens/* | bg-red-500, text-green-600 |
| Patterns | @shared/patterns/* | Manual composition |
| Icons | lucide-react | heroicons, Radix icons |
| Touch | h-11 w-11 (44px) | h-9 w-9 (36px) |
| Spacing | gap-2, gap-4, p-4 | gap-3, p-5 (off-grid) |
| Icon buttons | aria-label="..." | 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 | shared/ui/ | Button, Dialog, Select |
| shadcn + customize | shared/ui/ (modify) | Badge with new variant |
| Composition | shared/patterns/ | CardWithStatus, FormField |
| Business reusable | shared/components/ | SearchBar, TopicSelector |
| Feature-specific | features/X/components/ | AtomCard, ProviderList |
| Page-specific | pages/X/components/ | 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 |
|---|---|---|
shared/ui/ | Always | 4-6 |
shared/patterns/ | Always | 5-8 |
shared/components/ | Always | 4-6 |
features/*/ | If >50 LOC or reused | 2-4 |
Actions:
- Create
.stories.tsxwithtags: ['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 | no-raw-tailwind-colors | Semantic tokens only |
| 2 | no-odd-spacing | 4px grid system |
| 3 | no-heroicons | lucide-react only |
| 4 | no-raw-zindex | Named z-index tokens |
| 5 | no-direct-fonts | Font tokens only |
| 6 | no-raw-page-wrapper | PageWrapper required |
| 7 | no-direct-api-imports | Service classes |
| 8 | no-hardcoded-api-paths | API_ENDPOINTS config |
| 9 | stories-require-autodocs | 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 | tsc --noEmit passes | Yes |
| ESLint | 9 Design System rules pass | Yes |
| Tests | Unit tests pass | Yes |
| Story Coverage | story:check passes | Yes |
| Accessibility | test:a11y for shared/ | Recommended |
| Knowledge | Learnings captured in vault | Recommended |
Principle: If verification fails → task NOT complete.
Quick Reference
Commands:
| Action | Command |
|---|---|
| Start Storybook | just storybook |
| TypeScript check | npx tsc --noEmit |
| ESLint | npm run lint |
| ESLint fix | npm run lint:fix |
| Unit tests | npm run test:run |
| Story coverage | npm run story:check |
| A11y tests | npm run test:a11y |
Related skills:
| Skill | When to use |
|---|---|
/frontend | Architecture, state management |
/storybook | Story templates, interaction tests |
/design-tokens | Token API reference |
/testing | 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.
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon