Read
.agents/software-principles/SKILL.mdfirst.
Pre-Code Checklist
- All four states: loading · error · empty · ideal
- Server vs. client boundary (default: Server Component)
- Existing conventions in
app/,components/,hooks/,lib/ - Only use libraries in
package.json
Architecture
| Need | Solution |
|---|---|
| Fetch + render data | async Server Component |
useState / events / browser API |
'use client' — push as deep as possible |
| Reusable UI | components/ — server-first, add 'use client' only if needed |
| Custom logic | hooks/*.js (client) · lib/*.js (server/shared) |
Extensions: .jsx for JSX · .js for hooks and utilities.
Four States (all required)
| State | Implementation |
|---|---|
| Loading | loading.jsx or <Suspense fallback={<Skeleton />}> |
| Error | error.jsx — must be 'use client' |
| Empty | Inline message — helpful, not just "No data" |
| Not found | not-found.jsx |
Data Fetching
- Server:
asyncRSC +fetchwith{ next: { revalidate: N } }orcache()for dedup - Client:
useEffectwith cleanup — only when Server Component is impossible - Never
useEffectfor data when Server Component works useEffectdeps array must be exhaustive — no suppression comments. Extract stable refs withuseCallback/useMemoif needed
Styling
- Tailwind: existing tokens only. No
[]arbitrary values unless truly one-off - CSS Modules: follow existing class naming pattern
- Never invent design tokens, colors, or custom fonts
Forms, Routing & Quality
- Mutations → Server Actions (
'use server') layout.jsxfor shared UI. ExportmetadataorgenerateMetadatafor SEOnext/imagefor images ·next/fontfor fonts ·@/alias for all imports- Semantic HTML + ARIA. All interactive elements keyboard-accessible
- Stable
keyprops — never array index for dynamic lists - Env vars server-only unless
NEXT_PUBLIC_prefix
Never Do
- Hooks or browser APIs in Server Components
.tsx/.tsextensions — this is a JS project- Libraries not in
package.json - Invented design tokens or broken folder conventions
- Skip any of the four states
key={index}on dynamic lists- Suppress
useEffectexhaustive-deps lint rule