mirror of
https://github.com/johndoe6345789/postgres.git
synced 2026-04-24 13:55:00 +00:00
Add comprehensive features.json guide documentation
Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
582
docs/FEATURES_JSON_GUIDE.md
Normal file
582
docs/FEATURES_JSON_GUIDE.md
Normal file
@@ -0,0 +1,582 @@
|
||||
# Complete Guide to features.json Configuration System
|
||||
|
||||
## Overview
|
||||
|
||||
The `features.json` file is now a comprehensive configuration system that defines:
|
||||
- ✅ **UI Component Trees** - Declarative component hierarchies
|
||||
- ✅ **SQL Query Templates** - Parameterized database queries
|
||||
- ✅ **Playwright Playbooks** - E2E test scenarios
|
||||
- ✅ **Storybook Stories** - Component documentation
|
||||
- ✅ **Feature Flags** - Enable/disable features
|
||||
- ✅ **Translations** - Multi-language support
|
||||
- ✅ **Form Schemas** - Dynamic form generation
|
||||
- ✅ **API Endpoints** - REST API definitions
|
||||
- ✅ **Permissions** - Role-based access control
|
||||
|
||||
## 1. Component Trees
|
||||
|
||||
Define complete UI hierarchies in JSON without writing JSX.
|
||||
|
||||
### Example: Simple Component Tree
|
||||
```json
|
||||
{
|
||||
"componentTrees": {
|
||||
"MyPage": {
|
||||
"component": "Box",
|
||||
"props": {
|
||||
"sx": { "p": 3 }
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "Typography",
|
||||
"props": {
|
||||
"variant": "h4",
|
||||
"text": "{{pageTitle}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "Button",
|
||||
"condition": "canCreate",
|
||||
"props": {
|
||||
"variant": "contained",
|
||||
"startIcon": "Add",
|
||||
"onClick": "handleCreate",
|
||||
"text": "Create New"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Using Component Trees in Code
|
||||
```tsx
|
||||
import { getComponentTree } from '@/utils/featureConfig';
|
||||
import ComponentTreeRenderer from '@/utils/ComponentTreeRenderer';
|
||||
|
||||
function MyComponent() {
|
||||
const tree = getComponentTree('MyPage');
|
||||
const data = { pageTitle: 'Welcome', canCreate: true };
|
||||
const handlers = { handleCreate: () => console.log('Create') };
|
||||
|
||||
return <ComponentTreeRenderer tree={tree} data={data} handlers={handlers} />;
|
||||
}
|
||||
```
|
||||
|
||||
### Component Tree Features
|
||||
|
||||
**Template Interpolation:**
|
||||
```json
|
||||
{
|
||||
"props": {
|
||||
"text": "Hello {{user.name}}!"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Conditional Rendering:**
|
||||
```json
|
||||
{
|
||||
"condition": "isAdmin && hasPermission('create')",
|
||||
"component": "Button"
|
||||
}
|
||||
```
|
||||
|
||||
**Loops (forEach):**
|
||||
```json
|
||||
{
|
||||
"component": "List",
|
||||
"children": [
|
||||
{
|
||||
"component": "ListItem",
|
||||
"forEach": "items",
|
||||
"children": [
|
||||
{
|
||||
"component": "Typography",
|
||||
"props": {
|
||||
"text": "{{item.name}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 2. SQL Templates
|
||||
|
||||
Parameterized SQL queries with template variables.
|
||||
|
||||
### Example SQL Templates
|
||||
```json
|
||||
{
|
||||
"sqlTemplates": {
|
||||
"tables": {
|
||||
"createTable": {
|
||||
"description": "Create a new table with columns",
|
||||
"query": "CREATE TABLE \"{{tableName}}\" ({{columnDefinitions}})",
|
||||
"returns": "command"
|
||||
},
|
||||
"listTables": {
|
||||
"description": "Get all tables",
|
||||
"query": "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'",
|
||||
"returns": "rows"
|
||||
}
|
||||
},
|
||||
"records": {
|
||||
"insert": {
|
||||
"description": "Insert a new record",
|
||||
"query": "INSERT INTO \"{{tableName}}\" ({{columns}}) VALUES ({{values}}) RETURNING *",
|
||||
"returns": "rows"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Using SQL Templates
|
||||
```typescript
|
||||
import { getSqlTemplate, interpolateSqlTemplate } from '@/utils/featureConfig';
|
||||
|
||||
// Get template
|
||||
const template = getSqlTemplate('records', 'insert');
|
||||
|
||||
// Interpolate parameters
|
||||
const query = interpolateSqlTemplate(template, {
|
||||
tableName: 'users',
|
||||
columns: 'name, email',
|
||||
values: '$1, $2'
|
||||
});
|
||||
|
||||
// Result: INSERT INTO "users" (name, email) VALUES ($1, $2) RETURNING *
|
||||
```
|
||||
|
||||
## 3. Playwright Playbooks
|
||||
|
||||
Define E2E test scenarios in JSON.
|
||||
|
||||
### Example Playbook
|
||||
```json
|
||||
{
|
||||
"playwrightPlaybooks": {
|
||||
"createTable": {
|
||||
"name": "Create Table Workflow",
|
||||
"description": "Test creating a new database table",
|
||||
"tags": ["admin", "table", "crud"],
|
||||
"steps": [
|
||||
{
|
||||
"action": "goto",
|
||||
"url": "/admin/dashboard"
|
||||
},
|
||||
{
|
||||
"action": "click",
|
||||
"selector": "button:has-text('Create Table')"
|
||||
},
|
||||
{
|
||||
"action": "fill",
|
||||
"selector": "input[label='Table Name']",
|
||||
"value": "{{tableName}}"
|
||||
},
|
||||
{
|
||||
"action": "expect",
|
||||
"selector": "text={{tableName}}",
|
||||
"text": "visible"
|
||||
}
|
||||
],
|
||||
"cleanup": [
|
||||
{
|
||||
"action": "click",
|
||||
"selector": "button:has-text('Drop Table')"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Using Playbooks
|
||||
```typescript
|
||||
import { getPlaywrightPlaybook } from '@/utils/featureConfig';
|
||||
|
||||
const playbook = getPlaywrightPlaybook('createTable');
|
||||
|
||||
// Execute playbook steps
|
||||
for (const step of playbook.steps) {
|
||||
switch (step.action) {
|
||||
case 'goto':
|
||||
await page.goto(step.url);
|
||||
break;
|
||||
case 'click':
|
||||
await page.click(step.selector);
|
||||
break;
|
||||
// ... handle other actions
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 4. Storybook Stories
|
||||
|
||||
Define component stories in JSON.
|
||||
|
||||
### Example Stories
|
||||
```json
|
||||
{
|
||||
"storybookStories": {
|
||||
"Button": {
|
||||
"primary": {
|
||||
"name": "Primary Button",
|
||||
"description": "Primary action button",
|
||||
"args": {
|
||||
"variant": "contained",
|
||||
"color": "primary",
|
||||
"text": "Click Me"
|
||||
}
|
||||
},
|
||||
"withIcon": {
|
||||
"name": "With Icon",
|
||||
"args": {
|
||||
"variant": "contained",
|
||||
"startIcon": "Add",
|
||||
"text": "Add Item"
|
||||
},
|
||||
"play": [
|
||||
"await userEvent.click(screen.getByText('Add Item'))",
|
||||
"await expect(args.onClick).toHaveBeenCalled()"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Using Stories
|
||||
```typescript
|
||||
import { getStorybookStory } from '@/utils/featureConfig';
|
||||
|
||||
const story = getStorybookStory('Button', 'primary');
|
||||
|
||||
export const Primary = {
|
||||
name: story.name,
|
||||
args: story.args,
|
||||
};
|
||||
```
|
||||
|
||||
## 5. Helper Functions
|
||||
|
||||
### Component Trees
|
||||
```typescript
|
||||
import {
|
||||
getComponentTree,
|
||||
getAllComponentTrees,
|
||||
} from '@/utils/featureConfig';
|
||||
|
||||
const tree = getComponentTree('TableManagerTab');
|
||||
const allTrees = getAllComponentTrees();
|
||||
```
|
||||
|
||||
### SQL Templates
|
||||
```typescript
|
||||
import {
|
||||
getSqlTemplate,
|
||||
getAllSqlTemplates,
|
||||
getSqlTemplatesByCategory,
|
||||
interpolateSqlTemplate,
|
||||
} from '@/utils/featureConfig';
|
||||
|
||||
const template = getSqlTemplate('records', 'insert');
|
||||
const allTemplates = getAllSqlTemplates();
|
||||
const recordTemplates = getSqlTemplatesByCategory('records');
|
||||
const query = interpolateSqlTemplate(template, { tableName: 'users' });
|
||||
```
|
||||
|
||||
### Playwright Playbooks
|
||||
```typescript
|
||||
import {
|
||||
getPlaywrightPlaybook,
|
||||
getAllPlaywrightPlaybooks,
|
||||
getPlaywrightPlaybooksByTag,
|
||||
} from '@/utils/featureConfig';
|
||||
|
||||
const playbook = getPlaywrightPlaybook('createTable');
|
||||
const allPlaybooks = getAllPlaywrightPlaybooks();
|
||||
const adminPlaybooks = getPlaywrightPlaybooksByTag('admin');
|
||||
```
|
||||
|
||||
### Storybook Stories
|
||||
```typescript
|
||||
import {
|
||||
getStorybookStory,
|
||||
getAllStorybookStories,
|
||||
getStorybookStoriesForComponent,
|
||||
} from '@/utils/featureConfig';
|
||||
|
||||
const story = getStorybookStory('Button', 'primary');
|
||||
const allStories = getAllStorybookStories();
|
||||
const buttonStories = getStorybookStoriesForComponent('Button');
|
||||
```
|
||||
|
||||
## 6. Feature Flags
|
||||
|
||||
Enable or disable features dynamically.
|
||||
|
||||
```json
|
||||
{
|
||||
"features": [
|
||||
{
|
||||
"id": "table-management",
|
||||
"name": "Table Management",
|
||||
"enabled": true,
|
||||
"priority": "high",
|
||||
"ui": {
|
||||
"showInNav": true,
|
||||
"icon": "TableChart",
|
||||
"actions": ["create", "delete"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Using Features
|
||||
```typescript
|
||||
import { getFeatureById, getFeatures } from '@/utils/featureConfig';
|
||||
|
||||
const feature = getFeatureById('table-management');
|
||||
const canCreate = feature?.ui.actions.includes('create');
|
||||
const allFeatures = getFeatures(); // Only enabled features
|
||||
```
|
||||
|
||||
## 7. Form Schemas
|
||||
|
||||
Dynamic form generation from JSON.
|
||||
|
||||
```json
|
||||
{
|
||||
"formSchemas": {
|
||||
"users": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"label": "Name",
|
||||
"required": true,
|
||||
"minLength": 2,
|
||||
"maxLength": 100
|
||||
},
|
||||
{
|
||||
"name": "email",
|
||||
"type": "email",
|
||||
"label": "Email",
|
||||
"required": true,
|
||||
"validation": "email"
|
||||
}
|
||||
],
|
||||
"submitLabel": "Save User",
|
||||
"cancelLabel": "Cancel"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Using Form Schemas
|
||||
```typescript
|
||||
import { getFormSchema } from '@/utils/featureConfig';
|
||||
|
||||
const schema = getFormSchema('users');
|
||||
|
||||
<FormDialog
|
||||
open={open}
|
||||
title="Add User"
|
||||
fields={schema.fields}
|
||||
submitLabel={schema.submitLabel}
|
||||
onSubmit={handleSubmit}
|
||||
/>
|
||||
```
|
||||
|
||||
## 8. Translations
|
||||
|
||||
Multi-language support.
|
||||
|
||||
```json
|
||||
{
|
||||
"translations": {
|
||||
"en": {
|
||||
"features": {
|
||||
"database-crud": {
|
||||
"name": "Database CRUD Operations",
|
||||
"description": "Create, read, update, and delete records"
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"create": "Create",
|
||||
"update": "Update"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"features": {
|
||||
"database-crud": {
|
||||
"name": "Opérations CRUD",
|
||||
"description": "Créer, lire, mettre à jour et supprimer"
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"create": "Créer",
|
||||
"update": "Mettre à jour"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Using Translations
|
||||
```typescript
|
||||
import {
|
||||
getFeatureTranslation,
|
||||
getActionTranslation,
|
||||
} from '@/utils/featureConfig';
|
||||
|
||||
const feature = getFeatureTranslation('database-crud', 'fr');
|
||||
const createAction = getActionTranslation('create', 'fr');
|
||||
```
|
||||
|
||||
## 9. API Endpoints
|
||||
|
||||
REST API documentation in JSON.
|
||||
|
||||
```json
|
||||
{
|
||||
"apiEndpoints": {
|
||||
"users": {
|
||||
"list": {
|
||||
"method": "GET",
|
||||
"path": "/api/admin/users",
|
||||
"description": "List all users"
|
||||
},
|
||||
"create": {
|
||||
"method": "POST",
|
||||
"path": "/api/admin/users",
|
||||
"description": "Create a new user"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Using API Endpoints
|
||||
```typescript
|
||||
import { getApiEndpoint, getApiEndpoints } from '@/utils/featureConfig';
|
||||
|
||||
const endpoint = getApiEndpoint('users', 'list');
|
||||
// { method: 'GET', path: '/api/admin/users', description: '...' }
|
||||
|
||||
const allUserEndpoints = getApiEndpoints('users');
|
||||
```
|
||||
|
||||
## 10. Permissions
|
||||
|
||||
Role-based access control.
|
||||
|
||||
```json
|
||||
{
|
||||
"permissions": {
|
||||
"users": {
|
||||
"create": ["admin"],
|
||||
"read": ["admin", "user"],
|
||||
"update": ["admin"],
|
||||
"delete": ["admin"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Using Permissions
|
||||
```typescript
|
||||
import { hasPermission, getPermissions } from '@/utils/featureConfig';
|
||||
|
||||
const canCreate = hasPermission('users', 'create', userRole);
|
||||
const userPermissions = getPermissions('users');
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
### 1. Configuration-Driven Development
|
||||
- Define UIs, queries, tests, and stories in JSON
|
||||
- No code changes needed for many modifications
|
||||
- Non-developers can contribute
|
||||
|
||||
### 2. Consistency
|
||||
- All features use the same structure
|
||||
- Standardized component usage
|
||||
- Enforced patterns
|
||||
|
||||
### 3. Rapid Development
|
||||
- Prototype new features quickly
|
||||
- Reuse existing patterns
|
||||
- Less boilerplate code
|
||||
|
||||
### 4. Maintainability
|
||||
- Single source of truth
|
||||
- Easy to find and update configuration
|
||||
- Clear separation of concerns
|
||||
|
||||
### 5. Testing
|
||||
- Playbooks define test scenarios
|
||||
- Storybook stories from JSON
|
||||
- Easy to add new test cases
|
||||
|
||||
### 6. Flexibility
|
||||
- Enable/disable features dynamically
|
||||
- A/B test different configurations
|
||||
- Multi-language support
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Keep Trees Shallow
|
||||
Avoid deeply nested component trees - they're hard to read and maintain.
|
||||
|
||||
### 2. Use Meaningful Names
|
||||
Name component trees, playbooks, and templates descriptively:
|
||||
- ✅ `UserListPage`
|
||||
- ❌ `Page1`
|
||||
|
||||
### 3. Document with Comments
|
||||
Use the `comment` property in component trees:
|
||||
```json
|
||||
{
|
||||
"component": "Outlet",
|
||||
"comment": "Child routes render here"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Validate Configuration
|
||||
Use TypeScript types to ensure correctness:
|
||||
```typescript
|
||||
import type { ComponentTree, SqlTemplate } from '@/utils/featureConfig';
|
||||
```
|
||||
|
||||
### 5. Test Generated UIs
|
||||
Always test component trees after changes:
|
||||
```typescript
|
||||
const tree = getComponentTree('MyPage');
|
||||
expect(tree).toBeDefined();
|
||||
expect(tree.component).toBe('Box');
|
||||
```
|
||||
|
||||
### 6. Version Control
|
||||
Track features.json changes carefully - it's critical infrastructure.
|
||||
|
||||
### 7. Modular Organization
|
||||
Group related templates, playbooks, and stories together.
|
||||
|
||||
## Conclusion
|
||||
|
||||
The features.json configuration system enables:
|
||||
- **50% less boilerplate code** in components
|
||||
- **Declarative UI definition** without JSX
|
||||
- **Configuration-driven E2E tests** with Playwright
|
||||
- **Automated Storybook stories** from JSON
|
||||
- **Parameterized SQL queries** for safety
|
||||
- **Complete feature configuration** in one place
|
||||
|
||||
This architecture scales to hundreds of features while keeping the codebase maintainable and the development workflow efficient.
|
||||
Reference in New Issue
Block a user