一键导入
fsd-architecture
Feature-Sliced Design architecture for frontend. Use when creating new features, slices, or understanding the FSD layer structure.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Feature-Sliced Design architecture for frontend. Use when creating new features, slices, or understanding the FSD layer structure.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Generate TypeScript API client from Swagger/Go comments. Use when updating API endpoints, adding new routes, or regenerating the frontend API client after backend changes.
Manage database migrations and Better Auth schema. Use when adding tables, modifying schema, running migrations, or resetting the database.
Generate full-stack features. Backend = hand-written bounded-context aggregates (DDD); frontend = FSD slices with HydrationBoundary. Use when creating new features, adding CRUD operations, or scaffolding new pages.
Access local technical documentation before searching the internet. Use FIRST when researching any tech stack question.
Create and manage authentication pages with server-side session handling. Use when adding login, register, or protected pages WITHOUT flicker/skeleton.
Server-Side + Client-Side Data Fetching with Orval + TanStack Query HydrationBoundary Pattern. ALWAYS use Orval - NEVER manual fetch()!
| name | fsd-architecture |
| description | Feature-Sliced Design architecture for frontend. Use when creating new features, slices, or understanding the FSD layer structure. |
| allowed-tools | Read, Edit, Write, Glob, Grep |
The frontend uses Feature-Sliced Design. This skill documentation helps you understand the architecture and correctly create new features.
app/ → widgets, features, entities, shared
widgets/ → features, entities, shared
features/ → entities, shared
entities/ → shared
shared/ → (only external libs)
Import direction: ONLY downward!
frontend/src/
├── app/ # Next.js App Router (outside FSD)
│
├── widgets/ # Composite UI Blocks
│ └── header/
│ ├── ui/
│ │ ├── header.tsx
│ │ └── mode-toggle.tsx
│ └── index.ts # Public API
│
├── features/ # User Interactions / Use Cases
│ ├── auth/
│ │ ├── ui/
│ │ │ ├── login-form.tsx
│ │ │ └── register-form.tsx
│ │ ├── model/
│ │ │ └── use-auth-sync.ts
│ │ └── index.ts
│ └── stats/
│ ├── ui/
│ │ └── stats-grid.tsx
│ ├── model/
│ │ └── use-sse.ts
│ └── index.ts
│
├── entities/ # Business Objects
│ └── user/
│ ├── ui/
│ │ └── user-info.tsx
│ ├── model/
│ │ └── types.ts
│ └── index.ts
│
└── shared/ # Reusable Code
├── ui/ # shadcn/ui components
├── api/ # Orval-generated
│ ├── endpoints/
│ ├── models/
│ └── custom-fetch.ts
├── lib/
│ ├── auth-client/ # Client-safe Auth
│ ├── auth-server/ # Server-only Auth
│ ├── query-client.ts
│ └── utils.ts
└── config/
├── providers.tsx
└── theme-provider.tsx
// Always use layer aliases:
import { Button } from "@shared/ui/button"
import { useAuthSync } from "@features/auth"
import { SessionUser } from "@entities/user"
import { Header } from "@widgets/header"
Each slice can have these segments:
| Segment | Purpose | Example |
|---|---|---|
ui/ | React Components | login-form.tsx |
model/ | Hooks, State, Types | use-auth-sync.ts |
api/ | API Calls (rare, mostly in shared) | user-api.ts |
lib/ | Utilities for the slice | validation.ts |
Every slice MUST have an index.ts:
// features/auth/index.ts
export { LoginForm } from "./ui/login-form"
export { RegisterForm } from "./ui/register-form"
export { useAuthSync, broadcastSignOut } from "./model/use-auth-sync"
Always import via index.ts:
// ✅ Correct
import { LoginForm } from "@features/auth"
// ❌ Wrong (Public API Sidestep)
import { LoginForm } from "@features/auth/ui/login-form"
mkdir -p src/features/<name>/ui
mkdir -p src/features/<name>/model # if hooks/state needed
// src/features/<name>/ui/<name>-form.tsx
"use client"
import { Button } from "@shared/ui/button"
import { Card } from "@shared/ui/card"
export function NameForm() {
return (
<Card>
<Button>Action</Button>
</Card>
)
}
// src/features/<name>/model/use-<name>.ts
"use client"
import { useQueryClient } from "@tanstack/react-query"
import { useCallback } from "react"
export function useName() {
const queryClient = useQueryClient()
// ...
return { /* ... */ }
}
// src/features/<name>/index.ts
export { NameForm } from "./ui/name-form"
export { useName } from "./model/use-name"
// app/(protected)/page.tsx
import { NameForm } from "@features/<name>"
export default function Page() {
return <NameForm />
}
// src/entities/<name>/model/types.ts
export interface Product {
id: string
name: string
price: number
}
// src/entities/<name>/ui/product-card.tsx
"use client"
import type { Product } from "../model/types"
import { Card } from "@shared/ui/card"
export function ProductCard({ product }: { product: Product }) {
return <Card>{product.name}</Card>
}
// src/entities/<name>/index.ts
export type { Product } from "./model/types"
export { ProductCard } from "./ui/product-card"
// ✅ ALLOWED
// In app/:
import { Header } from "@widgets/header"
import { LoginForm } from "@features/auth"
import { SessionUser } from "@entities/user"
import { Button } from "@shared/ui/button"
// In widgets/:
import { useAuthSync } from "@features/auth"
import { SessionUser } from "@entities/user"
import { Button } from "@shared/ui/button"
// In features/:
import { SessionUser } from "@entities/user"
import { Button } from "@shared/ui/button"
// In entities/:
import { Button } from "@shared/ui/button"
// ❌ FORBIDDEN
// In shared/ NEVER import features/!
// In entities/ NEVER import features/!
// In features/ NEVER import other features/!
FSD rules are automatically checked:
# Integrated in lint
bun run lint
# Only Steiger
bunx steiger src
| Error | Cause | Solution |
|---|---|---|
no-public-api-sidestep | Direct import instead of via index.ts | Import via index.ts |
insignificant-slice | Slice has only 1 reference | Use more or move to widget/higher layer |
forbidden-imports | Import from higher layer | Fix import direction |
// Server Component (no "use client")
// → Can only import shared/, no hooks
// Client Component
"use client"
// → Can use hooks, but NEVER server-only code
// In Client Components:
import { signIn, signOut } from "@shared/lib/auth-client"
// In Server Components:
import { getSession } from "@shared/lib/auth-server"
bun run lint checks FSD rules