brokle-frontend-dev

Use this skill when developing Next.js/React frontend code for Brokle. Includes components, pages, hooks, API clients, stores, or any frontend features.

$ 설치

git clone https://github.com/brokle-ai/brokle /tmp/brokle && cp -r /tmp/brokle/.claude/skills/brokle-frontend-dev ~/.claude/skills/brokle

// tip: Run this command in your terminal to install the skill


name: brokle-frontend-dev description: Use this skill when developing Next.js/React frontend code for Brokle. Includes components, pages, hooks, API clients, stores, or any frontend features.

Brokle Frontend Development

Tech Stack

TechnologyVersionPurpose
Next.js15.5.2App Router, Turbopack
React19.2.0UI library
TypeScript5.9.3Strict mode
Tailwind CSS4.1.15Styling
shadcn/ui-Component primitives
Zustand-Client state
React Query-Server state
React Hook Form-Forms + Zod validation
Vitest-Testing
pnpm-Package manager

Critical Import Rules

Always import from feature index, never internal paths:

// CORRECT
import { useAuth, SignInForm } from '@/features/authentication'
import { useOrganization } from '@/features/organizations'
import { Button } from '@/components/ui/button'
import { cn } from '@/lib/utils'
import { apiClient } from '@/lib/api/core/client'

// FORBIDDEN - internal paths
import { useAuth } from '@/features/authentication/hooks/use-auth'
import { AuthStore } from '@/features/authentication/stores/auth-store'

Feature-Based Architecture

web/src/
├── app/                      # Next.js App Router (routing only)
│   ├── (auth)/              # Auth route group
│   └── (dashboard)/         # Dashboard routes
├── features/                # Domain features (self-contained)
│   ├── authentication/
│   ├── organizations/
│   ├── projects/
│   └── [feature]/
│       ├── components/      # Feature UI
│       ├── hooks/           # React hooks
│       ├── api/             # API functions
│       ├── stores/          # Zustand (optional)
│       ├── types/           # TypeScript types
│       └── index.ts         # Public API exports
├── components/
│   ├── ui/                 # shadcn/ui primitives
│   ├── shared/             # Cross-feature components
│   └── layout/             # App shell
├── lib/api/core/           # BrokleAPIClient
└── hooks/                  # Global hooks

Rule: Routes are thin - delegate to feature components:

// app/(dashboard)/projects/page.tsx
import { ProjectsList } from '@/features/projects'
export default function ProjectsPage() {
  return <ProjectsList />
}

State Management

State TypeToolLocation
Server dataReact QueryFeature hooks
Client stateZustandFeature stores
Form stateReact Hook Form + ZodComponent
URL stateuseSearchParams()Component

Server State Pattern

// features/[feature]/hooks/use-data.ts
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { getData, updateData } from '../api/data-api'

export function useData(id: string) {
  const queryClient = useQueryClient()

  const query = useQuery({
    queryKey: ['data', id],
    queryFn: () => getData(id),
  })

  const mutation = useMutation({
    mutationFn: updateData,
    onSuccess: () => queryClient.invalidateQueries({ queryKey: ['data', id] }),
  })

  return { ...query, update: mutation.mutate }
}

Client State Pattern

// features/[feature]/stores/feature-store.ts
import { create } from 'zustand'

interface FeatureState {
  selectedId: string | null
  setSelectedId: (id: string | null) => void
}

export const useFeatureStore = create<FeatureState>((set) => ({
  selectedId: null,
  setSelectedId: (id) => set({ selectedId: id }),
}))

Component Patterns

Server Components (Default)

No directive needed. Use for static content and SEO:

export default async function Page({ params }: { params: { id: string } }) {
  const data = await fetchData(params.id)
  return <div>{data.title}</div>
}

Client Components

Add 'use client' when needed:

'use client'
import { useState } from 'react'

export function Interactive() {
  const [count, setCount] = useState(0)
  return <Button onClick={() => setCount(c => c + 1)}>{count}</Button>
}

Use 'use client' when:

  • Event handlers (onClick, onChange)
  • React hooks (useState, useEffect)
  • Browser APIs (localStorage, window)

API Client Pattern

// features/[feature]/api/feature-api.ts
import { apiClient } from '@/lib/api/core/client'
import type { FeatureResponse, CreateFeatureRequest } from '../types'

export async function getFeature(id: string): Promise<FeatureResponse> {
  const response = await apiClient.get<FeatureResponse>(`/feature/${id}`)
  return response.data
}

export async function createFeature(data: CreateFeatureRequest): Promise<FeatureResponse> {
  const response = await apiClient.post<FeatureResponse>('/feature', data)
  return response.data
}

Form Pattern

'use client'
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'

const schema = z.object({
  email: z.string().email(),
  name: z.string().min(2),
})

type FormData = z.infer<typeof schema>

export function MyForm() {
  const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
    resolver: zodResolver(schema),
  })

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Input {...register('email')} />
      {errors.email && <p className="text-destructive">{errors.email.message}</p>}
    </form>
  )
}

Feature Index Pattern

// features/[feature]/index.ts

// Hooks
export { useFeature } from './hooks/use-feature'

// Components
export { FeatureComponent } from './components/feature-component'

// Types (selective)
export type { FeatureData, FeatureConfig } from './types'

// DO NOT export stores directly - use hooks

Testing

// features/[feature]/__tests__/component.test.tsx
import { describe, it, expect } from 'vitest'
import { render, screen } from '@testing-library/react'
import { Component } from '../components/component'

describe('Component', () => {
  it('renders', () => {
    render(<Component />)
    expect(screen.getByText('Expected')).toBeInTheDocument()
  })
})

Development Commands

cd web

pnpm dev          # Dev server (Turbopack)
pnpm build        # Production build
pnpm lint         # Next.js linter
pnpm format       # Prettier
pnpm test         # Vitest
pnpm test:watch   # Watch mode

Supporting References

Load these files when you need detailed guidance:

NeedReference
Colors, typography, spacing, dark modedesign-system.md
UI components, state patterns, formscomponent-patterns.md
Animations, transitions, micro-interactionsanimation-patterns.md
Complete feature example (authentication)feature-patterns.md
Decision trees, cheat sheetsquick-reference.md

Quick Decision Tree

Creating new functionality?

  • Feature-specific → features/[feature]/
  • Shared across features → components/shared/
  • UI primitive → components/ui/

Adding state?

  • Server data → React Query hook
  • Client state → Zustand store
  • Form → React Hook Form
  • URL → useSearchParams()

Component type?

  • Needs interactivity/hooks → 'use client'
  • Static/SEO → Server Component (default)

Best Practices

  1. Import from feature index - Never from internal paths
  2. Keep routes thin - Delegate to feature components
  3. Server Components default - Add 'use client' only when needed
  4. Type everything - No any types
  5. Error boundaries - Add per feature and route
  6. Check existing components - components/shared/ before creating new