589 lines
19 KiB
Markdown
589 lines
19 KiB
Markdown
|
|
# 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(®ion) {
|
||
|
|
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
|