Files
low-code-react-app-b/docs/architecture/CONFIG_ARCHITECTURE.md
2026-01-17 00:33:02 +00:00

437 lines
16 KiB
Markdown

# Declarative Page Configuration System
## Overview
CodeForge uses a **declarative, JSON-driven configuration system** to manage pages, components, props, and layouts. This architecture enables rapid development without modifying core application logic.
## Architecture Diagram
```
┌─────────────────────────────────────────────────────────────┐
│ App.tsx │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Uses page-loader to: │ │
│ │ • Get enabled pages │ │
│ │ • Resolve component props dynamically │ │
│ │ • Render pages with correct configuration │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│ imports & uses
┌─────────────────────────────────────────────────────────────┐
│ page-loader.ts (Resolution Logic) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ • getPageConfig() │ │
│ │ • getEnabledPages(featureToggles) │ │
│ │ • resolveProps(propConfig, state, actions) │ │
│ │ • getPageShortcuts() │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│ reads
┌─────────────────────────────────────────────────────────────┐
│ pages.json (Declarative Config) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ { │ │
│ │ "pages": [ │ │
│ │ { │ │
│ │ "id": "models", │ │
│ │ "component": "ModelDesigner", │ │
│ │ "props": { │ │
│ │ "state": ["models"], │ │
│ │ "actions": ["onModelsChange:setModels"] │ │
│ │ } │ │
│ │ } │ │
│ │ ] │ │
│ │ } │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│ validates
┌─────────────────────────────────────────────────────────────┐
│ validate-config.ts (Validation Logic) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ • validatePageConfig() │ │
│ │ • Checks for duplicate IDs/shortcuts │ │
│ │ • Validates state/action keys exist │ │
│ │ • Validates resizable configurations │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│ uses schemas
┌─────────────────────────────────────────────────────────────┐
│ page-schema.ts (Type Definitions) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ • PropConfigSchema │ │
│ │ • ResizableConfigSchema │ │
│ │ • SimplePageConfigSchema │ │
│ │ • Zod schemas for runtime validation │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
## Core Files
### 1. `pages.json` - Source of Truth
The declarative configuration file that defines all pages, their components, and props.
**Location**: `/src/config/pages.json`
**Purpose**:
- Define all application pages
- Configure component props mapping
- Set keyboard shortcuts
- Configure resizable layouts
- Enable/disable features
### 2. `page-loader.ts` - Resolution Engine
The TypeScript module that reads and processes the JSON configuration.
**Location**: `/src/config/page-loader.ts`
**Key Functions**:
- `getPageConfig()` - Returns full page configuration
- `getEnabledPages(featureToggles)` - Filters pages based on toggles
- `resolveProps(propConfig, stateContext, actionContext)` - Maps JSON config to actual props
- `getPageShortcuts(featureToggles)` - Extracts keyboard shortcuts
### 3. `validate-config.ts` - Configuration Validator
Validates the pages.json configuration for errors and warnings.
**Location**: `/src/config/validate-config.ts`
**Validates**:
- Required fields (id, title, component)
- Duplicate IDs, shortcuts, or order numbers
- Valid state and action keys
- Resizable configuration correctness
- Feature toggle key validity
### 4. `page-schema.ts` - Type Definitions
Zod schemas and TypeScript types for type-safe configuration.
**Location**: `/src/config/page-schema.ts`
**Exports**:
- `PropConfigSchema` - Props configuration structure
- `ResizableConfigSchema` - Resizable layout structure
- `SimplePageConfigSchema` - Individual page structure
- TypeScript types inferred from schemas
## Data Flow
### Adding a New Page
```mermaid
graph LR
A[Edit pages.json] --> B[Add page config with props]
B --> C[page-loader reads config]
C --> D[App.tsx calls resolveProps]
D --> E[Props mapped from state/actions]
E --> F[Component rendered with props]
```
### Prop Resolution Flow
```
1. Component needs props
2. App.tsx calls getPropsForComponent(pageId)
3. getPropsForComponent finds page config
4. Calls resolveProps(page.props, stateContext, actionContext)
5. resolveProps iterates over state/action arrays
6. Maps JSON keys to actual values from contexts
7. Returns resolved props object
8. Props passed to component
```
## Configuration Examples
### Simple Page (Dashboard)
```json
{
"id": "dashboard",
"title": "Dashboard",
"icon": "ChartBar",
"component": "ProjectDashboard",
"enabled": true,
"shortcut": "ctrl+1",
"order": 1,
"props": {
"state": ["files", "models", "components"]
}
}
```
### Page with Actions (Model Designer)
```json
{
"id": "models",
"title": "Models",
"component": "ModelDesigner",
"props": {
"state": ["models"],
"actions": ["onModelsChange:setModels"]
}
}
```
### Page with Renamed Props (Flask Designer)
```json
{
"id": "flask",
"component": "FlaskDesigner",
"props": {
"state": ["config:flaskConfig"],
"actions": ["onConfigChange:setFlaskConfig"]
}
}
```
### Resizable Split-Panel Page (Code Editor)
```json
{
"id": "code",
"component": "CodeEditor",
"requiresResizable": true,
"props": {
"state": ["files", "activeFileId"],
"actions": ["onFileChange:handleFileChange"]
},
"resizableConfig": {
"leftComponent": "FileExplorer",
"leftProps": {
"state": ["files"],
"actions": ["onFileSelect:setActiveFileId"]
},
"leftPanel": {
"defaultSize": 20,
"minSize": 15,
"maxSize": 30
},
"rightPanel": {
"defaultSize": 80
}
}
}
```
## State Context Keys
Available state variables that can be referenced in `props.state`:
- `files` - Project files
- `models` - Data models
- `components` - Component definitions
- `componentTrees` - Component tree structures
- `workflows` - Workflow definitions
- `lambdas` - Lambda functions
- `theme` - Theme configuration
- `playwrightTests` - Playwright tests
- `storybookStories` - Storybook stories
- `unitTests` - Unit tests
- `flaskConfig` - Flask configuration
- `nextjsConfig` - Next.js configuration
- `npmSettings` - NPM settings
- `featureToggles` - Feature toggles
- `activeFileId` - Active file ID
## Action Context Keys
Available action functions that can be referenced in `props.actions`:
- `handleFileChange` - Update file content
- `setActiveFileId` - Set active file
- `handleFileClose` - Close file
- `handleFileAdd` - Add new file
- `setModels` - Update models
- `setComponents` - Update components
- `setComponentTrees` - Update component trees
- `setWorkflows` - Update workflows
- `setLambdas` - Update lambdas
- `setTheme` - Update theme
- `setPlaywrightTests` - Update Playwright tests
- `setStorybookStories` - Update Storybook stories
- `setUnitTests` - Update unit tests
- `setFlaskConfig` - Update Flask config
- `setNextjsConfig` - Update Next.js config
- `setNpmSettings` - Update NPM settings
- `setFeatureToggles` - Update feature toggles
## Benefits of This Architecture
### 1. **Declarative Configuration**
- All pages defined in one place
- Easy to understand at a glance
- No need to read through TypeScript code
### 2. **Separation of Concerns**
- Configuration separate from logic
- Props resolution handled systematically
- Business logic stays in components
### 3. **Type Safety**
- Zod schemas validate runtime data
- TypeScript types ensure compile-time safety
- Catch errors early in development
### 4. **Maintainability**
- Add pages without touching App.tsx logic
- Modify props without code changes
- Clear validation error messages
### 5. **Scalability**
- Easy to add new pages
- Simple to extend prop mappings
- Can add more configuration options
### 6. **Testability**
- Validate configuration independently
- Test prop resolution in isolation
- Mock configurations for testing
## Validation
Run configuration validation:
```bash
# Via TypeScript (if configured)
npm run validate-config
# Or manually import and run
import { validatePageConfig, printValidationErrors } from '@/config/validate-config'
const errors = validatePageConfig()
printValidationErrors(errors)
```
Validation checks:
- ✅ Required fields present
- ✅ No duplicate IDs or shortcuts
- ✅ Valid state/action keys
- ✅ Correct resizable config format
- ✅ Panel sizes sum to 100
- ⚠️ Warnings for missing icons or duplicate orders
## Extending the System
### Adding New State Keys
1. Add state to `useProjectState` hook
2. Add to `stateContext` in `App.tsx`
3. Add to validation in `validate-config.ts`
4. Document in this README
### Adding New Action Keys
1. Create action function in `App.tsx` or hook
2. Add to `actionContext` in `App.tsx`
3. Add to validation in `validate-config.ts`
4. Document in this README
### Adding New Configuration Options
1. Update `pages.json` with new field
2. Update `PageConfig` interface in `page-loader.ts`
3. Update Zod schema in `page-schema.ts`
4. Add validation in `validate-config.ts`
5. Implement logic in `App.tsx`
## Migration Guide
### From Hardcoded Props to JSON Config
**Before** (Hardcoded in App.tsx):
```typescript
const getPropsForComponent = (pageId: string) => {
const propsMap: Record<string, any> = {
'ModelDesigner': {
models,
onModelsChange: setModels,
},
}
return propsMap[pageId] || {}
}
```
**After** (Declarative in pages.json):
```json
{
"id": "models",
"component": "ModelDesigner",
"props": {
"state": ["models"],
"actions": ["onModelsChange:setModels"]
}
}
```
## Best Practices
1. **Keep props minimal** - Only pass what the component needs
2. **Use descriptive prop names** - Clear intent over brevity
3. **Validate configurations** - Run validation before deployment
4. **Document new features** - Update this README when extending
5. **Consistent naming** - Follow existing patterns for state/actions
6. **Group related props** - Keep state and actions organized
## Troubleshooting
### Props not reaching component?
- Check state/action key spelling in pages.json
- Verify key exists in stateContext/actionContext
- Run validation to catch errors
### Component not rendering?
- Ensure component added to componentMap in App.tsx
- Check component name matches exactly (case-sensitive)
- Verify component has default export
### Resizable panel issues?
- Ensure defaultSize values sum to 100
- Check leftComponent exists in componentMap
- Verify resizableConfig structure is complete
## Related Documentation
- [PROPS_CONFIG_GUIDE.md](./PROPS_CONFIG_GUIDE.md) - Detailed props configuration guide
- [src/config/pages.json](./src/config/pages.json) - Current page configurations
- [src/config/page-loader.ts](./src/config/page-loader.ts) - Resolution logic
- [src/config/validate-config.ts](./src/config/validate-config.ts) - Validation utilities
## Future Enhancements
Potential improvements to the configuration system:
- [ ] Hot-reload configuration changes in development
- [ ] Visual configuration editor UI
- [ ] Import/export page configurations
- [ ] Configuration presets/templates
- [ ] Computed/derived props from state
- [ ] Conditional prop mappings
- [ ] Hook injection via configuration
- [ ] Layout templates beyond resizable panels
- [ ] Permission-based page visibility
- [ ] Analytics tracking configuration