Configuration System Overview
The @tagna/udiot configuration system provides a layered, type-safe approach to managing application settings. Values are assembled from multiple sources in a defined precedence order, every value carries provenance metadata, and schema violations are surfaced before your application starts.
Key Concepts
Layered configuration — values flow through discrete layers. A higher layer always wins over a lower one, but the system records every layer that touched a key so you can audit the final value.
Schema-first design — you declare what your configuration looks like using TypeScript classes decorated with @AIConfig and @AIEnv. The framework derives environment variable names, types, validation rules, and secret-provider bindings automatically from those decorations.
Convention-based discovery — the ConfigConventionSystem scans a config/ directory for files matching *.config.ts and loads them automatically. .env, .env.{environment}, .env.local, and .env.{environment}.local files are loaded in order so local overrides never need to be committed.
Drift detection — after loading, the system can report keys that exist in the environment but have no corresponding schema field, as well as required keys that are absent. This catches configuration drift before it causes runtime errors.
Provenance tracing — every resolved value is stamped with the layer name, source identifier, and timestamp at which it was written. Sensitive values are redacted in provenance output so trace logs are safe to share.
Precedence Order (highest to lowest)
| # | Layer | Source |
|---|---|---|
| 1 | overrides |
Programmatic runtime overrides passed to EnvironmentConfigManager |
| 2 | secrets |
Values fetched from the configured SecretProvider |
| 3 | environment |
process.env variables matched by the env key on each field |
| 4 | manifest |
YAML/JSON config file discovered in the config/ directory |
| 5 | schema-defaults |
Default values declared in @AIEnv({ default: … }) or as class property initialisers |
Architecture Summary
┌─────────────────────────────────────────────────────┐
│ Your Application │
└──────────────────────┬──────────────────────────────┘
│ builds
▼
┌─────────────────────────┐
│ ConfigSchema(s) │ ← @AIConfig / @AIEnv decorators
└────────────┬────────────┘
│ passed to
▼
┌──────────────────────────────┐
│ EnvironmentConfigManager │
│ ┌────────────────────────┐ │
│ │ schema-defaults layer │ │
│ │ environment layer │ │
│ │ manifest layer │ │
│ │ secrets layer │ │
│ │ overrides layer │ │
│ └────────────────────────┘ │
└──────────────┬───────────────┘
│ returns
▼
┌─────────────────────────────┐
│ ConfigLoadResult │
│ values / layers / provenance│
│ missingRequired / violations│
└─────────────────────────────┘
Related Documentation
- Schema Decorators —
@AIConfig,@AIEnv,@AISuggested,ConfigFieldSchema,ConfigPolicy - Environment Manager —
EnvironmentConfigManager, layer snapshots, provenance maps - Secret Providers —
EnvSecretProvider,FileSecretProvider,CompositeSecretProvider - CLI Tooling —
validate,diff,scaffold,tracecommands
Pitfalls
- The
manifestlayer (YAML/JSON file) sits below secrets and environment variables. Do not store secrets in manifest files — they belong in secret providers. - Convention-based
.envloading uses a simple line parser. It does not support multi-line values or variable interpolation. For complex values use a config file or environment variable. - Re-running
buildConfigSchemaon the same class after the module is loaded a second time (e.g., with hot-reload) will produce a fresh schema but will not automatically invalidate a previously constructedEnvironmentConfigManager. Construct a new manager instance after a schema reload.