name: frontend-dev description: Coding practices for frontend development in Atomic CRM. Use when creating or modifying React components, forms, list pages, detail views, filters, data fetching, or responsive layouts.
The frontend uses ra-core (react-admin headless) for data fetching, routing, and CRUD logic, with shadcn-admin-kit and shadcn/ui for the UI layer.
Component architecture
- Import form inputs (
TextInput,SelectInput,ReferenceInput, etc.) from@/components/admin/, not from shadcn/ui directly. The admin layer wraps shadcn with ra-core integration (labels, validation, data binding). - Import pure UI components (
Card,Button,Badge,Sheet, etc.) from@/components/ui/. - Domain configuration (deal stages, note statuses, task types, company sectors) comes from
useConfigurationContext(), never hardcoded.
Resource (CRUD) conventions
Each resource follows this file structure (e.g. contacts/):
ContactList.tsx— list page (desktop + mobile variants)ContactShow.tsx— detail viewContactEdit.tsx/ContactCreate.tsx— form pagesContactInputs.tsx— shared form fields reused between create and editindex.tsx— exports{ list, show, edit, create, recordRepresentation }
Resources are registered in root/CRM.tsx via <Resource name="contacts" {...contacts} />.
Data fetching
- For standard CRUD, use ra-core hooks:
useListContext(),useShowContext(),useGetList(),useGetOne(),useGetIdentity(). - When a query or mutation isn't covered by ra-core hooks, add a custom dataProvider method and call it via
useQuery/useMutationwithuseDataProvider<CrmDataProvider>()(e.g.dataProvider.getActivityLog()inActivityLog.tsx,dataProvider.salesCreate()inSalesCreate.tsx).
Forms
- Forms use
Formfrom ra-core +FormToolbarfor submit/cancel actions. - Ra-core's
Formuses React Hook Form under the hood. UseuseFormContext()for imperative operations (setValue,reset,getValues). - Top-level resource forms use full-page
CreateBase/EditBasewithCard(e.g. contacts), orDialog(e.g. deals). - On mobile, inline/sub-resource forms use
CreateSheet/EditSheetfrommisc/(e.g. notes, tasks). - Split form fields into semantic sub-components (e.g.
ContactIdentityInputs,ContactPositionInputs).
Filters
- Use
ToggleFilterButton/ActiveFilterButtoncomponents for filter UI. - Filters apply immediately, no "apply" button.
Responsive design
- Major pages have desktop and mobile variants. Use
useIsMobile()to branch. - Desktop: 2-column grid layouts. Mobile: single column with
MobileHeader/MobileContent. - Mobile lists use
InfiniteListBasefor scroll pagination.