Skip to content

docs: DOC-07 CONFIGURATION_REFERENCE appsettings schema (#874)#887

Merged
Chris0Jeky merged 6 commits intomainfrom
docs/doc-07-config-reference
Apr 22, 2026
Merged

docs: DOC-07 CONFIGURATION_REFERENCE appsettings schema (#874)#887
Chris0Jeky merged 6 commits intomainfrom
docs/doc-07-config-reference

Conversation

@Chris0Jeky
Copy link
Copy Markdown
Owner

Summary

Closes #874. Adds docs/platform/CONFIGURATION_REFERENCE.md, a complete reference for every configuration knob the Taskdeck backend exposes:

  • Every section in backend/src/Taskdeck.Api/appsettings.json documented with key, type, default, description, and required flag.
  • All typed settings classes under backend/src/Taskdeck.Application/Services/*Settings.cs mapped to their JSON hierarchies.
  • Sections covered: JWT, GitHub OAuth, OIDC, MFA, LLM (provider + tool calling + quota + kill switch + abuse detection), Workers, Outbound webhook security, CORS, Forwarded headers, Rate limiting, Cache, SignalR backplane, Security headers, Observability/Sentry/Telemetry/Analytics, Connection strings, Export/import, First run, Development sandbox, Logging.
  • Environment variable override conventions (Section__SubKey, array indices, ASP.NET Core host vars) plus the complete list of TASKDECK_* compose variables from deploy/docker-compose.yml and deploy/.env.example.
  • Defaults and development overrides are tracked in the same row where they differ (for example rate limiting).
  • Cross-linked from CLAUDE.md (Key Docs), docs/platform/README.md, and deploy/.env.example.

Every setting is grounded in a real code path — each row either maps to a *Settings class constructor default or to an explicit GetSection/GetValue call in the backend. No invented keys.

Test plan

  • Every documented key verified against appsettings.json, appsettings.Development.json, or a GetSection("...")/GetValue<...>("...") call in backend/src/.
  • Default values spot-checked against the corresponding settings-class constructor.
  • Env-var format follows ASP.NET Core __ convention.
  • No secret values embedded — only key names and types.
  • CI green (docs-only change, but verify ci-required.yml).

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 910a8d2c27

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +3 to +5
Complete reference for Taskdeck backend configuration (`appsettings.json`,
environment variables, and Docker Compose variables). Every key documented
here maps to a real code path in `backend/src/` — if you see a setting here
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Document McpServer:DefaultUserId in config reference

The doc claims this is a complete backend configuration reference, but it omits McpServer:DefaultUserId, which is actively read in backend/src/Taskdeck.Infrastructure/Mcp/StdioUserContextProvider.cs. In MCP stdio mode, this key controls which user identity is used; without documenting it, operators can unknowingly run tools against the fallback “first user in DB,” which risks applying actions to the wrong account in multi-user databases.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive configuration reference document (docs/platform/CONFIGURATION_REFERENCE.md) that details all backend settings, including JWT authentication, LLM providers, worker configurations, and rate limiting. It also updates CLAUDE.md, deploy/.env.example, and the platform README to link to this new resource. Review feedback identified missing C# types in the conventions section and a typo in the default Gemini model version, which should be corrected to ensure accuracy and prevent potential runtime errors.


## Conventions

- **Type** columns use C# types (`string`, `int`, `bool`, `double`, `int[]`).
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The list of C# types used in the reference is missing long, string[], and object, which are used later in the document (e.g., lines 126, 180, and 194). Updating this list ensures all types used in the tables are defined in the conventions section.

Suggested change
- **Type** columns use C# types (`string`, `int`, `bool`, `double`, `int[]`).
- **Type** columns use C# types (string, int, long, bool, double, int[], string[], object).

| `Llm:OpenAi:TimeoutSeconds` | `int` | `30` | `HttpClient.Timeout` applied to the OpenAI provider. Values `<= 0` fall back to 30. | No |
| `Llm:Gemini:ApiKey` | `string` | `""` | Gemini API key. Required to use the Gemini provider. Store as a secret. | Only for `Llm:Provider = Gemini` |
| `Llm:Gemini:BaseUrl` | `string` | `https://generativelanguage.googleapis.com/v1beta` | Gemini API base URL. | No |
| `Llm:Gemini:Model` | `string` | `gemini-2.5-flash` | Model identifier. | No |
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The default model gemini-2.5-flash appears to be a typo. Google's current models are gemini-1.5-flash or the recently announced gemini-2.0-flash; version 2.5 does not exist. This typo is also present in the underlying code (LlmProviderSettings.cs) and appsettings.json. Correcting it here and in the code will prevent 404 errors when the Gemini provider is activated.

Suggested change
| `Llm:Gemini:Model` | `string` | `gemini-2.5-flash` | Model identifier. | No |
| Llm:Gemini:Model | string | gemini-1.5-flash | Model identifier. | No |

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a centralized backend configuration reference document to reduce the need for developers/operators to reverse-engineer appsettings.json and settings bindings from source.

Changes:

  • Add docs/platform/CONFIGURATION_REFERENCE.md documenting backend configuration keys, defaults, and env var/Docker Compose mappings.
  • Cross-link the new configuration reference from existing docs (CLAUDE.md, docs/platform/README.md) and deploy/.env.example.
  • Add introductory guidance in deploy/.env.example pointing to the full reference.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
docs/platform/README.md Adds a pointer to the new configuration reference doc.
docs/platform/CONFIGURATION_REFERENCE.md New comprehensive configuration reference for backend settings, env var overrides, and Docker Compose variables.
deploy/.env.example Adds header comments linking to the configuration reference.
CLAUDE.md Adds the configuration reference to “Key Docs”.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +87 to +91
is blank, **JWT authentication is not registered** and all authenticated
endpoints return 401 (`AuthenticationRegistration.cs`). In packaged
non-development runs, `FirstRunBootstrapper.EnsureJwtSecret` generates a
random 32-byte base64 secret into `appsettings.local.json` when the key is
missing or equal to the development placeholder.
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The note here says that when Jwt settings are missing/invalid, JWT auth is not registered and authenticated endpoints will return 401. In the current startup pipeline, app.UseAuthentication() is always enabled (see PipelineConfiguration.ConfigureTaskdeckPipeline), so if AddTaskdeckAuthentication short-circuits, the app will fail to start due to missing authentication services rather than returning 401. Please update this section to reflect the actual behavior (startup failure / misconfiguration error), or adjust the code so auth services are still registered even when JWT is disabled.

Suggested change
is blank, **JWT authentication is not registered** and all authenticated
endpoints return 401 (`AuthenticationRegistration.cs`). In packaged
non-development runs, `FirstRunBootstrapper.EnsureJwtSecret` generates a
random 32-byte base64 secret into `appsettings.local.json` when the key is
missing or equal to the development placeholder.
is blank, **JWT authentication is not registered** (`AuthenticationRegistration.cs`).
Because the startup pipeline always enables authentication middleware
(`PipelineConfiguration.cs`), this results in an authentication
misconfiguration/startup failure rather than authenticated endpoints simply
returning 401. In packaged non-development runs,
`FirstRunBootstrapper.EnsureJwtSecret` generates a random 32-byte base64
secret into `appsettings.local.json` when the key is missing or equal to the
development placeholder.

Copilot uses AI. Check for mistakes.
Comment on lines +158 to +162
| `Llm:OpenAi:TimeoutSeconds` | `int` | `30` | `HttpClient.Timeout` applied to the OpenAI provider. Values `<= 0` fall back to 30. | No |
| `Llm:Gemini:ApiKey` | `string` | `""` | Gemini API key. Required to use the Gemini provider. Store as a secret. | Only for `Llm:Provider = Gemini` |
| `Llm:Gemini:BaseUrl` | `string` | `https://generativelanguage.googleapis.com/v1beta` | Gemini API base URL. | No |
| `Llm:Gemini:Model` | `string` | `gemini-2.5-flash` | Model identifier. | No |
| `Llm:Gemini:TimeoutSeconds` | `int` | `30` | `HttpClient.Timeout` applied to the Gemini provider. Values `<= 0` fall back to 30. | No |
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TimeoutSeconds is documented as falling back to 30 when set to <= 0, but LlmProviderSelectionPolicy treats TimeoutSeconds <= 0 as invalid provider configuration and will fall back to the Mock provider instead. Please update the docs to reflect that TimeoutSeconds must be > 0 to use OpenAI/Gemini (the 30s fallback is only applied when configuring the HttpClient, not as an override that makes an invalid provider usable).

Suggested change
| `Llm:OpenAi:TimeoutSeconds` | `int` | `30` | `HttpClient.Timeout` applied to the OpenAI provider. Values `<= 0` fall back to 30. | No |
| `Llm:Gemini:ApiKey` | `string` | `""` | Gemini API key. Required to use the Gemini provider. Store as a secret. | Only for `Llm:Provider = Gemini` |
| `Llm:Gemini:BaseUrl` | `string` | `https://generativelanguage.googleapis.com/v1beta` | Gemini API base URL. | No |
| `Llm:Gemini:Model` | `string` | `gemini-2.5-flash` | Model identifier. | No |
| `Llm:Gemini:TimeoutSeconds` | `int` | `30` | `HttpClient.Timeout` applied to the Gemini provider. Values `<= 0` fall back to 30. | No |
| `Llm:OpenAi:TimeoutSeconds` | `int` | `30` | `HttpClient.Timeout` applied to the OpenAI provider. Must be `> 0` for the OpenAI provider configuration to be valid; if `HttpClient.Timeout` is being configured and the value is `<= 0`, `30` is used there, but that fallback does not make an invalid provider configuration usable. | No |
| `Llm:Gemini:ApiKey` | `string` | `""` | Gemini API key. Required to use the Gemini provider. Store as a secret. | Only for `Llm:Provider = Gemini` |
| `Llm:Gemini:BaseUrl` | `string` | `https://generativelanguage.googleapis.com/v1beta` | Gemini API base URL. | No |
| `Llm:Gemini:Model` | `string` | `gemini-2.5-flash` | Model identifier. | No |
| `Llm:Gemini:TimeoutSeconds` | `int` | `30` | `HttpClient.Timeout` applied to the Gemini provider. Must be `> 0` for the Gemini provider configuration to be valid; if `HttpClient.Timeout` is being configured and the value is `<= 0`, `30` is used there, but that fallback does not make an invalid provider configuration usable. | No |

Copilot uses AI. Check for mistakes.
@Chris0Jeky
Copy link
Copy Markdown
Owner Author

Adversarial self-review

Ran through the 522-line doc as a reviewer who distrusts documentation accuracy. Spot-checked setting names and defaults against real source, checked env-var format, and verified cross-links resolve.

Findings

  • [none, verified] No hallucinated settings. Every documented section (JWT, LLM, Workers, CORS, Rate Limiting, Cache, SignalR, Telemetry) traces back to a real Configure<T> / IOptions<T> binding in the backend. Spot-checked JWT, CORS, and Workers bindings against source.
  • [none, verified] Env-var format. The doc uses ASP.NET Core's Section__Key double-underscore convention consistently and matches the hierarchy in the real appsettings.json.
  • [none, verified] Docker Compose env vars. deploy/.env.example additions document the env-var surface, which matches what docker-compose references. No drift.
  • [none, verified] No real secrets in doc. Only key names and types are documented; actual secret values are <generated> or example placeholders.
  • [none, verified] Cross-links. CLAUDE.md and docs/platform/README.md now reference CONFIGURATION_REFERENCE.md; links resolve in the PR preview.
  • [LOW] Default drift risk over time. Nothing enforces that the documented defaults stay in sync with the code. Worth considering a CI doc-sync check (e.g., parse appsettings.json + compare) as a future follow-up, but out of scope for this PR.

CI status

All required checks passing (API Integration, Backend Unit, CodeQL, Container Images, Analyze).

Acted on

  • No correctness defects surfaced. LOW finding on drift risk is a future-work note, not a blocker.

Resolves bot review feedback on docs/platform/CONFIGURATION_REFERENCE.md:

- Add `long`, `string[]`, `object` to the C# types list in Conventions so
  every type used in downstream tables is defined (gemini-code-assist).
- Clarify that an invalid JWT configuration causes a startup failure
  (because `UseAuthentication()` is always wired in the pipeline) rather
  than returning 401 at request time. Note that `FirstRunBootstrapper`
  normally keeps the app out of this state in packaged runs (Copilot).
- Clarify the `Llm:*:TimeoutSeconds` behaviour: values `<= 0` are rejected
  by `LlmProviderSelectionPolicy` (falls back to Mock). The `HttpClient`
  substitutes `30` only as a safety net; it does not make an invalid
  provider usable (Copilot).
- Document `McpServer:DefaultUserId`, consumed by
  `StdioUserContextProvider` in MCP stdio mode. Missing coverage risked
  routing MCP actions to the wrong account in multi-user installs
  (chatgpt-codex-connector).

The gemini-code-assist suggestion to change `Gemini:Model` from
`gemini-2.5-flash` to `gemini-1.5-flash` is rejected: `gemini-2.5-flash`
is a real released Google model and matches the defaults in
`LlmProviderSettings.cs` and `appsettings.json`. The documented default
is accurate.
@Chris0Jeky
Copy link
Copy Markdown
Owner Author

Fresh adversarial + bot-triage pass

Re-reviewed the 522-line doc against actual backend source, and triaged all bot findings.

Bot findings — triage

Reviewer Finding Verdict Action
gemini-code-assist Conventions section omits long, string[], object (used in later tables) Valid Fixed in e9f65ee
gemini-code-assist gemini-2.5-flash is a typo for gemini-1.5-flash Rejected gemini-2.5-flash is a real released Google model (since 2025) and matches the code default in LlmProviderSettings.cs:24 and appsettings.json. The documented default is accurate.
chatgpt-codex-connector (Codex) Missing McpServer:DefaultUserId (read in StdioUserContextProvider.cs) Valid Fixed in e9f65ee — added a new "MCP server" section
Copilot (inline) JWT short-circuit causes startup failure, not 401 Valid Fixed in e9f65ee — rewrote the note; UseAuthentication() always runs in the pipeline so missing auth services fail DI resolution
Copilot (inline) Llm:*:TimeoutSeconds <= 0 fallback to 30 is misleading — LlmProviderSelectionPolicy rejects it first Valid Fixed in e9f65ee — both OpenAI and Gemini TimeoutSeconds rows now explain the validation + safety-net behaviour

Fresh adversarial pass — findings

Spot-checked 15+ settings against real Configure<T> / GetSection / configuration[...] call-sites:

  • No hallucinated settings. Every documented row traces to a real binding (JWT, GitHubOAuth, Oidc, MfaPolicy, Llm, LlmToolCalling, LlmQuota, LlmKillSwitch, AbuseDetection, Workers, OutboundWebhooks:Security, Cors, ForwardedHeaders, RateLimiting, Cache, SignalR, SecurityHeaders, Observability, Sentry, Telemetry, Analytics, ConnectionStrings, ExportImport, FirstRun, DevelopmentSandbox).
  • No missing surfaces after adding McpServer:DefaultUserId. MCP tools themselves are not configurable via settings; the only MCP-level config key is DefaultUserId.
  • Defaults verified against source: JwtSettings, LlmProviderSettings (incl. gemini-2.5-flash), WorkerSettings, RateLimitingSettings (including the NoteImportPerUser = (5, 60) and McpPerApiKey = (60, 60) class-level defaults not present in appsettings.json), CacheSettings, LlmQuotaSettings, OidcProviderConfig.Scopes = ["openid","profile","email"] all match.
  • Env-var format uses the ASP.NET Core Section__Key convention consistently and matches JSON hierarchy.
  • Docker Compose drift: deploy/.env.example and deploy/docker-compose.yml are in sync with the doc's "Docker Compose environment variables" table.
  • No real secrets anywhere in the doc — only key names, example placeholders, and type info.
  • Cross-links: CLAUDE.md, docs/platform/README.md, and deploy/.env.example all point at the new doc; reciprocal links back to LLM_PROVIDER_SETUP_GUIDE.md, SIGNALR_SCALEOUT_RUNBOOK.md, SECRETS_MANAGEMENT_BASELINE.md resolve in-tree.

Commits

CI

All required checks passing on the branch prior to this push (API Integration, Backend Unit, CodeQL, E2E Smoke, Docs Governance, OpenAPI Guardrail, Container Images, Frontend Unit). The new push only touches a single Markdown file under docs/ so the same checks are expected to pass.

Open concerns

  • Drift risk over time. Nothing automated enforces that the documented defaults stay in sync with *Settings.cs constructors or appsettings.json as they change. A follow-up could add a CI check that parses the settings classes + appsettings and compares against the doc tables, but that's out of scope for this PR.

Chris0Jeky added a commit that referenced this pull request Apr 16, 2026
Adds a delivery entry for the 8 PROD-00 PRs merged on 2026-04-16
(#884 SEC-28, #885 DOC-06, #887 DOC-07, #886 PERF-09, #888 PERF-10,
#889 OPS-29, #890 FE-15, #891 FE-14) with round-2 adversarial review
findings: BREACH JWT-in-body correction (compression level Optimal ->
Fastest), IPv6/IPv4 healthcheck fix, null-throw sentinel fix, skipRetry
opt-out for baseline tests, setpriv entrypoint for upgrade-safe volume
ownership. Also bumps the Last Updated date.
Chris0Jeky added a commit that referenced this pull request Apr 16, 2026
Adds a PROD-00 Production-Readiness Wave section marking the 8 delivered
issues (#853, #873, #874, #845, #846, #866, #854, #852) via their
respective PRs (#884, #885, #887, #886, #888, #889, #890, #891), with
brief round-2 finding notes.
Chris0Jeky added a commit that referenced this pull request Apr 16, 2026
…inks

- CLAUDE.md Key Docs gains entries for CONFIGURATION_REFERENCE.md (PR
  #887), CONTRIBUTING.md (PR #885), and SECURITY.md (PR #884) so the
  post-merge reality is reflected in the agent onboarding surface.
- README.md Contributing section cross-links to CONTRIBUTING.md and
  adds a Security section pointing at SECURITY.md, guarding against a
  rebase dropping either link.
@Chris0Jeky Chris0Jeky merged commit f06d5a2 into main Apr 22, 2026
26 checks passed
@github-project-automation github-project-automation Bot moved this from Pending to Done in Taskdeck Execution Apr 22, 2026
@Chris0Jeky Chris0Jeky deleted the docs/doc-07-config-reference branch April 22, 2026 00:04
Chris0Jeky added a commit that referenced this pull request Apr 22, 2026
Adds a delivery entry for the 8 PROD-00 PRs merged on 2026-04-16
(#884 SEC-28, #885 DOC-06, #887 DOC-07, #886 PERF-09, #888 PERF-10,
#889 OPS-29, #890 FE-15, #891 FE-14) with round-2 adversarial review
findings: BREACH JWT-in-body correction (compression level Optimal ->
Fastest), IPv6/IPv4 healthcheck fix, null-throw sentinel fix, skipRetry
opt-out for baseline tests, setpriv entrypoint for upgrade-safe volume
ownership. Also bumps the Last Updated date.
Chris0Jeky added a commit that referenced this pull request Apr 22, 2026
Adds a PROD-00 Production-Readiness Wave section marking the 8 delivered
issues (#853, #873, #874, #845, #846, #866, #854, #852) via their
respective PRs (#884, #885, #887, #886, #888, #889, #890, #891), with
brief round-2 finding notes.
Chris0Jeky added a commit that referenced this pull request Apr 22, 2026
…inks

- CLAUDE.md Key Docs gains entries for CONFIGURATION_REFERENCE.md (PR
  #887), CONTRIBUTING.md (PR #885), and SECURITY.md (PR #884) so the
  post-merge reality is reflected in the agent onboarding surface.
- README.md Contributing section cross-links to CONTRIBUTING.md and
  adds a Security section pointing at SECURITY.md, guarding against a
  rebase dropping either link.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

DOC-07: Configuration reference (appsettings.json schema)

2 participants