mirror of
https://github.com/azaion/missions.git
synced 2026-06-21 14:11:08 +00:00
a26d7b163b
The .woodpecker/build-arm.yml already pushes ${REGISTRY_HOST}/azaion/missions
(landed earlier as part of the B5 csproj/namespace rename). What this commit
fixes is the missions-internal documentation that still described the legacy
azaion/flights image as the *current* state.
Edits:
- _docs/02_document/deployment/environment_strategy.md: drop "today's edge
compose still references azaion/flights" — B10 is done. Container/service
name 'flights' still noted as B6/B11 work.
- _docs/02_document/deployment/containerization.md: drop "today's Dockerfile
ENTRYPOINT is dotnet Azaion.Flights.dll, image tag base is azaion/flights"
— both AZ-544 (B5) and AZ-549 (B10) done.
- _docs/02_document/deployment/ci_cd_pipeline.md: same fix.
- _docs/02_document/components/07_host/description.md: same fix.
- _docs/02_document/04_verification_log.md row for AZ-549: explicitly
marked "done"; Code symbol column converged to post-rename value.
- _docs/00_problem/restrictions.md E6: parenthetical reworded so the row
reads as a present-state assertion (B10 done) instead of a forward-
looking note.
- _docs/02_document/glossary.md "Synonym pairs" heading flipped from
"today's code ↔ post-rename target" to "pre-rename ↔ post-rename"
(adjacent hygiene — B5-B9+B10 are done across the missions rename
Epic; the table's "today" framing no longer matches reality).
Spec _docs/tasks/todo/AZ-549a_missions_rename_b10_pipeline.md moved to
_docs/tasks/done/.
rg -F 'azaion/flights' missions/ | grep -v done/ now returns only
intentional pre-rename historical references in glossary.md /
architecture.md / restrictions.md / verification_log.md — the "current
state" wording is gone.
Suite-side slice (AZ-549b — _infra/deploy/*/docker-compose.yml image
ref + ci/README.md example) shipped separately in the suite repo.
Co-authored-by: Cursor <cursoragent@cursor.com>
102 lines
6.6 KiB
Markdown
102 lines
6.6 KiB
Markdown
# Environment Strategy
|
|
|
|
> **NOTE**: image tag and namespace reflect the post-rename state (B10 done). The container name and compose service name are still `flights` — that rename is B6/B11 (consumer cutover), tracked separately.
|
|
|
|
## Environments
|
|
|
|
| Environment | Where it runs | Audience | Image tag (post-B10) |
|
|
|-------------|---------------|----------|----------------------|
|
|
| **Development** | Local workstation (`dotnet run` from the repo root, or `docker run` against a local PG) | Engineers | none — built ad-hoc |
|
|
| **Edge production** | Each customer-owned edge device (Jetson Orin / OrangePI / operator-PC), one container per device | Operators, autopilot, UI | `azaion/missions:dev-arm` / `stage-arm` / `main-arm` per device tier |
|
|
|
|
There is **no centralized staging environment** in the suite. Each edge device is its own deployment; the `stage` image tag is for pre-prod customer demo devices, not for a separate cloud staging cluster.
|
|
|
|
## Configuration sources (precedence)
|
|
|
|
`Program.cs` resolves each setting in this order:
|
|
|
|
1. `IConfiguration` (defaults: appsettings.json + ASPNETCORE_-prefixed env vars)
|
|
2. `Environment.GetEnvironmentVariable(...)` (legacy fallback for unprefixed env)
|
|
3. **Hardcoded dev fallback** (last resort)
|
|
|
|
### `DATABASE_URL`
|
|
|
|
| Environment | Value source | Resolved value |
|
|
|-------------|--------------|----------------|
|
|
| Development (no env set) | hardcoded fallback | `Host=localhost;Database=azaion;Username=postgres;Password=changeme` |
|
|
| Development (env set) | env var | Whatever the engineer sets (URL form OR raw Npgsql key=value form both work) |
|
|
| Edge production | env var passed via docker compose | `postgresql://postgres:${PG_LOCAL_PASSWORD}@postgres-local/azaion` (per `../../../suite/_docs/00_top_level_architecture.md`) |
|
|
|
|
**`ConvertPostgresUrl` helper** parses the URL form into Npgsql key=value form. **Does NOT URL-decode user/password** — credentials with `@`, `:`, `/`, `%` will be mis-parsed. `07_host` Caveats #4 calls this out. Mitigation: avoid those characters in the local PG password (the standard suite provisioning does), or pass a raw Npgsql key=value string instead of a URL.
|
|
|
|
### `JWT_SECRET`
|
|
|
|
| Environment | Value source | Resolved value |
|
|
|-------------|--------------|----------------|
|
|
| Development (no env set) | hardcoded fallback | `development-secret-key-min-32-chars!!` (**well-known; never use in production**) |
|
|
| Development (env set) | env var | Whatever the engineer sets |
|
|
| Edge production | env var (compose `env_file` or per-device-provisioned secret) | The shared HMAC secret used by `admin` + every backend service on the device. **Rotation is suite-coordinated** — see `architecture.md` § Security |
|
|
|
|
**Critical foot-gun (ADR-005 carry-forward)**: there is **no runtime gate** that blocks startup with the dev fallback in production. A misconfigured production deploy will silently boot with the well-known dev secret. The CMMC L2 scorecard tracks the broader fix at suite level (AZ-487 / AZ-494).
|
|
|
|
## Other configuration
|
|
|
|
These settings are **NOT** environment-overridable today (carry-forward improvements):
|
|
|
|
| Setting | Current behavior | Should it differ between dev and prod? |
|
|
|---------|------------------|----------------------------------------|
|
|
| Swagger UI mount | Always on | Yes — production should gate on `IsDevelopment()` (ADR-005) |
|
|
| CORS policy | `AllowAnyOrigin/Method/Header` always | Yes — production should restrict to the suite's reverse-proxy origin |
|
|
| HTTPS redirection | None — assumes upstream TLS termination | No — the suite's reverse proxy handles TLS; this is correct |
|
|
| Logging verbosity | ASP.NET Core defaults (Information+) | Probably not at this scale; `LogLevel:Default = Warning` could be useful in prod |
|
|
| Migrator `DROP TABLE IF EXISTS` (B9 one-shot) | Runs every startup; idempotent on already-cleaned devices | No — the idempotent design means this is safe everywhere |
|
|
|
|
## Edge compose excerpt (suite-wide pattern, post-B10)
|
|
|
|
Per `../../../suite/_docs/00_top_level_architecture.md` § Edge compose:
|
|
|
|
```yaml
|
|
services:
|
|
missions: # was: flights (pre-B10)
|
|
image: ${REGISTRY_HOST}/azaion/missions:${BRANCH:-main}-arm
|
|
container_name: missions
|
|
restart: unless-stopped
|
|
depends_on:
|
|
postgres-local:
|
|
condition: service_healthy
|
|
environment:
|
|
DATABASE_URL: postgresql://postgres:${PG_LOCAL_PASSWORD}@postgres-local/azaion
|
|
JWT_SECRET: ${JWT_SECRET}
|
|
ports:
|
|
- "5002:8080"
|
|
networks:
|
|
- azaion-edge
|
|
```
|
|
|
|
The actual file lives in the suite repo (`../../../suite/_infra/_compose/`) — the snippet here is illustrative.
|
|
|
|
## Secrets management
|
|
|
|
- **Local dev**: hardcoded fallbacks in `Program.cs` (the dev-secret values listed above).
|
|
- **Edge production**: env vars sourced from a per-device `.env` file (created at provisioning) OR a local secrets manager (per-customer choice — the suite supports both patterns). The `JWT_SECRET` is suite-wide (one value across all backend services on the device).
|
|
- **Rotation**: changing `JWT_SECRET` invalidates every issued token until new ones are minted. Coordinated procedure across the device's backend services + UI re-login. There is **no online rotation** — every backend must be restarted with the new secret simultaneously.
|
|
|
|
## Network / port layout
|
|
|
|
- Container `EXPOSE 8080`; bound HTTP only (no TLS in this service).
|
|
- Edge compose maps `5002:8080` per the suite convention.
|
|
- Reverse proxy (Caddy fronting the suite per `../../../suite/_docs/00_top_level_architecture.md`) terminates TLS upstream.
|
|
- No outbound network calls except to `postgres-local` (DB).
|
|
|
|
## Restart / lifecycle
|
|
|
|
- Container restart policy: `unless-stopped` in production compose (manually-stopped containers stay stopped; crash → auto-restart).
|
|
- Watchtower polls the registry and triggers re-create on new image digest.
|
|
- `flight-gate` (suite component) gates container restart so it does not happen mid-mission. Once the active mission completes, Watchtower's queued restart goes through.
|
|
- `missions` itself does not implement graceful shutdown beyond ASP.NET Core's defaults — in-flight HTTP requests are allowed to complete; idle connections are closed.
|
|
|
|
## Backup / disaster recovery
|
|
|
|
- **Out of scope for this service.** PostgreSQL backup is a per-device, suite-level concern (not per-service). Each edge device runs `postgres-local`; backup cadence and offsite replication are decided at provisioning time and documented at suite level (currently informally).
|
|
- **No application-level export** — the only way to read mission / waypoint data out of the device is through the API or `pg_dump` against `postgres-local`.
|