Generated Provisioning Output Example
This directory demonstrates the complete output structure generated by the provisioning generator across all 7 layers.
Directory Structure
output-example/
├── config.ncl # Master configuration file
├── constraints.toml # Layer 1: Validation bounds (single source of truth)
├── schemas/ # Layer 2: Type contracts
│ ├── http_server.ncl
│ ├── database.ncl
│ ├── authentication.ncl
│ └── ...
├── validators/ # Layer 3: Validation logic
│ ├── http_server.ncl
│ ├── database.ncl
│ ├── common.ncl
│ └── ...
├── defaults/ # Layer 4: Default values
│ ├── http_server.ncl
│ ├── database.ncl
│ └── ...
├── fragments/ # Layer 5: TypeDialog forms
│ ├── http_server-section.toml
│ ├── database-section.toml
│ ├── authentication-section.toml
│ └── ...
├── scripts/ # Layer 6: Orchestration
│ ├── config.sh
│ ├── config.nu
│ ├── json-to-nickel.sh
│ ├── nickel-to-json.sh
│ ├── validate-nickel.sh
│ └── README.md (orchestration guide)
└── README.md # This file
```text
## 7-Layer Validation Architecture
The provisioning system implements a complete validation stack:
### Layer 1: Constraints (Single Source of Truth)
**File**: `constraints.toml`
Defines bounds and rules for all fields:
```toml
[http_server.bind_address]
min_length = 3
max_length = 100
[http_server.timeout_seconds]
min = 1
max = 600
[database.port]
min = 1
max = 65535
unique = false
[authentication.jwt_secret]
min_length = 32
max_length = 256
```text
**Purpose**:
- Single source of truth for validation rules
- Referenced by validators, forms, and documentation
- Enables constraint interpolation across layers
- Facilitates consistency across multiple validation backends
### Layer 2: Schemas (Type Contracts)
**Directory**: `schemas/`
Nickel type definitions for each domain feature:
**Example**: `schemas/http_server.ncl`
```nickel
{
HttpServer = {
bind_address | String,
timeout_seconds | Number,
max_connections | Number | optional,
},
}
```text
**Purpose**:
- Type-safe configuration definitions
- Interfaces between application and configuration
- Validated by Nickel before use
- Self-documenting code
### Layer 3: Validators (Validation Logic)
**Directory**: `validators/`
Functions that enforce constraints:
**Example**: `validators/http_server.ncl`
```nickel
let validate_bind_address = fun value =>
(std.is_string value) &&
(std.string.length value >= 3) &&
(std.string.length value <= 100);
let validate_timeout_seconds = fun value =>
(std.is_number value) &&
(value >= 1) &&
(value <= 600);
{
validate_bind_address,
validate_timeout_seconds,
}
```text
**Purpose**:
- Enforce constraints defined in Layer 1
- Provide detailed validation error messages
- Can include complex logic (e.g., regex matching)
- Reusable across multiple configs
### Layer 4: Defaults (Default Values)
**Directory**: `defaults/`
Sensible defaults for each feature:
**Example**: `defaults/http_server.ncl`
```nickel
{
http_server = {
bind_address = "0.0.0.0:8080",
timeout_seconds = 30,
max_connections = 1000,
},
}
```text
**Purpose**:
- Provide reasonable configuration starting points
- Reduce user decisions
- Document typical values
- Enable incremental configuration
### Layer 5: Fragments (Form Definitions)
**Directory**: `fragments/`
TypeDialog form fragments for user input:
**Example**: `fragments/http_server-section.toml`
```toml
[section.http_server]
description = "HTTP Server Configuration"
[[section.http_server.fields]]
name = "bind_address"
type = "text"
prompt = "Server bind address"
placeholder = "0.0.0.0:8080"
default = "0.0.0.0:8080"
help = "Format: IP:PORT (e.g., 0.0.0.0:8080)"
required = true
[[section.http_server.fields]]
name = "timeout_seconds"
type = "number"
prompt = "Request timeout"
default = 30
min = 1
max = 600
help = "Maximum seconds to wait for request completion"
```text
**Purpose**:
- Provide user-friendly configuration UI
- Enforce constraints client-side
- Guide users with prompts and help text
- Support multiple backends (CLI, TUI, Web)
### Layer 6: Scripts (Orchestration)
**Directory**: `scripts/`
Automated configuration management:
- **config.sh / config.nu**: Master orchestrator
- **json-to-nickel.sh / json-to-nickel.nu**: Convert JSON → Nickel
- **nickel-to-json.sh / nickel-to-json.nu**: Convert Nickel → JSON
- **validate-nickel.sh / validate-nickel.nu**: Validate Nickel syntax
**Purpose**:
- Automate configuration pipeline
- Convert between formats
- Validate configuration integrity
- Enable CI/CD integration
### Layer 7: Master Config
**File**: `config.ncl`
Integrates all layers:
```nickel
let constraints = import "constraints.toml"
let http_server_schema = import "schemas/http_server.ncl"
let http_server_validator = import "validators/http_server.ncl"
let http_server_defaults = import "defaults/http_server.ncl"
{
http_server = http_server_defaults.http_server
| http_server_schema.HttpServer
| http_server_validator,
}
```text
## Using the Generated Structure
### 1. Display Configuration Form
```bash
# Interactive CLI form
typedialog fragments/http_server-section.toml --backend cli
# Web-based form
typedialog-web fragments/http_server-section.toml --port 3000
```text
### 2. Validate Existing Config
```bash
# Validate Nickel syntax
./scripts/validate-nickel.sh < config.ncl
# Convert and validate JSON
./scripts/json-to-nickel.sh < input.json | ./scripts/validate-nickel.sh
```text
### 3. Generate Config from User Input
```bash
# Collect form input
typedialog fragments/*.toml --backend cli --output config.json
# Convert to Nickel
./scripts/json-to-nickel.sh < config.json > config.ncl
# Validate
./scripts/validate-nickel.sh < config.ncl
```text
### 4. Use in Application
```rust
// Load and parse configuration
let config_str = std::fs::read_to_string("config.ncl")?;
let config: ServiceConfig = nickel::evaluate(&config_str)?;
// Use typed configuration
println!("Server: {}:{}", config.http_server.bind_address);
```text
### 5. Export to Other Formats
```bash
# Export to JSON
./scripts/nickel-to-json.sh < config.ncl > config.json
# Export to YAML
./scripts/nickel-to-json.sh < config.ncl | jq -r 'to_entries | map("\(.key): \(.value)") | .[]'
```text
## Constraint Interpolation
Constraints can be referenced in validators and forms:
**In constraints.toml**:
```toml
[http_server.timeout_seconds]
min = 1
max = 600
```text
**In validators**:
```nickel
let max_timeout = {{ constraints.http_server.timeout_seconds.max }};
validate_timeout = fun value => value <= max_timeout
```text
**In fragments**:
```toml
max = {{ constraints.http_server.timeout_seconds.max }}
```text
This ensures single source of truth for validation bounds.
## Field Types Supported
### Primitive Types
- **Text** - Free-form string input
- **Number** - Numeric value (integer or float)
- **Password** - Sensitive text (encrypted)
- **Confirm** - Boolean yes/no toggle
### Selection Types
- **Select** - Single choice from predefined options
- **MultiSelect** - Multiple selections
### Complex Types
- **Editor** - Multi-line code or text editing
- **Date** - Calendar date picker
- **RepeatingGroup** - Array of structured items
## Sensitive Data Handling
Fields marked as sensitive are automatically encrypted:
```toml
[[section.authentication.fields]]
name = "jwt_secret"
type = "password"
sensitive = true
encryption_backend = "age" # or: sops, secretumvault, aws-kms, gcp-kms
```text
**Supported Encryption Backends**:
- `age` - Modern encryption (recommended)
- `sops` - Mozilla SOPS
- `secretumvault` - SecretumVault integration
- `aws-kms` - AWS KMS
- `gcp-kms` - GCP Cloud KMS
- `azure-kms` - Azure Key Vault
Encrypted fields are:
- Masked in TypeDialog forms
- Decrypted only when needed
- Never logged or stored in plain text
## Configuration Workflow
Typical workflow with generated structure:
```text
1. User runs interactive form
↓
typedialog fragments/*.toml
↓
User input: {http_server: {bind_address: "0.0.0.0:3000"}}
2. Convert to Nickel
↓
./scripts/json-to-nickel.sh < input.json > config.ncl
3. Validate against schema
↓
./scripts/validate-nickel.sh < config.ncl
✓ Valid configuration
4. Use in application
↓
app.load_config("config.ncl")
↓
Server starts on 0.0.0.0:3000
```text
## Extending Generated Structure
### Add a New Feature
1. **Add schema** (`schemas/my_feature.ncl`):
```nickel
{
MyFeature = {
field1 | String,
field2 | Number | optional,
},
}
-
Add validator (
validators/my_feature.ncl):{ validate_field1 = fun value => true, validate_field2 = fun value => true, } -
Add defaults (
defaults/my_feature.ncl):{ my_feature = { field1 = "default", field2 = 42, }, } -
Add fragment (
fragments/my_feature-section.toml):[section.my_feature] [[section.my_feature.fields]] name = "field1" type = "text" -
Add constraints (update
constraints.toml):[my_feature.field1] min_length = 1 max_length = 100 -
Update master config (
config.ncl):let my_feature_schema = import "schemas/my_feature.ncl" # ... include in final config
Testing Configuration
# Test entire pipeline
./scripts/config.sh validate
# Test specific feature
typedialog fragments/http_server-section.toml --backend cli --test
# Test with sample data
echo '{"http_server":{"bind_address":"127.0.0.1:8080"}}' | \
./scripts/json-to-nickel.sh | \
./scripts/validate-nickel.sh
```text
## Documentation and References
- **Nickel Docs**: Type contracts and validation
- **TypeDialog Docs**: Form field types and features
- **Scripts Guide**: Orchestration and conversions (`scripts/README.md`)
## Summary
The 7-layer architecture provides:
✅ **Separation of Concerns**: Each layer has a specific role
✅ **Single Source of Truth**: Constraints defined once, used everywhere
✅ **Type Safety**: Nickel contracts prevent invalid configs
✅ **User-Friendly Forms**: TypeDialog provides intuitive UI
✅ **Automated Validation**: Constraints enforced at multiple layers
✅ **Format Flexibility**: Convert between JSON, TOML, Nickel
✅ **Reusability**: Generic components shared across projects
✅ **Extensibility**: Easy to add features and customize
The generated structure is ready for:
- Production deployment
- CI/CD integration
- Distributed configuration management
- Multi-environment setups