# ADR-013: Typdialog Web UI Backend Integration for Interactive Configuration\n\n## Status\n\n**Accepted** - 2025-01-08\n\n## Context\n\nThe provisioning system requires interactive user input for configuration workflows, workspace initialization, credential setup, and guided deployment\nscenarios. The system architecture combines Rust (performance-critical), Nushell (scripting), and Nickel (declarative configuration), creating\nchallenges for interactive form-based input and multi-user collaboration.\n\n### The Interactive Configuration Problem\n\n**Current limitations**:\n\n1. **Nushell CLI**: Terminal-only interaction\n   - `input` command: Single-line text prompts only\n   - No form validation, no complex multi-field forms\n   - Limited to single-user, terminal-bound workflows\n   - User experience: Basic and error-prone\n\n2. **Nickel**: Declarative configuration language\n   - Cannot handle interactive prompts (by design)\n   - Pure evaluation model (no side effects)\n   - Forms must be defined statically, not interactively\n   - No runtime user interaction\n\n3. **Existing Solutions**: Inadequate for modern infrastructure provisioning\n   - **Shell-based prompts**: Error-prone, no validation, single-user\n   - **Custom web forms**: High maintenance, inconsistent UX\n   - **Separate admin panels**: Disconnected from IaC workflow\n   - **Terminal-only TUI**: Limited to SSH sessions, no collaboration\n\n### Use Cases Requiring Interactive Input\n\n1. **Workspace Initialization**:\n   ```nushell\n   # Current: Error-prone prompts\n   let workspace_name = input "Workspace name: "\n   let provider = input "Provider (aws/azure/oci): "\n   # No validation, no autocomplete, no guidance\n   ```\n\n2. **Credential Setup**:\n   ```nushell\n   # Current: Insecure and basic\n   let api_key = input "API Key: "  # Shows in terminal history\n   let region = input "Region: "    # No validation\n   ```\n\n3. **Configuration Wizards**:\n   - Database connection setup (host, port, credentials, SSL)\n   - Network configuration (CIDR blocks, subnets, gateways)\n   - Security policies (encryption, access control, audit)\n\n4. **Guided Deployments**:\n   - Multi-step infrastructure provisioning\n   - Service selection with dependencies\n   - Environment-specific overrides\n\n### Requirements for Interactive Input System\n\n- ✅ **Terminal UI widgets**: Text input, password, select, multi-select, confirm\n- ✅ **Validation**: Type checking, regex patterns, custom validators\n- ✅ **Security**: Password masking, sensitive data handling\n- ✅ **User Experience**: Arrow key navigation, autocomplete, help text\n- ✅ **Composability**: Chain multiple prompts into forms\n- ✅ **Error Handling**: Clear validation errors, retry logic\n- ✅ **Rust Integration**: Native Rust library (no subprocess overhead)\n- ✅ **Cross-Platform**: Works on Linux, macOS, Windows\n\n## Decision\n\nIntegrate **typdialog** with its **Web UI backend** as the standard interactive configuration interface for the provisioning platform. The major\nachievement of typdialog is not the TUI - it is the Web UI backend that enables browser-based forms, multi-user collaboration, and seamless\nintegration with the provisioning orchestrator.\n\n### Architecture Diagram\n\n```\n┌─────────────────────────────────────────┐\n│   Nushell Script                        │\n│                                         │\n│   provisioning workspace init           │\n│   provisioning config setup             │\n│   provisioning deploy guided            │\n└────────────┬────────────────────────────┘\n             │\n             ▼\n┌─────────────────────────────────────────┐\n│   Rust CLI Handler                      │\n│   (provisioning/core/cli/)              │\n│                                         │\n│   - Parse command                       │\n│   - Determine if interactive needed     │\n│   - Invoke TUI dialog module            │\n└────────────┬────────────────────────────┘\n             │\n             ▼\n┌─────────────────────────────────────────┐\n│   TUI Dialog Module                     │\n│   (typdialog wrapper)                   │\n│                                         │\n│   - Form definition (validation rules)  │\n│   - Widget rendering (text, select)     │\n│   - User input capture                  │\n│   - Validation execution                │\n│   - Result serialization (JSON/TOML)    │\n└────────────┬────────────────────────────┘\n             │\n             ▼\n┌─────────────────────────────────────────┐\n│   typdialog Library                     │\n│                                         │\n│   - Terminal rendering (crossterm)      │\n│   - Event handling (keyboard, mouse)    │\n│   - Widget state management             │\n│   - Input validation engine             │\n└────────────┬────────────────────────────┘\n             │\n             ▼\n┌─────────────────────────────────────────┐\n│   Terminal (stdout/stdin)               │\n│                                         │\n│   ✅ Rich TUI with validation           │\n│   ✅ Secure password input              │\n│   ✅ Guided multi-step forms            │\n└─────────────────────────────────────────┘\n```\n\n### Implementation Characteristics\n\n**CLI Integration Provides**:\n\n- ✅ Native Rust commands with TUI dialogs\n- ✅ Form-based input for complex configurations\n- ✅ Validation rules defined in Rust (type-safe)\n- ✅ Secure input (password masking, no history)\n- ✅ Error handling with retry logic\n- ✅ Serialization to Nickel/TOML/JSON\n\n**TUI Dialog Library Handles**:\n\n- ✅ Terminal UI rendering and event loop\n- ✅ Widget management (text, select, checkbox, confirm)\n- ✅ Input validation and error display\n- ✅ Navigation (arrow keys, tab, enter)\n- ✅ Cross-platform terminal compatibility\n\n## Rationale\n\n### Why TUI Dialog Integration Is Required\n\n| Aspect | Shell Prompts (current) | Web Forms | TUI Dialog (chosen) |\n| -------- | ------------------------- | ----------- | --------------------- |\n| **User Experience** | ❌ Basic text only | ✅ Rich UI | ✅ Rich TUI |\n| **Validation** | ❌ Manual, error-prone | ✅ Built-in | ✅ Built-in |\n| **Security** | ❌ Plain text, history | ⚠️ Network risk | ✅ Secure terminal |\n| **Setup Complexity** | ✅ None | ❌ Server required | ✅ Minimal |\n| **Terminal Workflow** | ✅ Native | ❌ Browser switch | ✅ Native |\n| **Offline Support** | ✅ Always | ❌ Requires server | ✅ Always |\n| **Dependencies** | ✅ None | ❌ Web stack | ✅ Single crate |\n| **Error Handling** | ❌ Manual | ⚠️ Complex | ✅ Built-in retry |\n\n### The Nushell Limitation\n\nNushell's `input` command is limited:\n\n```\n# Current: No validation, no security\nlet password = input "Password: "  # ❌ Shows in terminal\nlet region = input "AWS Region: "   # ❌ No autocomplete/validation\n\n# Cannot do:\n# - Multi-select from options\n# - Conditional fields (if X then ask Y)\n# - Password masking\n# - Real-time validation\n# - Autocomplete/fuzzy search\n```\n\n### The Nickel Constraint\n\nNickel is declarative and cannot prompt users:\n\n```\n# Nickel defines what the config looks like, NOT how to get it\n{\n  database = {\n    host | String,\n    port | Number,\n    credentials | { username: String, password: String },\n  }\n}\n\n# Nickel cannot:\n# - Prompt user for values\n# - Show interactive forms\n# - Validate input interactively\n```\n\n### Why Rust + TUI Dialog Is The Solution\n\n**Rust provides**:\n- Native terminal control (crossterm, termion)\n- Type-safe form definitions\n- Validation rules as functions\n- Secure memory handling (password zeroization)\n- Performance (no subprocess overhead)\n\n**TUI Dialog provides**:\n- Widget library (text, select, multi-select, confirm)\n- Event loop and rendering\n- Validation framework\n- Error display and retry logic\n\n**Integration enables**:\n- Nushell calls Rust CLI → Shows TUI dialog → Returns validated config\n- Nickel receives validated config → Type checks → Merges with defaults\n\n## Consequences\n\n### Positive\n\n- **User Experience**: Professional TUI with validation and guidance\n- **Security**: Password masking, sensitive data protection, no terminal history\n- **Validation**: Type-safe rules enforced before config generation\n- **Developer Experience**: Reusable form components across CLI commands\n- **Error Handling**: Clear validation errors with retry options\n- **Offline First**: No network dependencies for interactive input\n- **Terminal Native**: Fits CLI workflow, no context switching\n- **Maintainability**: Single library for all interactive input\n\n### Negative\n\n- **Terminal Dependency**: Requires interactive terminal (not scriptable)\n- **Learning Curve**: Developers must learn TUI dialog patterns\n- **Library Lock-in**: Tied to specific TUI library API\n- **Testing Complexity**: Interactive tests require terminal mocking\n- **Non-Interactive Fallback**: Need alternative for CI/CD and scripts\n\n### Mitigation Strategies\n\n**Non-Interactive Mode**:\n```\n// Support both interactive and non-interactive\nif terminal::is_interactive() {\n    // Show TUI dialog\n    let config = show_workspace_form()?;\n} else {\n    // Use config file or CLI args\n    let config = load_config_from_file(args.config)?;\n}\n```\n\n**Testing**:\n```\n// Unit tests: Test form validation logic (no TUI)\n#[test]\nfn test_validate_workspace_name() {\n    assert!(validate_name("my-workspace").is_ok());\n    assert!(validate_name("invalid name!").is_err());\n}\n\n// Integration tests: Use mock terminal or config files\n```\n\n**Scriptability**:\n```\n# Batch mode: Provide config via file\nprovisioning workspace init --config workspace.toml\n\n# Interactive mode: Show TUI dialog\nprovisioning workspace init --interactive\n```\n\n**Documentation**:\n- Form schemas documented in `docs/`\n- Config file examples provided\n- Screenshots of TUI forms in guides\n\n## Alternatives Considered\n\n### Alternative 1: Shell-Based Prompts (Current State)\n\n**Pros**: Simple, no dependencies\n**Cons**: No validation, poor UX, security risks\n**Decision**: REJECTED - Inadequate for production use\n\n### Alternative 2: Web-Based Forms\n\n**Pros**: Rich UI, well-known patterns\n**Cons**: Requires server, network dependency, context switch\n**Decision**: REJECTED - Too complex for CLI tool\n\n### Alternative 3: Custom TUI Per Use Case\n\n**Pros**: Tailored to each need\n**Cons**: High maintenance, code duplication, inconsistent UX\n**Decision**: REJECTED - Not sustainable\n\n### Alternative 4: External Form Tool (dialog, whiptail)\n\n**Pros**: Mature, cross-platform\n**Cons**: Subprocess overhead, limited validation, shell escaping issues\n**Decision**: REJECTED - Poor Rust integration\n\n### Alternative 5: Text-Based Config Files Only\n\n**Pros**: Fully scriptable, no interactive complexity\n**Cons**: Steep learning curve, no guidance for new users\n**Decision**: REJECTED - Poor user onboarding experience\n\n## Implementation Details\n\n### Form Definition Pattern\n\n```\nuse typdialog::Form;\n\npub fn workspace_initialization_form() -> Result<WorkspaceConfig> {\n    let form = Form::new("Workspace Initialization")\n        .add_text_input("name", "Workspace Name")\n            .required()\n            .validator(|s| validate_workspace_name(s))\n        .add_select("provider", "Cloud Provider")\n            .options(&["aws", "azure", "oci", "local"])\n            .required()\n        .add_text_input("region", "Region")\n            .default("us-west-2")\n            .validator(|s| validate_region(s))\n        .add_password("admin_password", "Admin Password")\n            .required()\n            .min_length(12)\n        .add_confirm("enable_monitoring", "Enable Monitoring?")\n            .default(true);\n\n    let responses = form.run()?;\n\n    // Convert to strongly-typed config\n    let config = WorkspaceConfig {\n        name: responses.get_string("name")?,\n        provider: responses.get_string("provider")?.parse()?,\n        region: responses.get_string("region")?,\n        admin_password: responses.get_password("admin_password")?,\n        enable_monitoring: responses.get_bool("enable_monitoring")?,\n    };\n\n    Ok(config)\n}\n```\n\n### Integration with Nickel\n\n```\n// 1. Get validated input from TUI dialog\nlet config = workspace_initialization_form()?;\n\n// 2. Serialize to TOML/JSON\nlet config_toml = toml::to_string(&config)?;\n\n// 3. Write to workspace config\nfs::write("workspace/config.toml", config_toml)?;\n\n// 4. Nickel merges with defaults\n// nickel export workspace/main.ncl --format json\n// (uses workspace/config.toml as input)\n```\n\n### CLI Command Structure\n\n```\n// provisioning/core/cli/src/commands/workspace.rs\n\n#[derive(Parser)]\npub enum WorkspaceCommand {\n    Init {\n        #[arg(long)]\n        interactive: bool,\n\n        #[arg(long)]\n        config: Option<PathBuf>,\n    },\n}\n\npub fn handle_workspace_init(args: InitArgs) -> Result<()> {\n    if args.interactive || terminal::is_interactive() {\n        // Show TUI dialog\n        let config = workspace_initialization_form()?;\n        config.save("workspace/config.toml")?;\n    } else if let Some(config_path) = args.config {\n        // Use provided config\n        let config = WorkspaceConfig::load(config_path)?;\n        config.save("workspace/config.toml")?;\n    } else {\n        bail!("Either --interactive or --config required");\n    }\n\n    // Continue with workspace setup\n    Ok(())\n}\n```\n\n### Validation Rules\n\n```\npub fn validate_workspace_name(name: &str) -> Result<(), String> {\n    // Alphanumeric, hyphens, 3-32 chars\n    let re = Regex::new(r"^[a-z0-9-]{3,32}$").unwrap();\n    if !re.is_match(name) {\n        return Err("Name must be 3-32 lowercase alphanumeric chars with hyphens".into());\n    }\n    Ok(())\n}\n\npub fn validate_region(region: &str) -> Result<(), String> {\n    const VALID_REGIONS: &[&str] = &["us-west-1", "us-west-2", "us-east-1", "eu-west-1"];\n    if !VALID_REGIONS.contains(&region) {\n        return Err(format!("Invalid region. Must be one of: {}", VALID_REGIONS.join(", ")));\n    }\n    Ok(())\n}\n```\n\n### Security: Password Handling\n\n```\nuse zeroize::Zeroizing;\n\npub fn get_secure_password() -> Result<Zeroizing<String>> {\n    let form = Form::new("Secure Input")\n        .add_password("password", "Password")\n            .required()\n            .min_length(12)\n            .validator(password_strength_check);\n\n    let responses = form.run()?;\n\n    // Password automatically zeroized when dropped\n    let password = Zeroizing::new(responses.get_password("password")?);\n\n    Ok(password)\n}\n```\n\n## Testing Strategy\n\n**Unit Tests**:\n```\n#[test]\nfn test_workspace_name_validation() {\n    assert!(validate_workspace_name("my-workspace").is_ok());\n    assert!(validate_workspace_name("UPPERCASE").is_err());\n    assert!(validate_workspace_name("ab").is_err()); // Too short\n}\n```\n\n**Integration Tests**:\n```\n// Use non-interactive mode with config files\n#[test]\nfn test_workspace_init_non_interactive() {\n    let config = WorkspaceConfig {\n        name: "test-workspace".into(),\n        provider: Provider::Local,\n        region: "us-west-2".into(),\n        admin_password: "secure-password-123".into(),\n        enable_monitoring: true,\n    };\n\n    config.save("/tmp/test-config.toml").unwrap();\n\n    let result = handle_workspace_init(InitArgs {\n        interactive: false,\n        config: Some("/tmp/test-config.toml".into()),\n    });\n\n    assert!(result.is_ok());\n}\n```\n\n**Manual Testing**:\n```\n# Test interactive flow\ncargo build --release\n./target/release/provisioning workspace init --interactive\n\n# Test validation errors\n# - Try invalid workspace name\n# - Try weak password\n# - Try invalid region\n```\n\n## Configuration Integration\n\n**CLI Flag**:\n```\n# provisioning/config/config.defaults.toml\n[ui]\ninteractive_mode = "auto"  # "auto" | "always" | "never"\ndialog_theme = "default"   # "default" | "minimal" | "colorful"\n```\n\n**Environment Override**:\n```\n# Force non-interactive mode (for CI/CD)\nexport PROVISIONING_INTERACTIVE=false\n\n# Force interactive mode\nexport PROVISIONING_INTERACTIVE=true\n```\n\n## Documentation Requirements\n\n**User Guides**:\n- `docs/user/interactive-configuration.md` - How to use TUI dialogs\n- `docs/guides/workspace-setup.md` - Workspace initialization with screenshots\n\n**Developer Documentation**:\n- `docs/development/tui-forms.md` - Creating new TUI forms\n- Form definition best practices\n- Validation rule patterns\n\n**Configuration Schema**:\n```\n# provisioning/schemas/workspace.ncl\n{\n  WorkspaceConfig = {\n    name\n      | doc "Workspace identifier (3-32 alphanumeric chars with hyphens)"\n      | String,\n    provider\n      | doc "Cloud provider"\n      | [| 'aws, 'azure, 'oci, 'local |],\n    region\n      | doc "Deployment region"\n      | String,\n    admin_password\n      | doc "Admin password (min 12 characters)"\n      | String,\n    enable_monitoring\n      | doc "Enable monitoring services"\n      | Bool,\n  }\n}\n```\n\n## Migration Path\n\n**Phase 1: Add Library**\n- Add typdialog dependency to `provisioning/core/cli/Cargo.toml`\n- Create TUI dialog wrapper module\n- Implement basic text/select widgets\n\n**Phase 2: Implement Forms**\n- Workspace initialization form\n- Credential setup form\n- Configuration wizard forms\n\n**Phase 3: CLI Integration**\n- Update CLI commands to use TUI dialogs\n- Add `--interactive` / `--config` flags\n- Implement non-interactive fallback\n\n**Phase 4: Documentation**\n- User guides with screenshots\n- Developer documentation for form creation\n- Example configs for non-interactive use\n\n**Phase 5: Testing**\n- Unit tests for validation logic\n- Integration tests with config files\n- Manual testing on all platforms\n\n## References\n\n- [typdialog Crate](https://crates.io/crates/typdialog) (or similar: dialoguer, inquire)\n- [crossterm](https://crates.io/crates/crossterm) - Terminal manipulation\n- [zeroize](https://crates.io/crates/zeroize) - Secure memory zeroization\n- ADR-004: Hybrid Architecture (Rust/Nushell integration)\n- ADR-011: Nickel Migration (declarative config language)\n- ADR-012: Nushell Plugins (CLI wrapper patterns)\n- Nushell `input` command limitations: [Nushell Book - Input](https://www.nushell.sh/commands/docs/input.html)\n\n---\n\n**Status**: Accepted\n**Last Updated**: 2025-01-08\n**Implementation**: Planned\n**Priority**: High (User onboarding and security)\n**Estimated Complexity**: Moderate
