Files
OpenNoodl/dev-docs/tasks/phase-3-editor-ux-overhaul/TASK-007-app-config/README.md
2025-12-30 11:55:30 +01:00

368 lines
15 KiB
Markdown

# TASK-007: App Configuration & Environment System
## Overview
A new "App Setup" sidebar panel for defining app-wide configuration values (`Noodl.Config`), SEO metadata, PWA manifest generation, and an App Config node for accessing values without expressions.
**Estimated effort:** 64-86 hours
**Priority:** High - Foundation for theming, SEO, PWA, and deployment features
**Phase:** 3 (Editor UX Overhaul)
---
## Problem Statement
### Current Pain Points
1. **No central place for app metadata**: App name, description, and SEO values are scattered or missing
2. **Global variables require node clutter**: Users create Object/Variables nodes at App level and wire them everywhere, creating visual noise
3. **No PWA support**: Users must manually create manifest.json and configure service workers
4. **SEO is an afterthought**: No built-in way to set meta tags, Open Graph, or favicon
5. **Theming is manual**: No standard pattern for defining color palettes or configuration values
### User Stories
- *"I want to define my app's primary color once and reference it everywhere"*
- *"I want my app to appear correctly when shared on social media"*
- *"I want to add my app to home screen on mobile with proper icons"*
- *"I want a simple way to access config values without writing expressions"*
---
## Solution
### New Namespace: `Noodl.Config`
A **static, immutable** configuration namespace separate from `Noodl.Variables`:
```javascript
// Static - set once at app initialization, cannot change at runtime
Noodl.Config.appName // "My Amazing App"
Noodl.Config.primaryColor // "#d21f3c"
Noodl.Config.apiBaseUrl // "https://api.example.com"
Noodl.Config.menuItems // [{name: "Home", path: "/"}, ...]
// This is NOT allowed (throws or is ignored):
Noodl.Config.primaryColor = "#000000"; // ❌ Config is immutable
```
### Design Principles
1. **Config is static**: Values are "baked in" at app load - use Variables for runtime changes
2. **Type-aware editing**: Color picker for colors, array editor for arrays, etc.
3. **Required defaults**: Core metadata (name, description) always exists
4. **Expression + Node access**: Both `Noodl.Config.x` in expressions AND an App Config node
5. **Build-time injection**: SEO tags and PWA manifest generated during build/deploy
---
## Architecture
### Data Model
```typescript
interface AppConfig {
// Required sections (non-deletable)
identity: {
appName: string;
description: string;
coverImage?: string; // Path or URL
};
seo: {
ogTitle?: string; // Defaults to appName
ogDescription?: string; // Defaults to description
ogImage?: string; // Defaults to coverImage
favicon?: string;
themeColor?: string;
};
// Optional section
pwa?: {
enabled: boolean;
shortName?: string;
startUrl: string; // Default: "/"
display: 'standalone' | 'fullscreen' | 'minimal-ui' | 'browser';
backgroundColor?: string;
sourceIcon?: string; // Single source, auto-scaled to required sizes
};
// User-defined variables
variables: ConfigVariable[];
}
interface ConfigVariable {
key: string; // Valid JS identifier
type: ConfigType;
value: any;
description?: string; // Tooltip in UI
category?: string; // Grouping (defaults to "Custom")
validation?: {
required?: boolean;
pattern?: string; // Regex for strings
min?: number; // For numbers
max?: number;
};
}
type ConfigType = 'string' | 'number' | 'boolean' | 'color' | 'array' | 'object';
```
### Storage Location
Stored in `project.json` under metadata:
```json
{
"metadata": {
"appConfig": {
"identity": {
"appName": "My App",
"description": "An amazing app"
},
"seo": {
"themeColor": "#d21f3c"
},
"pwa": {
"enabled": true,
"display": "standalone"
},
"variables": [
{
"key": "primaryColor",
"type": "color",
"value": "#d21f3c",
"category": "Theme"
}
]
}
}
}
```
---
## UI Design
### App Setup Panel
New top-level sidebar tab (migrating some project settings here):
```
┌─────────────────────────────────────────────────┐
│ App Setup [?] │
├─────────────────────────────────────────────────┤
│ │
│ APP IDENTITY │
│ ┌─────────────────────────────────────────────┐ │
│ │ App Name [My Amazing App ] │ │
│ │ Description [A visual programming... ] │ │
│ │ [that makes building easy ] │ │
│ │ Cover Image [🖼️ cover.png ][Browse] │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ SEO & METADATA │
│ ┌─────────────────────────────────────────────┐ │
│ │ OG Title [ ] │ │
│ │ └ defaults to App Name │ │
│ │ OG Description [ ] │ │
│ │ └ defaults to Description │ │
│ │ OG Image [🖼️ ][Browse] │ │
│ │ └ defaults to Cover Image │ │
│ │ Favicon [🖼️ favicon.ico ][Browse] │ │
│ │ Theme Color [■ #d21f3c ] │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ▶ PWA CONFIGURATION [Enable] │
│ ┌─────────────────────────────────────────────┐ │
│ │ Short Name [My App ] │ │
│ │ Display Mode [Standalone ▼ ] │ │
│ │ Start URL [/ ] │ │
│ │ Background [■ #ffffff ] │ │
│ │ App Icon [🖼️ icon-512.png][Browse] │ │
│ │ └ 512x512 PNG, auto-scaled │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ CONFIGURATION VARIABLES [+ Add New] │
│ ┌─────────────────────────────────────────────┐ │
│ │ ┌─ Theme ─────────────────────────────────┐ │ │
│ │ │ primaryColor color [■ #d21f3c ][⋮]│ │ │
│ │ │ secondaryColor color [■ #1f3cd2 ][⋮]│ │ │
│ │ └─────────────────────────────────────────┘ │ │
│ │ ┌─ API ───────────────────────────────────┐ │ │
│ │ │ apiBaseUrl string [https://... ][⋮]│ │ │
│ │ └─────────────────────────────────────────┘ │ │
│ │ ┌─ Custom ────────────────────────────────┐ │ │
│ │ │ maxUploadSize number [10 ][⋮]│ │ │
│ │ └─────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────┘
```
### App Config Node
```
┌──────────────────────────────┐
│ App Config │
├──────────────────────────────┤
│ Variables │
│ ┌──────────────────────────┐ │
│ │ ☑ primaryColor │ │
│ │ ☑ apiBaseUrl │ │
│ │ ☐ secondaryColor │ │
│ │ ☑ menuItems │ │
│ └──────────────────────────┘ │
├──────────────────────────────┤
│ ○ primaryColor │──→
│ ○ apiBaseUrl │──→
│ ○ menuItems │──→
└──────────────────────────────┘
```
---
## Subtasks
| Task | Description | Estimate | Dependencies |
|------|-------------|----------|--------------|
| [CONFIG-001](./CONFIG-001-infrastructure.md) | Core Infrastructure | 14-18h | None |
| [CONFIG-002](./CONFIG-002-app-setup-panel.md) | App Setup Panel UI | 18-24h | CONFIG-001 |
| [CONFIG-003](./CONFIG-003-app-config-node.md) | App Config Node | 10-14h | CONFIG-001 |
| [CONFIG-004](./CONFIG-004-seo-integration.md) | SEO Build Integration | 8-10h | CONFIG-001, CONFIG-002 |
| [CONFIG-005](./CONFIG-005-pwa-manifest.md) | PWA Manifest Generation | 10-14h | CONFIG-001, CONFIG-002 |
| [CONFIG-006](./CONFIG-006-expression-integration.md) | Expression System Integration | 4-6h | CONFIG-001, TASK-006 |
**Total: 64-86 hours**
---
## Cloud Service Node UX Improvement
**Prerequisite cleanup task** (can be done as part of CONFIG-003 or separately):
### Problem
The existing "Config" node accesses Noodl Cloud Service (Parse Server) configuration. This will cause confusion with the new App Config system.
### Solution
1. **Rename existing node**: `Config``Noodl Cloud Config`
2. **Hide cloud nodes when no backend**: If no cloud service is connected, hide ALL nodes in the "Cloud Data" category from the node picker
3. **Show guidance**: Display "Please add a backend service" message in that category until a service is connected
4. **Preserve existing nodes**: Don't break legacy projects - existing nodes continue to work, just hidden from picker
### Files to modify:
- `packages/noodl-runtime/src/nodes/std-library/data/confignode.js` - Rename
- `packages/noodl-editor/src/editor/src/views/nodepicker/` - Category visibility logic
- `packages/noodl-runtime/src/nodelibraryexport.js` - Update node name in exports
---
## Integration Points
### With DEPLOY-003 (Environment Profiles)
DEPLOY-003 can **override** Config values per environment:
```
App Setup Panel DEPLOY-003 Profiles
───────────────── ───────────────────
apiBaseUrl: "dev" → Production: "https://api.prod.com"
Staging: "https://api.staging.com"
Development: (uses default)
```
The App Setup panel shows canonical/default values. DEPLOY-003 shows environment-specific overrides.
### With TASK-006 (Expression System)
The enhanced expression system will provide:
- `Noodl.Config.xxx` access in expressions
- Autocomplete for config keys
- Type hints
### With Phase 5 (Capacitor Deployment)
PWA icon generation will be reused for Capacitor app icons:
- Same 512x512 source image
- Generate iOS/Android required sizes
- Include in platform-specific builds
---
## Component Export Behavior
When exporting a component that uses `Noodl.Config.primaryColor`:
| Variable Type | Export Behavior |
|---------------|-----------------|
| **Custom variables** | Hard-coded to current values |
| **Default variables** (appName, etc.) | Reference preserved |
The importer is responsible for updating hard-coded values if needed.
---
## Testing Checklist
### Manual Testing
- [ ] App Setup panel appears in sidebar
- [ ] Can edit all identity fields
- [ ] Can edit SEO fields (with defaults shown)
- [ ] Can enable/disable PWA section
- [ ] Can add custom variables with different types
- [ ] Color picker works for color type
- [ ] Array editor works for array type
- [ ] Categories group variables correctly
- [ ] App Config node shows all custom variables
- [ ] Selected variables appear as outputs
- [ ] Output types match variable types
- [ ] `Noodl.Config.xxx` accessible in expressions
- [ ] SEO tags appear in built HTML
- [ ] manifest.json generated with correct values
- [ ] PWA icons auto-scaled from source
### Build Testing
- [ ] Export includes correct meta tags
- [ ] manifest.json valid and complete
- [ ] Icons generated at all required sizes
- [ ] Theme color in HTML head
- [ ] Open Graph tags render correctly
---
## Success Criteria
1. **Discoverable**: New users find App Setup easily in sidebar
2. **Complete**: SEO and PWA work without manual file editing
3. **Type-safe**: Color variables show color pickers, arrays show array editors
4. **Non-breaking**: Existing projects work, cloud nodes still function
5. **Extensible**: DEPLOY-003 can override values per environment
---
## Open Questions (Resolved)
| Question | Decision |
|----------|----------|
| Namespace name? | `Noodl.Config` |
| Static or reactive? | Static (immutable at runtime) |
| Panel location? | New top-level sidebar tab |
| PWA icons? | Single 512x512 source, auto-scaled |
| Categories required? | Optional, ungrouped → "Custom" |
| Loaded signal on node? | No, overkill for static values |
| ENV node name? | "App Config" |
---
## References
- Existing project settings: `views/panels/ProjectSettingsPanel/`
- Port type editors: `views/panels/propertyeditor/DataTypes/Ports.ts`
- HTML build processor: `utils/compilation/build/processors/html-processor.ts`
- Expression system: `TASK-006-expressions-overhaul/`
- Deploy settings: `TASK-005-deployment-automation/DEPLOY-003-deploy-settings.md`
- Cloud config node: `noodl-runtime/src/nodes/std-library/data/confignode.js`