Context
The AppCMS Theme Editor allows administrators to configure branding and UI styling properties for a platform, including colors, typography, component styling, navigation appearance, and other UI tokens.
Historically, frontend implementations that bind UI components directly to backend theme payload structures become brittle over time due to:
- backend schema changes
- inconsistent naming conventions
- nested structure changes
- platform-specific variants
- UI redesigns that require restructuring the form
Direct coupling between the UI layer and backend theme payloads leads to fragile systems where schema changes require UI rewrites.
To ensure long-term maintainability, the system must isolate:
- backend schema representation
- frontend form state structure
- UI rendering layer
This separation allows UI changes without affecting persistence logic and backend schema evolution without breaking frontend code.
Decision
Theme editing will follow a normalized form-state pipeline architecture with explicit adapter layers between backend data and UI form state.
:::info Theme data lifecycle
Backend Theme Schema
↓
normalizeThemeAdapter
↓
RHF Form State
↓
UI Renderer
↓
dirtyFields detection
↓
serializeThemeAdapter
↓
API update
↓
Server response → form.reset()
:::
1. Normalization Layer
Backend theme data is passed through normalizeThemeAdapter.
Responsibilities:
- convert backend schema into UI-friendly namespaced structure
- enforce consistent naming conventions
- provide stable keys for form binding
- isolate UI from backend payload structure
:::info Example transformation
Backend
cta_primary_bg
↓
Normalized
uiElements.cta.primary.backgroundColor
:::
2. Form State Management
The normalized theme object populates a React Hook Form (RHF) instance.
RHF provides:
- nested form state handling
- efficient change detection
dirtyFieldstracking- deterministic form updates
The RHF form state becomes the single source of truth for the editor UI.
3. UI Rendering Layer
- The UI renders fields based on the normalized structure.
- The UI must not depend on backend payload shape.
- UI layout (tabs, accordions, visual builders, etc.) may change independently without affecting persistence logic.
4. Change Detection
Updates are triggered based on dirtyFields instead of isDirty.
This ensures:
- deterministic detection of actual field modifications
- prevention of unnecessary API calls
- resilience to form resets and programmatic value updates
5. Serialization Layer
Before sending updates to the backend, the normalized structure is converted back into backend format via serializeThemeAdapter.
Responsibilities:
- convert UI namespace structure back to backend schema
- guarantee payload compatibility with the backend API
- isolate backend schema expectations from the UI layer
6. Server Response Handling
After a successful update:
- The backend response is treated as the source of truth.
- Theme state is updated.
form.reset()is called with the latest server values.
This ensures:
- dirty state is cleared
- UI reflects persisted data
- frontend state remains synchronized with backend data.
Consequences
Positive
- UI layer becomes replaceable without affecting persistence logic.
- Backend schema changes are isolated to adapter layers.
- Form state becomes predictable and easier to reason about.
- Dirty field detection prevents redundant API calls.
- Architecture supports autosave workflows and manual save workflows.
- Enables future capabilities such as:
- theme versioning
- theme import/export
- live preview editing
- platform-specific theme variants
- visual theme editors
Tradeoffs
- Requires maintaining adapter layers for normalization and serialization.
- Slightly higher architectural complexity compared to direct binding approaches.
However, this complexity prevents long-term coupling between UI and backend schema.
Notes
- This ADR defines the canonical data lifecycle for all theme editing operations within AppCMS.
- All theme editor implementations must conform to this pipeline to maintain separation between:
- backend schema
- frontend form state
- UI rendering
normalizeThemeAdapterandserializeThemeAdapterform the integration boundary between backend and frontend systems and should be covered by unit tests to prevent schema drift issues.