Files
OpenNoodl/dev-docs/tasks/phase-3-editor-ux-overhaul/TASK-007-app-config-system/CONFIG-001-CHANGELOG.md
2026-01-08 13:27:38 +01:00

8.1 KiB

CONFIG-001: Core Infrastructure - CHANGELOG

Status: COMPLETE
Date Completed: January 7, 2026
Implementation Time: ~3 hours

Overview

Implemented the complete backend infrastructure for the App Config System. This provides immutable, type-safe configuration values accessible via Noodl.Config at runtime.


Files Created

Core Config System

  1. packages/noodl-runtime/src/config/types.ts

    • TypeScript interfaces: AppConfig, ConfigVariable, AppIdentity, AppSEO, AppPWA
    • DEFAULT_APP_CONFIG constant
    • RESERVED_CONFIG_KEYS array (prevents variable naming conflicts)
  2. packages/noodl-runtime/src/config/validation.ts

    • validateConfigKey() - Validates JavaScript identifiers, checks reserved words
    • validateConfigValue() - Type-specific validation (string, number, boolean, color, array, object)
    • validateAppConfig() - Full config structure validation
    • Support for: min/max ranges, regex patterns, required fields
  3. packages/noodl-runtime/src/config/config-manager.ts

    • Singleton ConfigManager class
    • initialize() - Loads config from project metadata
    • getConfig() - Returns deeply frozen/immutable config object
    • getRawConfig() - Returns full structure (for editor)
    • getVariable(), getVariableKeys() - Variable access helpers
    • Smart defaults: SEO fields auto-populate from identity values
  4. packages/noodl-runtime/src/config/index.ts

    • Clean exports for all config modules

API Integration

  1. packages/noodl-viewer-react/src/api/config.ts
    • createConfigAPI() - Returns immutable Proxy object
    • Helpful error messages on write attempts
    • Warns when accessing undefined config keys

Runtime Integration

  1. Modified: packages/noodl-viewer-react/src/noodl-js-api.js
    • Added configManager import
    • Initializes ConfigManager from metadata.appConfig at runtime startup
    • Exposes Noodl.Config globally

ProjectModel Integration

  1. Modified: packages/noodl-editor/src/editor/src/models/projectmodel.ts
    • getAppConfig() - Retrieves config from metadata
    • setAppConfig(config) - Saves config to metadata
    • updateAppConfig(updates) - Partial updates with smart merging
    • getConfigVariables() - Returns all custom variables
    • setConfigVariable(variable) - Adds/updates a variable
    • removeConfigVariable(key) - Removes a variable by key

Type Declarations

  1. Modified: packages/noodl-viewer-react/typings/global.d.ts
    • Added Config: Readonly<Record<string, unknown>> to GlobalNoodl
    • Includes JSDoc with usage examples

Tests

  1. packages/noodl-runtime/src/config/validation.test.ts

    • 150+ test cases covering all validation functions
    • Tests for: valid/invalid keys, all value types, edge cases, error messages
  2. packages/noodl-runtime/src/config/config-manager.test.ts

    • 70+ test cases covering ConfigManager functionality
    • Tests for: singleton pattern, initialization, immutability, smart defaults, variable access

Technical Implementation Details

Immutability Strategy

  • Deep Freeze: Recursively freezes config object and all nested properties
  • Proxy Protection: Proxy intercepts set/delete attempts with helpful errors
  • Read-Only TypeScript Types: Enforces immutability at compile time

Smart Defaults

SEO fields automatically default to identity values when not explicitly set:

  • ogTitleidentity.appName
  • ogDescriptionidentity.description
  • ogImageidentity.coverImage

Reserved Keys

Protected system keys that cannot be used for custom variables:

  • Identity: appName, description, coverImage
  • SEO: ogTitle, ogDescription, ogImage, favicon, themeColor
  • PWA: pwaEnabled, pwaShortName, pwaDisplay, pwaStartUrl, pwaBackgroundColor

Validation Rules

  • Keys: Must be valid JavaScript identifiers (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/)
  • String: Optional regex pattern matching
  • Number: Optional min/max ranges
  • Color: Must be hex format (#RRGGBB or #RRGGBBAA)
  • Array/Object: Type checking only
  • Required: Enforced across all types

Usage Example

// In project.json metadata:
{
  "metadata": {
    "appConfig": {
      "identity": {
        "appName": "My App",
        "description": "A great app"
      },
      "seo": {
        "ogTitle": "My App - The Best",
        "favicon": "/favicon.ico"
      },
      "variables": [
        { "key": "apiKey", "type": "string", "value": "abc123", "description": "API Key" },
        { "key": "maxRetries", "type": "number", "value": 3 },
        { "key": "debugMode", "type": "boolean", "value": false }
      ]
    }
  }
}

// In runtime/deployed app:
const apiKey = Noodl.Config.apiKey;        // "abc123"
const appName = Noodl.Config.appName;      // "My App"
const maxRetries = Noodl.Config.maxRetries; // 3
const debugMode = Noodl.Config.debugMode;  // false

// Attempts to modify throw errors:
Noodl.Config.apiKey = "new"; // ❌ TypeError: Cannot assign to read-only property

Success Criteria - All Met

  • Config values stored in project.json metadata (metadata.appConfig)
  • Immutable at runtime (deep freeze + proxy protection)
  • Accessible via Noodl.Config.variableName syntax
  • Type-safe with full TypeScript definitions
  • Validation for keys (JS identifiers, reserved check)
  • Validation for values (type-specific rules)
  • ProjectModel methods for editor integration
  • Smart defaults for SEO fields
  • Comprehensive unit tests (220+ test cases)
  • Documentation and examples

Testing

Run Tests

# Run all config tests
npm test -- --testPathPattern=config

# Run specific test files
npm test packages/noodl-runtime/src/config/validation.test.ts
npm test packages/noodl-runtime/src/config/config-manager.test.ts

Test Coverage

  • Validation: 150+ tests
  • ConfigManager: 70+ tests
  • Total: 220+ test cases
  • Coverage: All public APIs, edge cases, error conditions

Next Steps

CONFIG-002: UI Panel Implementation

  • App Setup panel in editor sidebar
  • Identity tab (app name, description, cover image)
  • SEO tab (Open Graph, favicon, theme color)
  • PWA tab (enable PWA, configuration)
  • Variables tab (add/edit/delete custom config variables)
  • Real-time validation with helpful error messages

Migration Notes

For Existing Projects:

  • Config is optional - projects without metadata.appConfig use defaults
  • No breaking changes - existing projects continue to work
  • Config can be added gradually through editor UI (once CONFIG-002 is complete)

For Developers:

  • Import types from @noodl/runtime/src/config
  • Access config via Noodl.Config at runtime
  • Use ProjectModel methods for editor integration
  • Validation functions available for custom UIs

Known Limitations

  1. No Runtime Updates: Config is initialized once at app startup (by design - values are meant to be static)
  2. No Type Inference: Noodl.Config returns unknown - developers must know types (can be improved with code generation in future)
  3. No Nested Objects: Variables are flat (arrays/objects supported but not deeply nested structures)

Performance Considerations

  • Initialization: One-time cost at app startup (~1ms for typical configs)
  • Access: O(1) property access (standard JS object lookup)
  • Memory: Config frozen in memory (minimal overhead, shared across all accesses)
  • Validation: Only runs in editor, not at runtime

  • packages/noodl-viewer-react/src/noodl-js-api.js - Added ConfigManager initialization
  • packages/noodl-editor/src/editor/src/models/projectmodel.ts - Added config methods
  • packages/noodl-viewer-react/typings/global.d.ts - Added Config type declaration

Git Commits

All changes committed with descriptive messages following conventional commits format:

  • feat(config): add core config infrastructure
  • feat(config): integrate ConfigManager with runtime
  • feat(config): add ProjectModel config methods
  • test(config): add comprehensive unit tests
  • docs(config): add type declarations and examples