# Component Architecture This document defines the strict separation of concerns for all UI code in the website layer. ## The Three Layers ``` apps/website/ ├── app/ ← App Layer (Pages & Layouts) ├── components/ ← Component Layer (App Components) ├── ui/ ← UI Layer (Pure Elements) └── hooks/ ← Shared Logic ``` --- ## 1. App Layer (`app/`) **Purpose**: Pages, layouts, and routing configuration. **Characteristics**: - ✅ Only page.tsx, layout.tsx, route.tsx files - ✅ Can import from `components/`, `ui/`, `hooks/` - ✅ Can use Next.js features (redirect, cookies, headers) - ✅ Can use Server Components - ❌ **NO raw HTML with styling** - ❌ **NO business logic** - ❌ **NO state management** **Allowed**: ```typescript // app/dashboard/page.tsx export default function DashboardPage() { return ( ); } ``` **Forbidden**: ```typescript // ❌ WRONG - Raw HTML in app/ export default function DashboardPage() { return (
{/* ❌ No raw HTML with styling */}

Dashboard

{/* ❌ No inline handlers */}
); } ``` --- ## 2. Component Layer (`components/`) **Purpose**: App-level components that may contain state and business logic. **Characteristics**: - ✅ Can be stateful (useState, useReducer) - ✅ Can have side effects (useEffect) - ✅ Can use hooks - ✅ Can contain business logic - ✅ Can import from `ui/`, `hooks/` - ❌ **NO Next.js imports** (navigation, routing) - ❌ **NO raw HTML with styling** (use ui/ elements) **Allowed**: ```typescript // components/DashboardHeader.tsx export function DashboardHeader() { const [isOpen, setIsOpen] = useState(false); return (
{isOpen && }
); } ``` **Forbidden**: ```typescript // ❌ WRONG - Next.js imports in components/ import { useRouter } from 'next/navigation'; // ❌ export function DashboardHeader() { const router = useRouter(); // ❌ // ... } ``` --- ## 3. UI Layer (`ui/`) **Purpose**: Pure, reusable, stateless UI elements. **Characteristics**: - ✅ Stateless (no useState, useReducer) - ✅ No side effects (no useEffect) - ✅ Pure functions based on props - ✅ Maximum reusability - ✅ Framework-agnostic - ❌ **NO state management** - ❌ **NO Next.js imports** - ❌ **NO business logic** **Allowed**: ```typescript // ui/Button.tsx export function Button({ children, onClick, variant = 'primary' }) { const className = variant === 'primary' ? 'bg-blue-500 text-white' : 'bg-gray-200 text-black'; return ( ); } // ui/Card.tsx export function Card({ children, className = '' }) { return (
{children}
); } ``` **Forbidden**: ```typescript // ❌ WRONG - State in UI element export function Button({ children }) { const [isLoading, setIsLoading] = useState(false); // ❌ return ; } // ❌ WRONG - Next.js imports import { useRouter } from 'next/navigation'; // ❌ export function Link({ href, children }) { const router = useRouter(); // ❌ // ... } ``` --- ## 4. Hooks Layer (`hooks/`) **Purpose**: Shared stateful logic. **Characteristics**: - ✅ Can use all hooks - ✅ Can contain business logic - ✅ Can be used by components and pages - ❌ **NO JSX** - ❌ **NO UI rendering** **Allowed**: ```typescript // hooks/useDropdown.ts export function useDropdown() { const [isOpen, setIsOpen] = useState(false); return { isOpen, open: () => setIsOpen(true), close: () => setIsOpen(false), toggle: () => setIsOpen(!isOpen), }; } ``` --- ## ESLint Enforcement ### 1. **No Raw HTML in `app/`** ```json { "files": ["app/**/*.tsx", "app/**/*.ts"], "rules": { "gridpilot-rules/no-raw-html-in-app": "error" } } ``` **Catches**: - `
` in app/ - ` ); } // ui/SearchInput.tsx export function SearchInput({ value, onChange }) { return ( onChange(e.target.value)} className="border p-2" /> ); } // ui/Button.tsx export function Button({ children, onClick }) { return ( ); } ``` ### ❌ Wrong Architecture ```typescript // app/dashboard/page.tsx export default function DashboardPage() { const [search, setSearch] = useState(''); // ❌ State in page return (
{/* ❌ Raw HTML */} setSearch(e.target.value)} // ❌ State logic />
); } ``` --- ## Benefits 1. **Reusability**: UI elements can be used anywhere 2. **Testability**: Pure functions are easy to test 3. **Maintainability**: Clear separation of concerns 4. **Performance**: No unnecessary re-renders 5. **Type Safety**: Each layer has clear contracts --- ## Migration Guide If you have existing code that violates these rules: 1. **Extract UI elements** from app/ to ui/ 2. **Move stateful logic** from ui/ to components/ 3. **Remove Next.js imports** from components/ui (pass callbacks from pages) 4. **Use hooks/** for shared logic **Example migration**: ```typescript // Before // app/page.tsx export default function Page() { return
...
; } // After // app/page.tsx export default function Page() { return ; } // components/HomePage.tsx export function HomePage() { return ( ); } // ui/PageContainer.tsx export function PageContainer({ children }) { return
{children}
; } ``` --- ## Summary | Layer | State | Next.js | HTML | Purpose | |-------|-------|---------|------|---------| | **app/** | ❌ No | ✅ Yes | ❌ No | Pages & layouts | | **components/** | ✅ Yes | ❌ No | ❌ No | App components | | **ui/** | ❌ No | ❌ No | ✅ Yes | Pure elements | | **hooks/** | ✅ Yes | ❌ No | ❌ No | Shared logic | **Golden Rule**: Each layer should only depend on layers below it.