- Introduction
- Pitch
- Hogwarts
- Live Demo
- MVP
- Roadmap
- Launch Sprint
- PRD
- Get Started
- Localhost
- Architecture
- Structure
- Pattern
- Page
- Layout
- Content
- Types
- Config
- Actions
- Queries
- Authorization
- Validation
- Form
- Table
- Detail
- Card
- Util
- Hooks
- List Params
- Views
- README.md
- ISSUE.md
- Technology Stack
- Database
- File
- CDN Assets
- Entry Points
- Dashboard
- Authentication
- Credentials
- OAuth
- Flow Diagrams
- Multi-Tenancy
- Offline
- Onboarding
- Onboarding Videos
- Add Values
- Admission
- Application
- Attendance
- Compliance
- Profile
- Exams
- Exam Wizard
- Timetable
- Classrooms
- Notifications
- Conference
- LMS (Lumos)
Finance
- Finance
- Fee Management
- Invoice
- Wallet
- Salary
- Payroll
- Timesheet
- Expenses
- Budget
- Receipt
- Accounts
- Banking
- Reports
- Dashboard
- Permissions
- Messages
- Integration Flow
- Provision
- AI Document Processing
- Document Intelligence
- Internationalization
- Translation
- Translation Guide
- Icons
- Docs Factory
- Inspiration
- Listings
- Teachers
- Students
- Catalog
- Library
- Contributing
- Code of conduct
- GitHub Workflow
- Database Seeds
- Database Safety
- Test Accounts
- Playwright
- Prettier
- Block Rebound
Sales & GTM
Custom hooks live next to the feature they serve. Cross-feature hooks live in src/lib/hooks/. Naming is use-<concept>.ts, kebab-case.
Categories
| Category | Purpose | Reference |
|---|---|---|
| Form / state | Multi-step orchestration, draft persistence | form/use-form.ts |
| Data fetching | Server-action wrappers with loading + error | use-domains.ts |
| File operations | Upload progress, drag-and-drop | file/use-upload.ts |
| Real-time | Socket.IO subscriptions, polling fallback | notifications/use-notifications.ts |
| URL state | nuqs wrappers for typed search params | listings/students/use-students.ts |
| Wizard | Step state, validation context | wizard/use-wizard.ts |
| Layout / responsive | Media query, mobile detect, scroll lock | src/lib/hooks/use-media-query.ts |
| Permissions | Reactive RBAC checks against the session | auth/use-permissions.ts |
| Drag and drop | DnD-kit wrappers | timetable/use-dnd.ts |
| Tables | Sorting, pagination wrappers around TanStack | table/use-table.ts |
| Animations | Framer Motion presets | atom/use-scroll-animation.ts |
| Browser APIs | Clipboard, localStorage, intersection observer | src/lib/hooks/use-clipboard.ts |
Rules
| # | Rule |
|---|---|
| 1 | "use client" at the top — hooks always run client-side |
| 2 | Named exports only |
| 3 | Return an object, not a tuple — { value, set, isLoading } |
| 4 | Stay under ~150 lines — a 523-line file with 5 hooks should be 5 files |
| 5 | Lift duplicates to src/lib/hooks/ when used in 3+ places |
Canonical example
"use client"
import { useState, useTransition } from "react"
import { deleteSubject } from "./actions"
export function useSubjectActions() {
const [pending, startTransition] = useTransition()
const [error, setError] = useState<string | null>(null)
function remove(id: string, onSuccess?: () => void) {
startTransition(async () => {
const res = await deleteSubject({ id })
if (res.success) {
onSuccess?.()
} else {
setError(res.errorCode)
}
})
}
return { remove, pending, error }
}Shared hooks already lifted
These live in src/lib/hooks/ — don't reinvent.
| Hook | Purpose |
|---|---|
use-media-query | Reactive matchMedia |
use-mobile | Mobile breakpoint detection |
use-callback-ref | Stable callback ref |
use-lock-body | Scroll lock for modals |
use-debounced-callback | Debounce a callback |
use-clipboard | Copy / read clipboard |
use-local-storage | Reactive localStorage state |
use-intersection-observer | Visibility detection |
Anti-patterns
use-media-queryduplicated 5 times,use-callback-ref3×,use-mobile3× — lift tosrc/lib/hooks/.- Multi-hook files —
form/use-form.tsis 523 lines exporting 5 hooks. Split. - Returning tuples (
[value, setValue, loading]) — switch to objects. - Side effects in render — wrap in
useEffectoruseTransition. - Reading
windowwithout an SSR guard — usetypeof window !== "undefined"oruseSyncExternalStore.
Naming
- File:
use-<concept>.ts(kebab-case). - Function:
use<Concept>(camelCase,useprefix). - Cross-feature:
src/lib/hooks/use-<concept>.ts. - Single-purpose — resist exporting 5 hooks per file.
Sibling roles
- Hooks consume server actions from
actions.ts. - Hooks don't import
dbdirectly — server-only. - Hooks export to
client.tsx,form.tsx,table.tsx. Server components don't use them.