# Restrictions — Azaion.Missions > **Status**: derived-from-code (autodev `/document` Step 6, 2026-05-14). > Each restriction below is grounded in code, configuration, or Dockerfile evidence — none are aspirational. References point to the artefact that establishes the constraint. --- ## Hardware restrictions | # | Restriction | Evidence | |---|-------------|----------| | H1 | Service runs on operator-owned edge devices (Jetson Orin / OrangePI / operator-PC), one container per device | `Dockerfile` multi-arch; `../../suite/_docs/00_top_level_architecture.md` § Edge Tier | | H2 | Multi-arch container — ARM64 dominant (Jetson / OrangePI), AMD64 supported (operator-PC) | `Dockerfile` `--platform=$BUILDPLATFORM`, `dotnet publish --os linux --arch $arch`; `.woodpecker/build-arm.yml` tag suffix `-arm` | | H3 | Vertical scale only — exactly one instance per device, no horizontal scale-out | `_docs/02_document/architecture.md` § 3 Deployment Model; suite arch doc § Edge Tier | | H4 | No managed cloud — every deployment is on customer-owned hardware | suite arch doc § Edge Tier | | H5 | Watchtower handles container restarts; `flight-gate` prevents container restart mid-mission | suite arch doc § Edge Tier; `_docs/02_document/architecture.md` § 6 Availability | | H6 | Resource limits not enforced inside the container; device-level cgroups / docker compose limits set at suite level | `Dockerfile` (no `--memory` / cpu); suite `_infra/_compose/` | ## Software restrictions | # | Restriction | Evidence | |---|-------------|----------| | S1 | Language: C#; runtime: .NET 10 (`net10.0`) | `Azaion.Flights.csproj` (post-B5: `Azaion.Missions.csproj`) | | S2 | Web framework: ASP.NET Core (`Microsoft.NET.Sdk.Web`) | csproj | | S3 | Data access library: linq2db `6.2.0` | csproj `` | | S4 | Database driver: Npgsql `10.0.2` | csproj | | S5 | Auth library: `Microsoft.AspNetCore.Authentication.JwtBearer` `10.0.5` | csproj | | S6 | Swagger / OpenAPI: Swashbuckle `10.1.5`, mounted unconditionally (NOT gated on `IsDevelopment()`) — ADR-005 carry-forward | csproj + `Program.cs` | | S7 | Database engine: PostgreSQL (no other DB engines supported) | `Program.cs` `UsePostgreSQL`; suite arch doc § Database Topology | | S8 | One csproj, one root namespace (`Azaion.Missions.*` post-B5) — components are logical groupings, not compilation units | csproj; `_docs/02_document/architecture.md` ADR-008 | | S9 | No `src/` directory — project sits at the repo root | repo layout; `_docs/02_document/00_discovery.md` § Repository Layout | | S10 | Layer-organized layout (`Controllers/`, `Services/`, `DTOs/`, `Enums/`, `Auth/`, `Middleware/`, `Database/` at repo root) | repo layout; `_docs/02_document/module-layout.md` | | S11 | No automated tests today (no `tests/` directory; no test sibling project) | repo layout; `_docs/02_document/00_discovery.md` § Test Layout | | S12 | No migration tool — schema bootstrap via raw `CREATE TABLE IF NOT EXISTS` + one-shot B9 `DROP TABLE IF EXISTS` block | `Database/DatabaseMigrator.cs`; ADR-004 | | S13 | No in-process message queue, no event bus, no RPC — components communicate via direct C# calls registered in DI | `_docs/02_document/architecture.md` § 5; `Program.cs` | | S14 | Tables OWNED by this service (post-B7+B9): `vehicles`, `missions`, `waypoints`, `map_objects` (4 owned). 3 borrowed read-only stubs (`media`, `annotations`, `detection`) | `Database/DatabaseMigrator.cs`; `Database/AppDataConnection.cs`; `_docs/02_document/data_model.md` | | S15 | `gps-denied` is decoupled by design — no runtime call in either direction; `gps-denied` references `mission_id` / `waypoint_id` as plain GUIDs in its own tables | ADR-007 | ## Environment / configuration restrictions | # | Restriction | Evidence | |---|-------------|----------| | E1 | Two required env vars at runtime: `DATABASE_URL`, `JWT_SECRET` | `Program.cs` `Environment.GetEnvironmentVariable` | | E2 | `DATABASE_URL` accepts either a `postgresql://user:pass@host:port/db` URL OR a raw Npgsql connection string (local helper `ConvertPostgresUrl`) | `Program.cs` `ConvertPostgresUrl` | | E3 | Hardcoded development fallbacks: `JWT_SECRET=development-secret-key-min-32-chars!!`, `DATABASE_URL=Host=localhost;Database=azaion;Username=postgres;Password=changeme` (NOT gated on `IsDevelopment()`) — ADR-005 carry-forward; production deploys MUST override | `Program.cs` | | E4 | `JWT_SECRET` is shared across `admin` + every backend service on the same edge device — rotation requires a coordinated re-deploy across all of them | `_docs/02_document/components/05_identity/description.md`; suite arch doc | | E5 | Container `EXPOSE 8080`; edge compose maps host port `5002:8080` | `Dockerfile`; suite `_infra/_compose/` | | E6 | Image tag: `${REGISTRY_HOST}/azaion/missions:${BRANCH}-arm` post-B10 (was `azaion/flights:*-arm` pre-B10) | `.woodpecker/build-arm.yml` (post-B10) | | E7 | Entrypoint: `dotnet Azaion.Missions.dll` post-B5 (was `Azaion.Flights.dll` pre-B5) | `Dockerfile` (post-B5) | | E8 | No environment-specific overrides in `appsettings.*.json` — single config flow via env vars | `Program.cs`; no `appsettings.Production.json` in repo | | E9 | CORS: `AllowAnyOrigin / AllowAnyMethod / AllowAnyHeader` in **all** environments (assumed safe behind suite reverse proxy) | `Program.cs` | | E10 | TLS termination is the suite reverse proxy's responsibility — container exposes plain HTTP on `:8080` | `Dockerfile`; suite arch doc | ## Operational restrictions | # | Restriction | Evidence | |---|-------------|----------| | O1 | Migrator runs at every process start; idempotent (`IF NOT EXISTS`); B9 adds a one-shot `DROP TABLE IF EXISTS orthophotos / gps_corrections` block for fielded legacy devices | `Database/DatabaseMigrator.cs` | | O2 | `flight-gate` (suite-level) is the ONLY orchestration that prevents restart mid-mission; no Kubernetes | suite arch doc § Edge Tier | | O3 | No version table; the migrator runs every startup | `Database/DatabaseMigrator.cs` | | O4 | Single Woodpecker CI job per repo: docker build + push on `[dev, stage, main]` branches; no test, no security scan, no migration check | `.woodpecker/build-arm.yml` | | O5 | No structured logging (Serilog / Seq) — `LogError(ex, "Unhandled exception")` is the only application-level log | `Middleware/ErrorHandlingMiddleware.cs`; `_docs/02_document/architecture.md` § 7 | | O6 | No correlation ID, no per-request audit trail, no per-user attribution (JWT user-id claim parsed but not consumed) | `Auth/JwtExtensions.cs`; `_docs/02_document/components/05_identity/description.md` | | O7 | Health endpoint: `GET /health` returns `{ status: "healthy" }` with no DB ping (process-liveness only) | `Program.cs` `MapGet("/health")` | | O8 | Cascade-delete is **NOT** transaction-wrapped today (ADR-006) — partial failure leaves orphan rows in `media` / `annotations` / `detection` / `map_objects` | `Services/FlightService.cs` (post-B6: `MissionService.cs`); `Services/WaypointService.cs` | | O9 | Each backend service is responsible for its own table migrations; if `annotations` is absent at deploy time, the cascade-delete walk fails on `relation does not exist` (abnormal edge deployment) | `_docs/02_document/components/02_mission_planning/description.md` Caveats #6 | | O10 | One-instance-per-device constraint means session state, in-memory caches, and rate limits are NOT cluster-aware (none of these are implemented today either) | `Program.cs`; suite arch doc | ## Out-of-scope (NOT this service's responsibility) | Concern | Where it lives | Why it's not here | |---------|----------------|-------------------| | Token issuance (sign / mint) | `admin` (central .NET service) | Local validation only; offline-tolerant edge design | | User CRUD, role assignment | `admin` + `../../suite/_docs/00_roles_permissions.md` | Suite-level concern | | Media storage / upload | `annotations` (sibling edge service) | `annotations` owns the table schema | | AI annotation rules | `annotations` | Schema and behaviour both owned by `annotations` | | Object detection / class definitions | Detection pipeline (sibling edge service) | Pipeline owns the `detection` table | | `map_objects` write path | `autopilot` (sibling edge service) | This service owns the schema + cascade-delete only | | Orthophoto / live-GPS / GPS correction | `gps-denied` (separate service after B7) | ADR-007 | | TLS / HTTPS termination | Suite reverse proxy | `_docs/02_document/architecture.md` § 7 | | Schema rename / column drop / type change | Future migration tool (ADR-004 carry-forward) | Today's `IF NOT EXISTS` migrator can't reshape existing schema; B9's `DROP TABLE IF EXISTS` is the single explicit destructive step | | `iss` / `aud` JWT validation | Suite-level remediation (CMMC L2 row 3, AZ-487 / AZ-494) | Out of this Epic; consistent with shared-secret model today | | camelCase wire-shape migration | Suite-wide cutover (ADR-002 carry-forward) | All-or-nothing; UI + autopilot consume PascalCase today |