# Module: `Program` (composition root) + `GlobalUsings` **Files (2)**: `Program.cs`, `GlobalUsings.cs` > **NOTE (forward-looking)**: post-rename. Today's source has `Azaion.Flights` namespace and `dotnet Azaion.Flights.dll` entrypoint. Renames + DLL/image changes tracked under Jira AZ-EPIC children B5 (namespace), B7 (drop GPS policy), B10 (Dockerfile + docker image rename). ## Purpose Top-level statements that build the ASP.NET Core web host: read environment, register DI services (DB connection, services, auth, CORS, MVC, Swagger), run the migrator once, then `app.Run()`. `GlobalUsings.cs` adds three project-wide `global using` directives so individual files don't need to repeat them: ```csharp global using LinqToDB; global using LinqToDB.Async; global using LinqToDB.Data; ``` ## Public Interface `Program.cs` is a top-level program -- it is not a class with a public surface. Its observable contract is the resulting HTTP server: - Listens on the Kestrel-default URL (typically `http://0.0.0.0:8080` in container per Dockerfile `EXPOSE 8080`). - Exposes routes mapped by `MapControllers` (see `controller_vehicles.md`, `controller_missions.md`) plus `GET /health`. - Serves Swagger UI at the default `/swagger` route (not gated on environment). ## Internal Logic ```text 1. WebApplicationBuilder = WebApplication.CreateBuilder(args) 2. Resolve DATABASE_URL (Configuration -> Env -> fallback) If it begins with "postgresql://" -> ConvertPostgresUrl() to Npgsql key=value form. 3. Resolve JWT_SECRET (Configuration -> Env -> fallback) 4. Register services (scoped where applicable): - AppDataConnection <- scoped, built via new DataOptions().UsePostgreSQL(connectionString) - MissionService, WaypointService, VehicleService <- scoped - AddJwtAuth(jwtSecret) -> JWT bearer + "FL" policy - AddCors with default policy = AllowAnyOrigin/Method/Header - AddControllers, AddEndpointsApiExplorer, AddSwaggerGen 5. Build the WebApplication. 6. Open a temp scope, resolve AppDataConnection, call DatabaseMigrator.Migrate(db). 7. Configure pipeline (order matters): a. UseMiddleware b. UseCors c. UseAuthentication d. UseAuthorization e. UseSwagger, UseSwaggerUI f. MapControllers g. MapGet("/health", () => Results.Ok({status:"healthy"})) 8. app.Run() ConvertPostgresUrl(url): parses postgresql://user[:pass]@host[:port]/db into "Host={host};Port={port};Database={db};Username={user};Password={pass}" (defaults port to 5432; absent password becomes empty) ``` ## Dependencies - All internal namespaces: `Azaion.Missions.{Auth, Database, Middleware, Services}`. - ASP.NET Core, LinqToDB, Npgsql, Swashbuckle, JWT bearer (NuGet). ## Consumers - The container runtime (`ENTRYPOINT ["dotnet", "Azaion.Missions.dll"]` in `Dockerfile` after B10). - `dotnet run` for local development. ## Configuration | Env / Config Key | Required? | Default | |------------------|-----------|---------| | `DATABASE_URL` | No (has dev fallback) | `Host=localhost;Database=azaion;Username=postgres;Password=changeme` | | `JWT_SECRET` | No (has dev fallback) | `development-secret-key-min-32-chars!!` | | `AZAION_REVISION` | Set by Dockerfile from `CI_COMMIT_SHA` | `unknown` (build arg default) | There is **no `appsettings.json`** in this repo (per discovery) -- config comes from env / process variables only. Suite-wide env conventions live in `../../suite/_docs/00_top_level_architecture.md` (Edge compose excerpt). ## External Integrations - PostgreSQL (read/write) via Npgsql. - Identity provider: the suite's `admin` service mints JWTs against the central user PostgreSQL; `JWT_SECRET` is the shared HMAC secret. Local validation only -- no network round-trip per request. ## Security - **Hardcoded fallbacks** for both `DATABASE_URL` and `JWT_SECRET` are dev-only. Production deployments MUST override them; failure to do so silently runs with weak/known credentials. - **CORS is permissive** in all environments (`AllowAnyOrigin/Method/Header`). Combined with JWT auth this is not catastrophic (browser will send the bearer token only if the front-end opts in), but exposes the API to opportunistic browser-based scraping. - **Swagger is unconditionally enabled** -- both the JSON document and the UI are served regardless of environment. Anyone reaching the host can enumerate the API surface. - **No HTTPS redirection** middleware (`UseHttpsRedirection`) -- TLS is assumed to terminate at an upstream reverse proxy. - **`app.UseMiddleware` runs before `UseAuthentication`/`UseAuthorization`** -- auth failures still emit the framework's stock 401/403 (which is fine), but any auth-stage exceptions ALSO run through the global handler (which converts `KeyNotFoundException` -> 404, etc.; auth pipeline doesn't typically throw those). ## Tests None present. ## Notes / Smells 1. **`DATABASE_URL` URL parsing**: `ConvertPostgresUrl` is a small ad-hoc parser. Fine for typical cases but does not URL-decode the user/password. A password containing `@`, `:`, `/`, `%` would break parsing or be interpreted wrong. Carry to verification log. 2. **No `IsDevelopment()` checks** anywhere in `Program.cs`. Dev/prod behaviors (Swagger, fallback secrets) are not gated. 3. **`AddSwaggerGen()` with no JWT bearer security definition** -- Swagger UI's "Authorize" button won't appear; users must supply tokens via `curl -H "Authorization: Bearer ..."`. Not a bug, but a usability issue. 4. **`DatabaseMigrator.Migrate` is fire-and-forget** -- if it throws (DB down at startup), the host process crashes. Acceptable for container orchestration that restarts on failure. 5. **`GlobalUsings.cs` imports `LinqToDB.Async`** but most async LINQ extensions used by the project (`AnyAsync`, `FirstOrDefaultAsync`, `ToListAsync`, etc.) actually live in the `LinqToDB` namespace already. Harmless redundancy. 6. **Service lifetime**: `AppDataConnection` is **scoped** (per-HTTP-request) -- correct, because `DataConnection` holds a backing Npgsql connection that should not be shared across requests. The three domain services share this scope, so all DB calls within one request go through the same physical connection (good for correctness, no implicit transactions though).