4.4 KiB
Frontend Architecture
Frontend stack:
- React
- TypeScript
- Vite
- React Admin
- shadcn/ui
- Keycloak JS
The frontend is generated from the DSL and API specification.
Each entity becomes a React Admin resource.
The generated frontend must also include Keycloak authentication by default.
Project Structure
client/ src/
App.tsx
main.tsx
dataProvider.ts
auth/
keycloak.ts
authProvider.ts
config/
env.ts
resources/
{entity}/
{entity}List.tsx
{entity}Create.tsx
{entity}Edit.tsx
{entity}Show.tsx
Resource Registration
Each resource must be registered in App.tsx.
The generated App.tsx must register:
dataProviderauthProvider
The generated Admin root must enforce authenticated operation. The generated frontend must not operate anonymously once auth is enabled.
Example:
Data Provider
React Admin uses a generated shared REST-compatible data provider.
API format must follow:
GET /resource GET /resource/:id POST /resource PATCH /resource/:id DELETE /resource/:id
List response format:
{ data: [], total: number }
The generated dataProvider.ts must remain the single shared request seam for backend API calls.
Rules:
- Use an env-driven API base URL.
- Attach
Authorization: Bearer <access_token>in this shared seam. - Cover all React Admin operations, including references and bulk fetches.
- Do not scatter auth headers across resource components.
Application Bootstrap
The generated main.tsx must initialize Keycloak before rendering the SPA.
Rules:
- Use redirect-based Keycloak login only.
- Use Authorization Code + PKCE (
S256). - Do not generate a custom in-app username/password login form.
- Do not render the authenticated admin app before Keycloak initialization completes.
Config
The generated frontend must include a dedicated config module in src/config/.
Required env variables:
VITE_API_URLVITE_KEYCLOAK_URLVITE_KEYCLOAK_REALMVITE_KEYCLOAK_CLIENT_ID
The generated frontend config must fail fast if required auth variables are missing. The generated frontend must not silently fall back to production auth settings in code.
Foreign Keys
Foreign keys must use ReferenceInput and ReferenceField.
Example:
Naming Conventions
React component naming
Components are named after the entity in PascalCase. One entity = one resource with four main views.
- List:
{Entity}List.tsx(e.g.EquipmentList.tsx,RepairOrderList.tsx) - Create:
{Entity}Create.tsx(e.g.EquipmentCreate.tsx) - Edit:
{Entity}Edit.tsx(e.g.EquipmentEdit.tsx) - Show:
{Entity}Show.tsx(e.g.EquipmentShow.tsx)
Examples:
- Equipment →
EquipmentList.tsx,EquipmentCreate.tsx,EquipmentEdit.tsx,EquipmentShow.tsx - EquipmentType →
EquipmentTypeList.tsx,EquipmentTypeCreate.tsx,EquipmentTypeEdit.tsx,EquipmentTypeShow.tsx - RepairOrder →
RepairOrderList.tsx,RepairOrderCreate.tsx,RepairOrderEdit.tsx,RepairOrderShow.tsx
Resource folder naming
Folder under resources/ uses kebab-case, matching the React Admin resource name:
resources/equipment/resources/equipment-type/resources/repair-order/
Resource Naming Rules
React Admin resource name (used in <Resource name="..." /> and in reference for ReferenceInput) must match the API resource path (no leading slash, same segment string).
- Entity → resource name: PascalCase entity name is converted to kebab-case and pluralized.
- Consistency with API: The resource name must be the same as the backend path segment so that the data provider calls the correct URL.
| Entity (DSL) | Resource name (React Admin) | API path |
|---|---|---|
| Equipment | equipment | /equipment |
| EquipmentType | equipment-types | /equipment-types |
| RepairOrder | repair-orders | /repair-orders |
Examples in App.tsx:
<Resource name="equipment" list={EquipmentList} create={EquipmentCreate} edit={EquipmentEdit} show={EquipmentShow} /><Resource name="equipment-types" list={EquipmentTypeList} ... /><Resource name="repair-orders" list={RepairOrderList} ... />