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
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:
[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
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
{
HttpServer = {
bind_address | String,
timeout_seconds | Number,
max_connections | Number | optional,
},
}
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
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,
}
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
{
http_server = {
bind_address = "0.0.0.0:8080",
timeout_seconds = 30,
max_connections = 1000,
},
}
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
[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"
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:
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,
}
Using the Generated Structure
1. Display Configuration Form
# Interactive CLI form
typedialog fragments/http_server-section.toml --backend cli
# Web-based form
typedialog-web fragments/http_server-section.toml --port 3000
2. Validate Existing Config
# Validate Nickel syntax
./scripts/validate-nickel.sh < config.ncl
# Convert and validate JSON
./scripts/json-to-nickel.sh < input.json | ./scripts/validate-nickel.sh
3. Generate Config from User Input
# 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
4. Use in Application
// 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);
5. Export to Other Formats
# 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)") | .[]'
Constraint Interpolation
Constraints can be referenced in validators and forms:
In constraints.toml:
[http_server.timeout_seconds]
min = 1
max = 600
In validators:
let max_timeout = {{ constraints.http_server.timeout_seconds.max }};
validate_timeout = fun value => value <= max_timeout
In fragments:
max = {{ constraints.http_server.timeout_seconds.max }}
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:
[[section.authentication.fields]]
name = "jwt_secret"
type = "password"
sensitive = true
encryption_backend = "age" # or: sops, secretumvault, aws-kms, gcp-kms
Supported Encryption Backends:
age- Modern encryption (recommended)sops- Mozilla SOPSsecretumvault- SecretumVault integrationaws-kms- AWS KMSgcp-kms- GCP Cloud KMSazure-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:
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
Extending Generated Structure
Add a New Feature
-
Add schema (
schemas/my_feature.ncl):{ 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
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