Skip to main content

ADR-016: Configuration-Driven Entity UI

Status

Implemented

Date

2025-01-16 (Retrospective)

Decision Makers

  • Frontend Team - UI architecture
  • Architecture Team - Pattern standardization

Layer

Frontend

  • ADR-006: React 18 with Material-UI v7
  • ADR-015: Plugin System Architecture
  • ADR-003: Three-Tier Entity Hierarchy

Supersedes

None

Depends On

  • ADR-006: React 18 with Material-UI v7

Context

Managing 17 entity types requires consistent UI patterns:

  1. Code Duplication: Each entity page had similar but different code
  2. Inconsistency: Features varied between entity types
  3. Maintenance: Fixing bugs required changes in 17+ places
  4. Onboarding: New entities required significant development
  5. Feature Parity: Hard to ensure all entities had same capabilities

Requirements:

  • Single source of truth for entity behavior
  • Quick onboarding of new entities
  • Consistent UX across all entities
  • Type-safe configuration
  • Easy customization where needed

Decision

We implement configuration-driven entity UI with unified components:

Key Design Decisions

  1. Entity Configuration: JSON-like TypeScript config per entity
  2. Unified Components: EntityListPage, EntityDetailPage shared
  3. Feature Flags: Per-entity feature enablement
  4. Column Definitions: Declarative table columns
  5. Form Schemas: Declarative form fields

Entity Configuration Structure

interface EntityConfig {
name: string;
plural: string;
apiPath: string;
icon: React.ComponentType;

// Features
features: {
search: boolean;
bulkDelete: boolean;
export: boolean;
import: boolean;
comments: boolean;
history: boolean;
relationships: boolean;
};

// Table
columns: ColumnDef[];
defaultSort: { field: string; order: 'asc' | 'desc' };

// Forms
createFields: FormField[];
editFields: FormField[];

// Actions
rowActions: RowAction[];
bulkActions: BulkAction[];

// Customization
detailTabs?: TabConfig[];
metrics?: MetricConfig;
}

Usage Pattern

// config/entityConfigs.ts
export const requirementConfig: EntityConfig = {
name: 'Requirement',
plural: 'Requirements',
apiPath: '/api/v1/requirements',
icon: DescriptionIcon,
features: {
search: true,
bulkDelete: true,
export: true,
import: true,
comments: true,
history: true,
relationships: true,
},
columns: [...],
// ...
};

// pages/Requirements.tsx
export const Requirements = () => (
<EntityListPage config={requirementConfig} />
);

Unified Components

ComponentPurpose
EntityListPageStandard list view with table
EntityDetailPageDetail view with tabs
EntityEditDialogCreate/edit modal
EntityDeleteDialogDelete confirmation
EntityFiltersFilter sidebar
EntitySearchSearch with suggestions

Consequences

Positive

  • 90% Code Reduction: Single implementation for all entities
  • Instant Parity: New features apply to all entities
  • Type Safety: TypeScript validates all configurations
  • Easy Onboarding: New entity = new config file
  • Consistent UX: Users learn once, use everywhere
  • Maintainability: Fix once, fix everywhere

Negative

  • Configuration Complexity: Large config objects
  • Limited Flexibility: Edge cases need escape hatches
  • Learning Curve: Must understand config schema
  • Type Definitions: Complex TypeScript types

Neutral

  • Bundle Size: Single component vs many specific ones
  • Performance: Slightly more props to process

Alternatives Considered

1. Copy-Paste Components

  • Approach: Duplicate components per entity
  • Rejected: Maintenance nightmare, inconsistency

2. Higher-Order Components

  • Approach: HOC pattern for shared behavior
  • Rejected: Harder to type, wrapper hell

3. Inheritance

  • Approach: Class inheritance for pages
  • Rejected: Not idiomatic React, less flexible

Implementation Status

  • Core implementation complete
  • Tests written and passing
  • Documentation updated
  • Migration/upgrade path defined
  • Monitoring/observability in place

Implementation Details

  • Configs: frontend/src/config/entityConfigs.ts
  • List Page: frontend/src/components/entities/EntityListPage.tsx
  • Detail Page: frontend/src/components/entities/EntityDetailPage.tsx
  • Types: frontend/src/types/entityConfig.ts
  • Docs: docs/development/entity-development-guide.md

Compliance/Validation

  • Automated checks: TypeScript validates configs
  • Manual review: New configs reviewed for consistency
  • Metrics: None (development pattern)

LLM Council Review

Review Date: 2025-01-16 Confidence Level: High (100%) Verdict: STRONG APPROVAL

Quality Metrics

  • Consensus Strength Score (CSS): 0.95
  • Deliberation Depth Index (DDI): 0.88

Council Feedback Summary

Unanimous consensus that configuration-driven UI is the correct pattern for managing 17 entity types. The 90% code reduction is realistic because SRE operations prioritize functional consistency over bespoke UX.

Key Concerns Identified:

  1. "Law of Leaky Abstractions": If complex workflow logic is encoded in JSON, config becomes a "poor man's programming language"
  2. Edge Cases (~10-20%): Some entities won't fit CRUD model (relationship editors, terminal windows, approval workflows)
  3. Type Safety: "JSON-like" is insufficient; must be strict TypeScript

Required Modifications:

  1. Strict TypeScript with Generics:
    • Bad: interface Column { key: string }
    • Good: interface Column<T> { key: keyof T }
    • Use satisfies operator or factory functions
  2. Accept Code, Not Just Data: Keep configs as .ts/.tsx files to allow typed functions
  3. Implement Escape Hatches (Slots Pattern):
    • Slots: BeforeList, DetailSidebar, CustomCellRenderer
    • Page Overrides: Bypass generator entirely for complex entities
  4. Feature Flag Contracts: If flag enabled (e.g., import: true), types must enforce supporting config
  5. Centralized Registry: Typed registry of all entity configs to prevent magic strings

Modifications Applied

  1. Documented strict generics requirement
  2. Added escape hatch slots pattern
  3. Documented Zod runtime validation recommendation
  4. Added centralized typed registry pattern

Council Ranking

  • All models reached strong consensus
  • gpt-5.2: Best Response (type safety focus)
  • claude-opus-4.5: Strong (escape hatches)

References

  • Industry patterns: Strapi content types, Contentful models
  • docs/development/entity-development-guide.md
  • docs/AI_ENTITY_IMPLEMENTATION_GUIDE.md

ADR-016 | Frontend Layer | Implemented