Configuration Management
Configuration Management
Relevant source files
The following files were used as context for generating this wiki page:
The Config module provides a standardized, dictionary-style configuration system designed to be shared across all microservices. It implements a Load-Cache-Get pattern that ensures high performance by avoiding database hits on the hot path while maintaining a DB-agnostic architecture through the use of ports.
Data Shape: IConfigEntity
Configuration data is modeled as a simple key-value pair system. Each configuration entry is represented by the IConfigEntity interface, which mirrors a standard configuration table structure where every row represents a single setting.
| Property | Type | Description |
|---|---|---|
key | string | The unique identifier for the setting (e.g., "brevo_api_key"). |
value | string | null | The raw text value. null indicates the key exists but is not yet set. |
label_key | string (optional) | i18n key for UI display titles. |
description_key | string (optional) | i18n key for UI display descriptions. |
Sources: src/config/iconfig-entity.ts:10-19
The ConfigRepositoryPort Contract
To maintain the SDK's database-agnostic philosophy, the ConfigLoader does not interact with a database directly. Instead, it depends on the ConfigRepositoryPort. Consuming microservices must provide an adapter that implements this interface using their specific Data Access Layer (DAL) or raw SQL.
Code
Sources: src/ports/config-repository-port.ts:8-14, src/config/config-loader.ts:8-18
ConfigLoader Lifecycle
The ConfigLoader manages an in-memory cache to ensure that once configuration is loaded, access is instantaneous.
1. Load & Cache
The load() method must be called once at application startup src/config/config-loader.ts:24-31. It fetches all rows via the ConfigRepositoryPort.findAll() method and populates an internal Map src/config/config-loader.ts:25-29.
2. Access (Get)
Once loaded, values are retrieved from the Map. If get() or require() is called before load(), the loader throws an error to prevent inconsistent application states src/config/config-loader.ts:38-40.
3. Invalidation
The invalidate() method clears the internal cache src/config/config-loader.ts:86-88. This forces the next call to load() to perform a fresh fetch from the underlying data source src/config/config-loader.ts:13-13.
Data Flow Diagram
Code
Sources: src/config/config-loader.ts:15-89, src/config/tests/config-loader.test.ts:22-81
Typed Accessors and Error Handling
Since the database stores all values as TEXT src/config/iconfig-entity.ts:13-13, the ConfigLoader provides utilities for type conversion and mandatory field validation.
Accessor Methods
| Method | Return Type | Behavior on Missing/Null |
|---|---|---|
get(key) | string | null | Returns null. src/config/config-loader.ts:37-42 |
require(key) | string | Throws Error. src/config/config-loader.ts:47-53 |
getTyped(key, conv) | T | null | Returns null. src/config/config-loader.ts:59-63 |
requireTyped(key, conv) | T | Throws Error. src/config/config-loader.ts:68-71 |
Type Conversion
The getTyped and requireTyped methods accept a converter function (e.g., Number, Boolean, or a custom parser) to transform the raw string into the desired runtime type src/config/config-loader.ts:59-71.
Error Handling
The loader enforces strict presence for "required" keys. If require() or requireTyped() encounters a null or empty string, it throws an error: Missing required config key: <key> src/config/config-loader.ts:49-51.
Sources: src/config/config-loader.ts:47-71, src/config/tests/config-loader.test.ts:42-59