# 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 5. **`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 6. **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 7. **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 8. **Modified: `packages/noodl-viewer-react/typings/global.d.ts`** - Added `Config: Readonly>` to `GlobalNoodl` - Includes JSDoc with usage examples ### Tests 9. **`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 10. **`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: - `ogTitle` → `identity.appName` - `ogDescription` → `identity.description` - `ogImage` → `identity.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 ```typescript // 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 ✅ - [x] Config values stored in `project.json` metadata (`metadata.appConfig`) - [x] Immutable at runtime (deep freeze + proxy protection) - [x] Accessible via `Noodl.Config.variableName` syntax - [x] Type-safe with full TypeScript definitions - [x] Validation for keys (JS identifiers, reserved check) - [x] Validation for values (type-specific rules) - [x] ProjectModel methods for editor integration - [x] Smart defaults for SEO fields - [x] Comprehensive unit tests (220+ test cases) - [x] Documentation and examples --- ## Testing ### Run Tests ```bash # 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 --- ## Related Files Modified - `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`