Example: Configuration¶
The configuration document records how a console application is configured
across environments: the settings it retrieves from the Environment API, the
DatabaseConfig registrations that produce its connection strings, the
App.config surface, and the log destinations. Doc gen produces one per
application at docs/applications/<app-slug>/configuration.md.
What reviewers should check¶
- The page states that connection strings are resolved from the Environment API
through each
DatabaseConfig's environment config key rather than stored in<connectionStrings>, and theApp.configsection that follows does not contradict it with a literal connection string. - Every Environment API row names the retrieval method (
GetConfigSettingorGetSecureConfigSetting) and the consuming class, andSecureisYesfor every value retrieved securely. - The database configuration table's
Config namevalues match the Autofac registration names used to resolveIUnitOfWork, and each row's environment config key is the key the instance name is resolved from. App.configsubsections with no entries are omitted rather than left empty;ApplicationHostappears inappSettingsbecause the Environment API host is resolved from it.- The log destination table maps
file0-file4to what this application actually writes, marking unused ids "Not used" instead of inventing content. - The environment variance table contains only verified values and uses
Unknownrather than a guess; a row repeated identically across DEV, TEST, and PROD should be checked against the environment data, not assumed. - Inherited framework statements carry
†so a reviewer can tell application behaviour from framework behaviour.
Example¶
The document below is a complete, correct console-configuration.md for a
fictional .NET Framework console application.
View rendered example — the same document as a real page, so you can compare rendering as well as source.
---
title: Configuration
summary: Environment API settings, database configurations, and app.config surface.
status: draft
owner: Policy Systems Team
last_reviewed: 2026-09-10
---
# Configuration
`SAIF.Policy.RenewalNotice` carries almost no configuration of its own. The
`App.config` deployed with the executable names the Environment API host, the
Oracle managed driver, and the log4net appender; everything that varies by
environment — the database instance behind `policyDb`, the Agency API base
address and key, the notice window, the print vendor drop path, and the summary
mail recipients — is retrieved at run time from the Environment API for the track
the executable is running on. The same binaries therefore run in DEV, TEST, and
PROD without a config transform.
Configuration is retrieved at runtime from the Environment API through `IEnvironmentService`.
Connection strings are **not** stored in `<connectionStrings>`; they are resolved from the database instance name returned for each `DatabaseConfig`'s environment config key.†
## Environment API settings
| Key | Retrieved by | Consuming class | Secure | Varies by environment | Purpose |
| --- | --- | --- | --- | --- | --- |
| `policy.db.instance` | `GetConfigSetting` | `Program` | No | Yes | Oracle instance name behind the `policyDb` `DatabaseConfig` registration. |
| `policy.db.password` | `GetSecureConfigSetting` | `Program` | Yes | Yes | Password for the `POLICY_APP` database user used by the `policyDb` unit of work. |
| `agency.api.baseUrl` | `GetConfigSetting` | `RenewalNoticeApplication` | No | Yes | Base address of `SAIF.Agency.Api`, used to construct the `SAIF.Agency.Api.Client` agency client. |
| `agency.api.apiKey` | `GetSecureConfigSetting` | `RenewalNoticeApplication` | Yes | Yes | API key sent by the agency client on every agency and agent request. |
| `renewalnotice.noticeWindowDays` | `GetConfigSetting` | `NoticeGenerator` | No | No | Default lead time in days applied to the notice window when the notice template does not override it. |
| `renewalnotice.printQueuePath` | `GetConfigSetting` | `NoticeQueueWriter` | No | Yes | UNC path of the print vendor drop folder that generated notice documents are written to. |
| `renewalnotice.notificationRecipients` | `GetConfigSetting` | `RenewalNoticeApplication` | No | Yes | Semicolon-separated addresses for the run summary mail sent by `Finish`. |
| `renewalnotice.healthProbeAgencyNumber` | `GetConfigSetting` | `RenewalNoticeApplication` | No | No | Agency number used for the Agency API health probe in `Initialize`. |
## Database configurations
Each entry is a `DatabaseConfig` passed to `RegisterCommonDependencies` in `RegisterAppDependencies`. `Config name` is the Autofac registration name used to resolve the corresponding `IUnitOfWork`.
| Config name | Type | Environment config key | Database user | Stateless | Server | Purpose |
| --- | --- | --- | --- | --- | --- | --- |
| `policyDb` | `OracleConfig` | `policy.db.instance` | `POLICY_APP` | No | Resolved per track from the Environment API | Reads `POLICY.POLICY_TERM` and `POLICY.NOTICE_TEMPLATE`, and writes `POLICY.RENEWAL_NOTICE` and `POLICY.RENEWAL_NOTICE_QUEUE` through the NHibernate unit of work. |
## app.config settings
### appSettings
| Key | Value | Read by | Purpose |
| --- | --- | --- | --- |
| `ApplicationHost` | `https://environmentapi.example.saif` | `EnvironmentServiceBase` | Environment API host resolution† |
| `ApplicationName` | `SAIF.Policy.RenewalNotice` | `ProgramRunnerBase` | Identifies the application to the Environment API and appears in the header, footer, and summary mail. |
| `AgencyApiTimeoutSeconds` | `30` | `RenewalNoticeApplication` | Request timeout applied to the agency client; a term whose agent lookup exceeds it is skipped and logged to `file2`. |
| `PrintFileExtension` | `.afp` | `NoticeQueueWriter` | Extension of the generated print document expected by the print vendor pickup job. |
### Custom configuration sections
| Section | Purpose |
| --- | --- |
| `oracle.manageddataaccess.client` | Oracle managed driver configuration |
| `hibernate-configuration` | NHibernate dialect (`Oracle10gDialect`), driver, and batch size used by the session factory built from the `policyDb` config |
| `log4net` | Rolling file appender for the application log that sits alongside the `file0`-`file2` destinations |
### Assembly binding redirects
| Assembly | Redirected to | Note |
| --- | --- | --- |
| Newtonsoft.Json | 13.0.0.0 | Aligns the version pulled in by `SAIF.Web.API.Clients` with the one the agency client contracts are compiled against |
| Oracle.ManagedDataAccess | 4.122.21.1 | Pins the managed driver version that `SAIF.Framework.Data.NHibernate` was built against |
| System.Runtime.CompilerServices.Unsafe | 6.0.0.0 | Required by the HTTP stack used underneath `SAIF.Web.API.Clients` |
## Log file destinations
Log outputs are resolved from **machine-level environment variables** `file0`–`file4`, scanned by `ConsoleLogService` at construction. Each variable's value is a log file path.†
| Environment variable | Log id | Content written by this application |
| --- | --- | --- |
| `file0` | `LogType.File0` | Run control log: header block, resolved arguments, notice window, per-100-notice progress lines, totals, and fatal errors |
| `file1` | `LogType.File1` | Notice detail: one line per generated notice with policy number, renewal effective date, agency number, servicing agent, and delivery channel; dry-run lines carry a `WHATIF` marker |
| `file2` | `LogType.File2` | Exception detail: one line per skipped or failed term with policy number, agency number, and the exception message |
| `file3` | `LogType.File3` | Not used |
| `file4` | `LogType.File4` | Not used |
## Environment variance
| Setting | DEV | TEST | PROD | Notes |
| --- | --- | --- | --- | --- |
| `policy.db.instance` | `POLICYDEV` | `POLICYTST` | `POLICYPRD` | Same `POLICY_APP` user in all three; only the instance differs. |
| `agency.api.baseUrl` | `https://agencyapi-dev.example.saif/` | `https://agencyapi-test.example.saif/` | `https://agencyapi.example.saif/` | DEV and TEST point at the corresponding `SAIF.Agency.Api` deployments. |
| `renewalnotice.noticeWindowDays` | `45` | `45` | `45` | Same in all tracks; the `NonRenewal` template overrides it with the statutory 60 days. |
| `renewalnotice.printQueuePath` | `\\printdev\drop\renewalnotice` | `\\printtest\drop\renewalnotice` | `\\printprd\drop\renewalnotice` | The DEV and TEST shares are drained by a cleanup job rather than by the print vendor. |
| `renewalnotice.notificationRecipients` | `policysystems-dev@example.saif` | `policysystems-test@example.saif` | `batchops@example.saif;policysystems-oncall@example.saif` | Only PROD notifies operations. |
| `agency.api.apiKey` | Unknown | Unknown | Unknown | Retrieved with `GetSecureConfigSetting`; values are not readable from the environment data. |
## Related documentation
- [Application index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Run lifecycle](run-lifecycle.md)
- [Arguments](arguments.md)
- [Dependencies](dependencies.md)
- [Operations and processes](operations-processes.md)
- [Business rules](business-rules.md)
- [Data model](data-model.md)
- [Operational runbook](operational-runbook.md)
- [Tech debt](tech-debt.md)
## Sources
- `src/SAIF.Policy.RenewalNotice/App.config`
- `src/SAIF.Policy.RenewalNotice/Program.cs`
- `src/SAIF.Policy.RenewalNotice/RenewalNoticeApplication.cs`
- `src/SAIF.Policy.RenewalNotice/NoticeQueueWriter.cs`
- `deploy/environment-settings/renewalnotice.settings.json`