Files
annotations/_docs/02_document/deployment/environment_strategy.md
T
Oleksandr Bezdieniezhnykh 03f879206e docs+src: complete Steps 1-3 outcomes + auth re-sync baseline
This commit captures everything produced during autodev existing-code
Steps 1 (Document), 2 (Architecture Baseline Scan), and 3 (Test Spec),
together with the targeted auth + CORS re-sync triggered on 2026-05-14
when codebase drift was detected at Step 4 entry. None of this work was
previously committed.

Step 1 (Document) — 50+ _docs/02_document/ files: problem, solution,
architecture, system flows, glossary, module-layout, per-component
specs (01..06), modules, deployment, diagrams, data model, FINAL
report, verification log, discovery.

Step 2 (Architecture Baseline) — architecture_compliance_baseline.md.
Verdict PASS_WITH_WARNINGS (0 Critical, 0 High, 1 Medium, 2 Low). No
High/Critical findings; auto-chained to Step 3 per existing-code flow.

Step 3 (Test Spec) — _docs/02_document/tests/* (67 scenarios across
blackbox, security, resilience, resource-limit, performance), plus
e2e/docker-compose.test.yml, e2e/seed/run.sh, scripts/run-tests.sh,
scripts/run-performance-tests.sh. Coverage 88% over the active scope
(40 of 45 items covered, 6 RB-deferred, 5 documented-as-uncovered).

Targeted auth + CORS re-sync — replaces the deleted in-house token
issuer with a JWKS-verifier model. AuthController and TokenService
removed; JwtExtensions switched from HS256 symmetric to ES256 over
admin's JWKS. ConfigurationResolver and CorsConfigurationValidator
added under src/Infrastructure/. ADR-002 and ADR-006 retired; SEC-01,
SEC-02, SEC-03 marked Closed. One new testability risk recorded in
architecture.md Open Risks Section 6 (JWKS HTTPS gating).

Source changes:
- src/Auth/JwtExtensions.cs (modified) — ES256, JWKS, alg pinning
- src/Program.cs (modified) — DI wiring for ConfigurationResolver
  and CorsConfigurationValidator
- src/Controllers/AuthController.cs (deleted) — no in-service issuance
- src/Services/TokenService.cs (deleted) — same
- src/Infrastructure/ConfigurationResolver.cs (new)
- src/Infrastructure/CorsConfigurationValidator.cs (new)
- .env.example (new) — required env var documentation
- .gitignore (updated)

Cross-repo coordination: _docs/cross-repo/flights_h1_h2_h3_change_spec
captures the change-spec for downstream services that consumed the now
deleted /auth endpoints.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-14 20:19:05 +03:00

4.5 KiB

Environment Strategy

Source of truth: src/Program.cs + src/Database/DatabaseMigrator.cs + .woodpecker/build-arm.yml.

Environments

Branch-driven from CI:

Branch Image tag Intended environment
dev dev-arm Development (shared)
stage stage-arm Pre-production
main main-arm Production

The service binary is identical across environments — all variation is runtime configuration via env vars (no per-environment build flags).

Configuration sources (priority order, per Program.cs)

  1. Environment.GetEnvironmentVariable("KEY").
  2. ASP.NET Core IConfiguration (builder.Configuration["KEY"]) — covers appsettings.json, command-line args, etc.
  3. No hard-coded fallback for security-sensitive values. DATABASE_URL, JWT_ISSUER, JWT_AUDIENCE, JWT_JWKS_URL, and (in Production) a non-empty CorsConfig:AllowedOrigins are required; missing values cause startup to fail fast via ConfigurationResolver.ResolveRequiredOrThrow / CorsConfigurationValidator.EnsureSafeForEnvironment.

Required environment variables

Variable Purpose Default Production action
DATABASE_URL Postgres connection (URL or LinqToDB conn string) — (required, fail-fast) MUST set
JWT_ISSUER Expected iss claim; must match admin's JwtConfig:Issuer — (required, fail-fast) MUST set
JWT_AUDIENCE Expected aud claim; must match admin's JwtConfig:Audience — (required, fail-fast) MUST set
JWT_JWKS_URL Admin's JWKS endpoint (HTTPS) — (required, fail-fast) https://admin.azaion.com/.well-known/jwks.json
CorsConfig__AllowedOrigins__0 First allowed CORS origin (array via __N indices) MUST set (or CorsConfig__AllowAnyOrigin=true) in Production
CorsConfig__AllowAnyOrigin Opt-in to permissive CORS (non-production only) false Leave false in Production
RABBITMQ_HOST Stream host 127.0.0.1 Override
RABBITMQ_STREAM_PORT Stream port 5552 Override if non-default
RABBITMQ_PRODUCER_USER Stream user azaion_producer Override
RABBITMQ_PRODUCER_PASS Stream password producer_pass Override
RABBITMQ_STREAM_NAME Stream name azaion-annotations Usually keep (suite contract)

JWT_SECRET was removed in this cycle — annotations no longer mints HS256 tokens; admin is the sole token issuer (ES256).

URL format conversion

Program.cs accepts DATABASE_URL either as a Linq2DB connection string or as a postgresql://user:pass@host:port/db URL. The ConvertPostgresUrl helper rewrites the URL form into LinqToDB conn-string form. This means operators can use either ENV-style URLs (kubectl/Postgres operator output) or Host=... directly.

DB-driven configuration

Several runtime concerns are stored in database tables, not env:

  • Filesystem rootsdirectory_settings (defaults /data/...). Updated via PUT /settings/directories; must trigger PathResolver.Reset for the change to take effect (Flow F7).
  • System settingssystem_settings (generate_annotated_image, silent_detection, thumbnail dimensions).
  • User settingsuser_settings (per UI session prefs).

Operators changing filesystem layout in production need an ADM JWT and the right cluster connectivity, not a redeploy.

Filesystem mounts

The container expects /data/ (or whatever directory_settings points at) to be a writable persistent mount:

  • /data/images — annotation full images
  • /data/labels — YOLO .txt files
  • /data/thumbnails — thumbnails
  • /data/results — annotated images (when generate_annotated_image=true)
  • /data/videos — media uploads
  • /data/gps_sat, /data/gps_route — GPS overlays

Without these mounts, every annotation-create / media-upload flow returns 500 from ErrorHandlingMiddleware (FS write fails).

Config drift between environments

Today, environment-specific config is held wherever the deployment platform places env vars (Helm values / Kustomize overlays / Compose files in _infra/). This repo intentionally does not commit per-environment values; the only environment-aware file in-repo is .woodpecker/build-arm.yml.

Open items

  • No appsettings.Production.json — all env-specific config is operator-supplied.
  • Swagger UI is mounted in all environments (ADR-005); production exposure must be controlled at the perimeter.