|
| 1 | +# React-Admin Agent Context |
| 2 | + |
| 3 | +React-admin is a comprehensive frontend framework for building B2B and admin applications on top of REST/GraphQL APIs, using TypeScript, React, and Material UI. It's an open-source project maintained by Marmelab that provides a complete solution for B2B applications with data-driven interfaces. |
| 4 | + |
| 5 | +## Architecture & Design Patterns |
| 6 | + |
| 7 | +### Key Principles |
| 8 | + |
| 9 | +- Designed for Single-Page Application (SPA) architecture |
| 10 | +- Provider-based abstraction for data fetching, auth, and i18n |
| 11 | +- "Batteries included but removable" - everything is replaceable |
| 12 | +- User Experience and Developer Experience are equally important |
| 13 | +- Backward compatibility prioritized over new features |
| 14 | +- Composition over Configuration - Use React patterns, not custom DSLs |
| 15 | +- Minimal API Surface - If it can be done in React, don't add to core |
| 16 | +- Standing on Giants' Shoulders - Use best-in-class libraries, don't reinvent the wheel |
| 17 | + |
| 18 | +### Provider Pattern |
| 19 | + |
| 20 | +React-admin uses adapters called "providers" for external integrations: |
| 21 | + |
| 22 | +```typescript |
| 23 | +// Data Provider - abstracts API calls |
| 24 | +dataProvider.getList('posts', { |
| 25 | + pagination: { page: 1, perPage: 5 }, |
| 26 | + sort: { field: 'title', order: 'ASC' }, |
| 27 | + filter: { author_id: 12 } |
| 28 | +}) |
| 29 | + |
| 30 | +// Auth Provider - handles authentication |
| 31 | +authProvider.checkAuth() |
| 32 | +authProvider.login({ username, password }) |
| 33 | +authProvider.getPermissions() |
| 34 | + |
| 35 | +// i18n Provider - manages translations |
| 36 | +i18nProvider.translate('ra.action.save') |
| 37 | +``` |
| 38 | + |
| 39 | +### Hook-Based API |
| 40 | + |
| 41 | +All functionality exposed through hooks following React patterns: |
| 42 | + |
| 43 | +```typescript |
| 44 | +// Data hooks |
| 45 | +const { data, isLoading } = useGetList('posts', { |
| 46 | + pagination: { page: 1, perPage: 10 } |
| 47 | +}); |
| 48 | + |
| 49 | +// State management hooks |
| 50 | +const [filters, setFilters] = useFilterState(); |
| 51 | +const [page, setPage] = usePaginationState(); |
| 52 | + |
| 53 | +// Auth hooks |
| 54 | +const { permissions } = usePermissions(); |
| 55 | +const canAccess = useCanAccess({ resource: 'posts', action: 'edit' }); |
| 56 | +``` |
| 57 | + |
| 58 | +### Headless Core |
| 59 | + |
| 60 | +The `ra-core` package contains all logic without UI. UI components are in separate packages like `ra-ui-materialui`. This allows: |
| 61 | + |
| 62 | +- Custom UIs using core hooks and controllers |
| 63 | +- Swapping UI libraries without changing core logic |
| 64 | + |
| 65 | +### Controller-View Separation |
| 66 | + |
| 67 | +- Controllers in `ra-core/src/controller/` handle business logic |
| 68 | +- Views in `ra-ui-materialui/src/` handle rendering |
| 69 | +- Controllers provide data and callbacks via hooks |
| 70 | + |
| 71 | +### Context: Pull, Don’t Push |
| 72 | + |
| 73 | +Communication between components can be challenging, especially in large React applications, where passing props down several levels can become cumbersome. React-admin addresses this issue using a pull model, where components expose props to their descendants via a context, and descendants can consume these props using custom hooks. |
| 74 | + |
| 75 | +Whenever a react-admin component fetches data or defines a callback, it creates a context and places the data and callback in it. |
| 76 | + |
| 77 | +## Codebase Organization |
| 78 | + |
| 79 | +### Monorepo Structure |
| 80 | + |
| 81 | +``` |
| 82 | +react-admin/ |
| 83 | +├── packages/ # Lerna-managed packages |
| 84 | +│ ├── ra-core/ # Core logic, hooks, controllers |
| 85 | +│ ├── ra-ui-materialui/ # Material UI components |
| 86 | +│ ├── react-admin/ # Main distribution package |
| 87 | +│ ├── ra-data-*/ # Data provider adapters |
| 88 | +│ ├── ra-i18n-*/ # i18n providers |
| 89 | +│ └── ra-language-*/ # Translation packages |
| 90 | +├── examples/ # Example applications |
| 91 | +│ ├── simple/ # E2E test app |
| 92 | +│ ├── demo/ # Full e-commerce demo |
| 93 | +│ ├── crm/ # CRM application |
| 94 | +│ └── tutorial/ # Tutorial app |
| 95 | +├── cypress/ # E2E test configuration |
| 96 | +├── docs/ # Jekyll documentation |
| 97 | +├── docs_headless/ # Astro + Starlight documentation for headless components |
| 98 | +└── scripts/ # Build scripts |
| 99 | +``` |
| 100 | + |
| 101 | +### Key ra-core Directories |
| 102 | + |
| 103 | +- `src/auth/` - Authentication and authorization (54 files) |
| 104 | +- `src/controller/` - CRUD controllers and state management |
| 105 | +- `src/dataProvider/` - Data fetching and caching logic (70 files) |
| 106 | +- `src/form/` - Form handling (31 files) |
| 107 | +- `src/routing/` - Navigation and routing (26 files) |
| 108 | +- `src/i18n/` - Internationalization (30 files) |
| 109 | + |
| 110 | +### Package Dependencies |
| 111 | + |
| 112 | +- **Core**: React 18.3+, TypeScript 5.8+, lodash 4.17+, inflection 3.0+ |
| 113 | +- **Routing**: React Router 6.28+ |
| 114 | +- **Data**: TanStack Query 5.90+ (React Query) |
| 115 | +- **Forms**: React Hook Form 7.53+ |
| 116 | +- **UI Components**: Material UI 5.16+ |
| 117 | +- **Testing**: Jest 29.5+, Testing Library, Storybook, Cypress |
| 118 | + |
| 119 | +## Development Practices |
| 120 | + |
| 121 | +### TypeScript Requirements |
| 122 | + |
| 123 | +- **Strict mode enabled** - no implicit any |
| 124 | +- **Complete type exports** - all public APIs must be typed |
| 125 | +- **Generic types** for flexibility in data providers and resources |
| 126 | +- **JSDoc comments** for better IDE support |
| 127 | + |
| 128 | +```typescript |
| 129 | +// GOOD - Properly typed with generics |
| 130 | +export const useGetOne = <RecordType extends RaRecord = any>( |
| 131 | + resource: string, |
| 132 | + options?: UseGetOneOptions<RecordType> |
| 133 | +): UseGetOneResult<RecordType> => { ... } |
| 134 | + |
| 135 | +// BAD - Using any without constraint |
| 136 | +export const useGetOne = (resource: any, options?: any): any => { ... } |
| 137 | +``` |
| 138 | + |
| 139 | +### Component Patterns |
| 140 | + |
| 141 | +1. **Composition over configuration** - Use React composition patterns |
| 142 | +2. **Smart defaults** - Components should work out-of-the-box |
| 143 | +3. **Controlled and uncontrolled** modes supported |
| 144 | +4. **Props pass-through** - Spread additional props to root element |
| 145 | + |
| 146 | +```jsx |
| 147 | +// Component composition example |
| 148 | +export const MyField = ({ source, ...props }) => { |
| 149 | + const record = useRecordContext(); |
| 150 | + return ( |
| 151 | + <TextField |
| 152 | + {...props} // Pass through all additional props |
| 153 | + value={record?.[source]} |
| 154 | + /> |
| 155 | + ); |
| 156 | +}; |
| 157 | +``` |
| 158 | +
|
| 159 | +### File Organization |
| 160 | +- **Feature-based structure** within packages (not type-based) |
| 161 | +- **Co-location** - Tests (`.spec.tsx`) and stories (`.stories.tsx`) next to components |
| 162 | +- **Index exports** - Each directory has an index.ts exporting public API |
| 163 | +- **Flat structure** within features - avoid unnecessary nesting |
| 164 | +
|
| 165 | +### Documentation |
| 166 | +
|
| 167 | +Every new feature or API change must be documented. The documentation consists of Markdown files located in the `/docs/` directory and built with Jekyll, one file per component or hook. |
| 168 | +
|
| 169 | +All documentation files must include: |
| 170 | +
|
| 171 | +- A brief description of the component or hook |
| 172 | +- Usage examples |
| 173 | +- List of props or parameters (required props first, then in alphabetical order) |
| 174 | +- Detailed usage for each prop/parameter (in alphabetical order) |
| 175 | +- Recipes and advanced usage examples if applicable |
| 176 | +
|
| 177 | +Headless hooks and components (the ones in `ra-core`) are also documented in the `/docs_headless/` directory. |
| 178 | +
|
| 179 | +### Pre-commit Hooks |
| 180 | +
|
| 181 | +- Automatic test execution for modified files |
| 182 | +- Prettier formatting check |
| 183 | +- ESLint validation |
| 184 | +- TypeScript compilation |
| 185 | +
|
| 186 | +
|
| 187 | +### Development Workflow |
| 188 | +```bash |
| 189 | +# Initial setup |
| 190 | +make install # Install all dependencies |
| 191 | + |
| 192 | +# After making changes |
| 193 | +make build # Build packages (TypeScript compilation) |
| 194 | +make test # run unit and e2e tests |
| 195 | + |
| 196 | +# Before pushing changes |
| 197 | +make lint # Check code quality |
| 198 | +make prettier # Format code |
| 199 | +``` |
| 200 | +
|
| 201 | +### Pull Request Process |
| 202 | +
|
| 203 | +1. **Target branch**: `next` for features, `master` for bug fixes or documentation changes |
| 204 | +2. **Required checks**: |
| 205 | + - All tests passing (`make test`) |
| 206 | + - Linting clean (`make lint`) |
| 207 | + - Prettier formatted (`make prettier`) |
| 208 | + - TypeScript compiles (`yarn typecheck`) |
| 209 | +
|
| 210 | +3. **Commit Messages**: Clear, descriptive messages focusing on "why" |
| 211 | + ``` |
| 212 | + fix: Prevent duplicate API calls in useGetList hook |
| 213 | + feat: Add support for custom row actions in Datagrid |
| 214 | + docs: Clarify dataProvider response format |
| 215 | + ``` |
| 216 | +
|
| 217 | +4. **Documentation**: Update relevant docs for API changes |
| 218 | +5. **Title**: Start with a verb (Add / Fix / Update / Remove), prefix with `[Doc]` or `[TypeScript]` if the change only concerns doc or types. |
| 219 | +
|
| 220 | +### Common Make Commands |
| 221 | +```bash |
| 222 | +make # Show all available commands |
| 223 | +make install # Install dependencies |
| 224 | +make build # Build all packages (CJS + ESM) |
| 225 | +make test # Run all tests |
| 226 | +make lint # Check code quality |
| 227 | +make prettier # Format code |
| 228 | +make run-simple # Run simple example |
| 229 | +make run-demo # Run demo application |
| 230 | +``` |
| 231 | +
|
| 232 | +### Performance Considerations |
| 233 | +
|
| 234 | +- Use `React.memo()` for expensive components |
| 235 | +- Leverage `useMemo()` and `useCallback()` appropriately |
| 236 | +- Use `useEvent()` (an internal hook) for memoized event handlers |
| 237 | +- Implement pagination for large datasets |
| 238 | +- Use query caching via React Query |
| 239 | +
|
| 240 | +### Accessibility |
| 241 | +
|
| 242 | +- Follow WCAG guidelines |
| 243 | +- Ensure keyboard navigation works |
| 244 | +- Provide proper ARIA labels |
| 245 | +- Test with screen readers |
| 246 | +
|
| 247 | +### Browser Support |
| 248 | +- Modern browsers only (Chrome, Firefox, Safari, Edge) |
| 249 | +- No IE11 support |
| 250 | +- ES5 compilation target for compatibility |
| 251 | +
|
| 252 | +## Misc |
| 253 | +
|
| 254 | +- **Don't use `React.cloneElement()`** - it breaks composition |
| 255 | +- **Don't inspect children** - violates React patterns (exception: Datagrid) |
| 256 | +- **Don't add comments** when code is self-explanatory |
| 257 | +- **Don't add features** achievable in a few lines with pure React |
| 258 | +- **Don't skip tests** - they run automatically on commit |
| 259 | +- **Don't force push** to main/master branches |
| 260 | +
|
| 261 | +## Testing Requirements |
| 262 | +
|
| 263 | +All developments must include tests to ensure code quality and prevent regressions. |
| 264 | +
|
| 265 | +### Storybook |
| 266 | +
|
| 267 | +- **Location**: Stories alongside components as `*.stories.tsx` |
| 268 | +- **Coverage**: All components must have stories demonstrating usage for all props |
| 269 | +- **Mocking**: Use jest mocks sparingly, prefer integration tests |
| 270 | +- **Data**: Use mock data providers (e.g., FakeRest) for stories. Make realistic data scenarios as the stories are also used for screenshots and visual testing. |
| 271 | +
|
| 272 | +### Unit & Integration Testing (Jest) |
| 273 | +
|
| 274 | +- **Location**: Tests alongside source files as `*.spec.tsx` |
| 275 | +- **Test Cases**: Reuse the component's stories as test cases |
| 276 | +- **Assertions**: Use testing-library to render and assert on elements. Don't test implementation details or HTML attributes, use assertions based on user interactions and visible output. |
| 277 | +- **Commands**: |
| 278 | + ```bash |
| 279 | + make test-unit # Run all unit and functional tests |
| 280 | + npx jest [pattern] # Run specific tests |
| 281 | + ``` |
| 282 | +
|
| 283 | +### E2E Testing (Cypress) |
| 284 | +
|
| 285 | +Kept minimal to critical user paths due to maintenance overhead. |
| 286 | +
|
| 287 | +- **Location**: `cypress/` directory |
| 288 | +- **Target**: Simple example app (`examples/simple/`) |
| 289 | +- **Coverage**: Critical user paths and interactions |
| 290 | +- **Commands**: |
| 291 | +
|
| 292 | + ```bash |
| 293 | + make test-e2e # Run in CI mode |
| 294 | + # or for local testing with GUI: |
| 295 | + make run-simple # Start test app with vite |
| 296 | + make test-e2e-local # Run e2e tests with GUI |
| 297 | + ``` |
| 298 | +
|
| 299 | +### Static Analysis |
| 300 | +
|
| 301 | +```bash |
| 302 | +make lint # ESLint checks |
| 303 | +make prettier # Prettier formatting |
| 304 | +make build # TypeScript type checking |
| 305 | +``` |
0 commit comments