# ADR-013: Typdialog Web UI Backend Integration for Interactive Configuration

## Status

**Accepted** - 2025-01-08

## Context

The provisioning system requires interactive user input for configuration workflows, workspace initialization, credential setup, and guided deployment scenarios. The system architecture combines Rust (performance-critical), Nushell (scripting), and Nickel (declarative configuration), creating challenges for interactive form-based input and multi-user collaboration.

### The Interactive Configuration Problem

**Current limitations**:

1. **Nushell CLI**: Terminal-only interaction
   - `input` command: Single-line text prompts only
   - No form validation, no complex multi-field forms
   - Limited to single-user, terminal-bound workflows
   - User experience: Basic and error-prone

2. **Nickel**: Declarative configuration language
   - Cannot handle interactive prompts (by design)
   - Pure evaluation model (no side effects)
   - Forms must be defined statically, not interactively
   - No runtime user interaction

3. **Existing Solutions**: Inadequate for modern infrastructure provisioning
   - **Shell-based prompts**: Error-prone, no validation, single-user
   - **Custom web forms**: High maintenance, inconsistent UX
   - **Separate admin panels**: Disconnected from IaC workflow
   - **Terminal-only TUI**: Limited to SSH sessions, no collaboration

### Use Cases Requiring Interactive Input

1. **Workspace Initialization**:
   ```nushell
   # Current: Error-prone prompts
   let workspace_name = input "Workspace name: "
   let provider = input "Provider (aws/azure/oci): "
   # No validation, no autocomplete, no guidance
   ```

2. **Credential Setup**:
   ```nushell
   # Current: Insecure and basic
   let api_key = input "API Key: "  # Shows in terminal history
   let region = input "Region: "    # No validation
   ```

3. **Configuration Wizards**:
   - Database connection setup (host, port, credentials, SSL)
   - Network configuration (CIDR blocks, subnets, gateways)
   - Security policies (encryption, access control, audit)

4. **Guided Deployments**:
   - Multi-step infrastructure provisioning
   - Service selection with dependencies
   - Environment-specific overrides

### Requirements for Interactive Input System

- ✅ **Terminal UI widgets**: Text input, password, select, multi-select, confirm
- ✅ **Validation**: Type checking, regex patterns, custom validators
- ✅ **Security**: Password masking, sensitive data handling
- ✅ **User Experience**: Arrow key navigation, autocomplete, help text
- ✅ **Composability**: Chain multiple prompts into forms
- ✅ **Error Handling**: Clear validation errors, retry logic
- ✅ **Rust Integration**: Native Rust library (no subprocess overhead)
- ✅ **Cross-Platform**: Works on Linux, macOS, Windows

## Decision

Integrate **typdialog** with its **Web UI backend** as the standard interactive configuration interface for the provisioning platform. The major achievement of typdialog is not the TUI - it is the Web UI backend that enables browser-based forms, multi-user collaboration, and seamless integration with the provisioning orchestrator.

### Architecture Diagram

```
┌─────────────────────────────────────────┐
│   Nushell Script                        │
│                                         │
│   provisioning workspace init           │
│   provisioning config setup             │
│   provisioning deploy guided            │
└────────────┬────────────────────────────┘
             │
             ▼
┌─────────────────────────────────────────┐
│   Rust CLI Handler                      │
│   (provisioning/core/cli/)              │
│                                         │
│   - Parse command                       │
│   - Determine if interactive needed     │
│   - Invoke TUI dialog module            │
└────────────┬────────────────────────────┘
             │
             ▼
┌─────────────────────────────────────────┐
│   TUI Dialog Module                     │
│   (typdialog wrapper)                   │
│                                         │
│   - Form definition (validation rules)  │
│   - Widget rendering (text, select)     │
│   - User input capture                  │
│   - Validation execution                │
│   - Result serialization (JSON/TOML)    │
└────────────┬────────────────────────────┘
             │
             ▼
┌─────────────────────────────────────────┐
│   typdialog Library                     │
│                                         │
│   - Terminal rendering (crossterm)      │
│   - Event handling (keyboard, mouse)    │
│   - Widget state management             │
│   - Input validation engine             │
└────────────┬────────────────────────────┘
             │
             ▼
┌─────────────────────────────────────────┐
│   Terminal (stdout/stdin)               │
│                                         │
│   ✅ Rich TUI with validation           │
│   ✅ Secure password input              │
│   ✅ Guided multi-step forms            │
└─────────────────────────────────────────┘
```

### Implementation Characteristics

**CLI Integration Provides**:

- ✅ Native Rust commands with TUI dialogs
- ✅ Form-based input for complex configurations
- ✅ Validation rules defined in Rust (type-safe)
- ✅ Secure input (password masking, no history)
- ✅ Error handling with retry logic
- ✅ Serialization to Nickel/TOML/JSON

**TUI Dialog Library Handles**:

- ✅ Terminal UI rendering and event loop
- ✅ Widget management (text, select, checkbox, confirm)
- ✅ Input validation and error display
- ✅ Navigation (arrow keys, tab, enter)
- ✅ Cross-platform terminal compatibility

## Rationale

### Why TUI Dialog Integration Is Required

| Aspect | Shell Prompts (current) | Web Forms | TUI Dialog (chosen) |
|--------|-------------------------|-----------|---------------------|
| **User Experience** | ❌ Basic text only | ✅ Rich UI | ✅ Rich TUI |
| **Validation** | ❌ Manual, error-prone | ✅ Built-in | ✅ Built-in |
| **Security** | ❌ Plain text, history | ⚠️ Network risk | ✅ Secure terminal |
| **Setup Complexity** | ✅ None | ❌ Server required | ✅ Minimal |
| **Terminal Workflow** | ✅ Native | ❌ Browser switch | ✅ Native |
| **Offline Support** | ✅ Always | ❌ Requires server | ✅ Always |
| **Dependencies** | ✅ None | ❌ Web stack | ✅ Single crate |
| **Error Handling** | ❌ Manual | ⚠️ Complex | ✅ Built-in retry |

### The Nushell Limitation

Nushell's `input` command is limited:

```nushell
# Current: No validation, no security
let password = input "Password: "  # ❌ Shows in terminal
let region = input "AWS Region: "   # ❌ No autocomplete/validation

# Cannot do:
# - Multi-select from options
# - Conditional fields (if X then ask Y)
# - Password masking
# - Real-time validation
# - Autocomplete/fuzzy search
```

### The Nickel Constraint

Nickel is declarative and cannot prompt users:

```nickel
# Nickel defines what the config looks like, NOT how to get it
{
  database = {
    host | String,
    port | Number,
    credentials | { username: String, password: String },
  }
}

# Nickel cannot:
# - Prompt user for values
# - Show interactive forms
# - Validate input interactively
```

### Why Rust + TUI Dialog Is The Solution

**Rust provides**:
- Native terminal control (crossterm, termion)
- Type-safe form definitions
- Validation rules as functions
- Secure memory handling (password zeroization)
- Performance (no subprocess overhead)

**TUI Dialog provides**:
- Widget library (text, select, multi-select, confirm)
- Event loop and rendering
- Validation framework
- Error display and retry logic

**Integration enables**:
- Nushell calls Rust CLI → Shows TUI dialog → Returns validated config
- Nickel receives validated config → Type checks → Merges with defaults

## Consequences

### Positive

- **User Experience**: Professional TUI with validation and guidance
- **Security**: Password masking, sensitive data protection, no terminal history
- **Validation**: Type-safe rules enforced before config generation
- **Developer Experience**: Reusable form components across CLI commands
- **Error Handling**: Clear validation errors with retry options
- **Offline First**: No network dependencies for interactive input
- **Terminal Native**: Fits CLI workflow, no context switching
- **Maintainability**: Single library for all interactive input

### Negative

- **Terminal Dependency**: Requires interactive terminal (not scriptable)
- **Learning Curve**: Developers must learn TUI dialog patterns
- **Library Lock-in**: Tied to specific TUI library API
- **Testing Complexity**: Interactive tests require terminal mocking
- **Non-Interactive Fallback**: Need alternative for CI/CD and scripts

### Mitigation Strategies

**Non-Interactive Mode**:
```rust
// Support both interactive and non-interactive
if terminal::is_interactive() {
    // Show TUI dialog
    let config = show_workspace_form()?;
} else {
    // Use config file or CLI args
    let config = load_config_from_file(args.config)?;
}
```

**Testing**:
```rust
// Unit tests: Test form validation logic (no TUI)
#[test]
fn test_validate_workspace_name() {
    assert!(validate_name("my-workspace").is_ok());
    assert!(validate_name("invalid name!").is_err());
}

// Integration tests: Use mock terminal or config files
```

**Scriptability**:
```bash
# Batch mode: Provide config via file
provisioning workspace init --config workspace.toml

# Interactive mode: Show TUI dialog
provisioning workspace init --interactive
```

**Documentation**:
- Form schemas documented in `docs/`
- Config file examples provided
- Screenshots of TUI forms in guides

## Alternatives Considered

### Alternative 1: Shell-Based Prompts (Current State)

**Pros**: Simple, no dependencies
**Cons**: No validation, poor UX, security risks
**Decision**: REJECTED - Inadequate for production use

### Alternative 2: Web-Based Forms

**Pros**: Rich UI, well-known patterns
**Cons**: Requires server, network dependency, context switch
**Decision**: REJECTED - Too complex for CLI tool

### Alternative 3: Custom TUI Per Use Case

**Pros**: Tailored to each need
**Cons**: High maintenance, code duplication, inconsistent UX
**Decision**: REJECTED - Not sustainable

### Alternative 4: External Form Tool (dialog, whiptail)

**Pros**: Mature, cross-platform
**Cons**: Subprocess overhead, limited validation, shell escaping issues
**Decision**: REJECTED - Poor Rust integration

### Alternative 5: Text-Based Config Files Only

**Pros**: Fully scriptable, no interactive complexity
**Cons**: Steep learning curve, no guidance for new users
**Decision**: REJECTED - Poor user onboarding experience

## Implementation Details

### Form Definition Pattern

```rust
use typdialog::Form;

pub fn workspace_initialization_form() -> Result<WorkspaceConfig> {
    let form = Form::new("Workspace Initialization")
        .add_text_input("name", "Workspace Name")
            .required()
            .validator(|s| validate_workspace_name(s))
        .add_select("provider", "Cloud Provider")
            .options(&["aws", "azure", "oci", "local"])
            .required()
        .add_text_input("region", "Region")
            .default("us-west-2")
            .validator(|s| validate_region(s))
        .add_password("admin_password", "Admin Password")
            .required()
            .min_length(12)
        .add_confirm("enable_monitoring", "Enable Monitoring?")
            .default(true);

    let responses = form.run()?;

    // Convert to strongly-typed config
    let config = WorkspaceConfig {
        name: responses.get_string("name")?,
        provider: responses.get_string("provider")?.parse()?,
        region: responses.get_string("region")?,
        admin_password: responses.get_password("admin_password")?,
        enable_monitoring: responses.get_bool("enable_monitoring")?,
    };

    Ok(config)
}
```

### Integration with Nickel

```rust
// 1. Get validated input from TUI dialog
let config = workspace_initialization_form()?;

// 2. Serialize to TOML/JSON
let config_toml = toml::to_string(&config)?;

// 3. Write to workspace config
fs::write("workspace/config.toml", config_toml)?;

// 4. Nickel merges with defaults
// nickel export workspace/main.ncl --format json
// (uses workspace/config.toml as input)
```

### CLI Command Structure

```rust
// provisioning/core/cli/src/commands/workspace.rs

#[derive(Parser)]
pub enum WorkspaceCommand {
    Init {
        #[arg(long)]
        interactive: bool,

        #[arg(long)]
        config: Option<PathBuf>,
    },
}

pub fn handle_workspace_init(args: InitArgs) -> Result<()> {
    if args.interactive || terminal::is_interactive() {
        // Show TUI dialog
        let config = workspace_initialization_form()?;
        config.save("workspace/config.toml")?;
    } else if let Some(config_path) = args.config {
        // Use provided config
        let config = WorkspaceConfig::load(config_path)?;
        config.save("workspace/config.toml")?;
    } else {
        bail!("Either --interactive or --config required");
    }

    // Continue with workspace setup
    Ok(())
}
```

### Validation Rules

```rust
pub fn validate_workspace_name(name: &str) -> Result<(), String> {
    // Alphanumeric, hyphens, 3-32 chars
    let re = Regex::new(r"^[a-z0-9-]{3,32}$").unwrap();
    if !re.is_match(name) {
        return Err("Name must be 3-32 lowercase alphanumeric chars with hyphens".into());
    }
    Ok(())
}

pub fn validate_region(region: &str) -> Result<(), String> {
    const VALID_REGIONS: &[&str] = &["us-west-1", "us-west-2", "us-east-1", "eu-west-1"];
    if !VALID_REGIONS.contains(&region) {
        return Err(format!("Invalid region. Must be one of: {}", VALID_REGIONS.join(", ")));
    }
    Ok(())
}
```

### Security: Password Handling

```rust
use zeroize::Zeroizing;

pub fn get_secure_password() -> Result<Zeroizing<String>> {
    let form = Form::new("Secure Input")
        .add_password("password", "Password")
            .required()
            .min_length(12)
            .validator(password_strength_check);

    let responses = form.run()?;

    // Password automatically zeroized when dropped
    let password = Zeroizing::new(responses.get_password("password")?);

    Ok(password)
}
```

## Testing Strategy

**Unit Tests**:
```rust
#[test]
fn test_workspace_name_validation() {
    assert!(validate_workspace_name("my-workspace").is_ok());
    assert!(validate_workspace_name("UPPERCASE").is_err());
    assert!(validate_workspace_name("ab").is_err()); // Too short
}
```

**Integration Tests**:
```rust
// Use non-interactive mode with config files
#[test]
fn test_workspace_init_non_interactive() {
    let config = WorkspaceConfig {
        name: "test-workspace".into(),
        provider: Provider::Local,
        region: "us-west-2".into(),
        admin_password: "secure-password-123".into(),
        enable_monitoring: true,
    };

    config.save("/tmp/test-config.toml").unwrap();

    let result = handle_workspace_init(InitArgs {
        interactive: false,
        config: Some("/tmp/test-config.toml".into()),
    });

    assert!(result.is_ok());
}
```

**Manual Testing**:
```bash
# Test interactive flow
cargo build --release
./target/release/provisioning workspace init --interactive

# Test validation errors
# - Try invalid workspace name
# - Try weak password
# - Try invalid region
```

## Configuration Integration

**CLI Flag**:
```toml
# provisioning/config/config.defaults.toml
[ui]
interactive_mode = "auto"  # "auto" | "always" | "never"
dialog_theme = "default"   # "default" | "minimal" | "colorful"
```

**Environment Override**:
```bash
# Force non-interactive mode (for CI/CD)
export PROVISIONING_INTERACTIVE=false

# Force interactive mode
export PROVISIONING_INTERACTIVE=true
```

## Documentation Requirements

**User Guides**:
- `docs/user/interactive-configuration.md` - How to use TUI dialogs
- `docs/guides/workspace-setup.md` - Workspace initialization with screenshots

**Developer Documentation**:
- `docs/development/tui-forms.md` - Creating new TUI forms
- Form definition best practices
- Validation rule patterns

**Configuration Schema**:
```nickel
# provisioning/schemas/workspace.ncl
{
  WorkspaceConfig = {
    name
      | doc "Workspace identifier (3-32 alphanumeric chars with hyphens)"
      | String,
    provider
      | doc "Cloud provider"
      | [| 'aws, 'azure, 'oci, 'local |],
    region
      | doc "Deployment region"
      | String,
    admin_password
      | doc "Admin password (min 12 characters)"
      | String,
    enable_monitoring
      | doc "Enable monitoring services"
      | Bool,
  }
}
```

## Migration Path

**Phase 1: Add Library**
- Add typdialog dependency to `provisioning/core/cli/Cargo.toml`
- Create TUI dialog wrapper module
- Implement basic text/select widgets

**Phase 2: Implement Forms**
- Workspace initialization form
- Credential setup form
- Configuration wizard forms

**Phase 3: CLI Integration**
- Update CLI commands to use TUI dialogs
- Add `--interactive` / `--config` flags
- Implement non-interactive fallback

**Phase 4: Documentation**
- User guides with screenshots
- Developer documentation for form creation
- Example configs for non-interactive use

**Phase 5: Testing**
- Unit tests for validation logic
- Integration tests with config files
- Manual testing on all platforms

## References

- [typdialog Crate](https://crates.io/crates/typdialog) (or similar: dialoguer, inquire)
- [crossterm](https://crates.io/crates/crossterm) - Terminal manipulation
- [zeroize](https://crates.io/crates/zeroize) - Secure memory zeroization
- ADR-004: Hybrid Architecture (Rust/Nushell integration)
- ADR-011: Nickel Migration (declarative config language)
- ADR-012: Nushell Plugins (CLI wrapper patterns)
- Nushell `input` command limitations: [Nushell Book - Input](https://www.nushell.sh/commands/docs/input.html)

---

**Status**: Accepted
**Last Updated**: 2025-01-08
**Implementation**: Planned
**Priority**: High (User onboarding and security)
**Estimated Complexity**: Moderate
