---
description: Frontend folder structure — ui vs non-ui, thin pages, feature layout
globs: frontend/src/**
alwaysApply: false
---
# Frontend component structure
## Rules
| Kind | Location |
|------|----------|
| Cross-feature UI | `components/ui/shared/` |
| Feature UI | `components/ui/{feature}/` |
| Cross-feature non-UI | `components/shared/` |
| Feature non-UI | `components/{feature}/` |
| Route logic | `components/ui/{feature}/{Feature}Page.tsx` |
| App routes | `app/**/page.tsx` — **thin wrapper only** |
## Thin page pattern
```tsx
'use client';
import { PatientsPage } from '@/components/ui/patient/PatientsPage';
export default function Page() {
return ;
}
```
Reference: `app/.../treatment/page.tsx` + `components/ui/treatment/TreatmentWorkspace.tsx`.
## Do not
- Put React components (`.tsx` with JSX) in `components/` outside `ui/`.
- Put pure helpers (`.ts`, no JSX) inside `components/ui/`.
- Put business logic, API calls, or large forms directly in `app/**/page.tsx`.
## API & errors
- API clients: `lib/api/`.
- Catch blocks: `getUserFacingError(err, tErrors, fallback)` from `components/shared/formatApiError.ts`.
## Toasts
- Use `useToast()` for transient page feedback — rendered globally by `ToastProvider` in dashboard layout (fixed bottom, above dialogs).
- Do **not** add `` inside pages or dialogs.
- Form/dialog validation: inline error text near the field or submit button, not a toast.
## When adding UI
1. Check `components/ui/shared/` for an existing primitive.
2. Check the feature's `ui/{feature}/` folder for an existing pattern.
3. Add i18n keys to en, fa, and nl.