Files
ui/_docs/02_document/deployment/environment_strategy.md
Oleksandr Bezdieniezhnykh 15838c5cc1
ci/woodpecker/push/build-arm Pipeline failed
Update autodev state and lessons documentation
- Changed current step from 15 (Performance Test) to 9 (New Task) in _docs/_autodev_state.md, reflecting the transition to Cycle 3.
- Updated cycle count from 2 to 3 and modified sub-step details to indicate progress in gathering feature descriptions.
- Added new lessons to _docs/LESSONS.md, emphasizing best practices for API key management, dependency handling, and reporting inline fixes during security audits.
- Enhanced CI/CD pipeline documentation in _docs/02_document/deployment/ci_cd_pipeline.md to include new gates for vulnerability scans and SBOM emissions, along with dependency overrides for transitive dependencies.
- Expanded environment strategy documentation in _docs/02_document/deployment/environment_strategy.md to include the new Google Geocode API key management.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 22:49:38 +03:00

7.0 KiB
Raw Permalink Blame History

Azaion UI — Environment Strategy

Synthesis output of /document Step 3d (environment_strategy). Derived from vite.config.ts, nginx.conf, .gitignore, the workspace README.md, and the absence of a workspace .env.example.

1. Environments

Env How it runs API base Auth Tile providers
Development bun run dev (Vite dev server, port 5173) Vite dev proxy: /api → http://localhost:8080 (configured in vite.config.ts) Suite admin/ service running locally (typically via parent suite docker-compose up) Suite-internal satellite-provider via env-configurable VITE_SATELLITE_TILE_URL (defaults to http://localhost:5100/tiles/{z}/{x}/{y} when unset). Cookie auth requires same-origin; running the SPA at localhost:5173 and satellite-provider at localhost:5100 cannot send the auth cookie cross-port — recommend reaching satellite-provider through the suite's local nginx OR running it with auth disabled in dev (per AZ-498 risk #2). mission-planner/ keeps its own independent VITE_SATELLITE_TILE_URL.
Stage nginx in container, ARM image :stage-arm nginx /api/<service>/ → http://<service>:8080/ (intra-cluster) Stage suite admin/ service Suite-internal satellite-provider on the same origin (nginx-fronted); cookie auth attached automatically.
Production nginx in container, ARM image :main-arm nginx /api/<service>/ → http://<service>:8080/ Prod suite admin/ service Same as Stage. Replaces the previously-used external OpenStreetMap and Esri tile providers as of cycle 2 / 2026-05-12 (AZ-498) — production deploy is gated on the cross-workspace satellite-provider cookie-auth ticket landing (autodev Step 16).

2. Configuration model

The SPA bundle is fully static. No env vars are read at runtime by the bundle. Every cross-environment difference is resolved at the deployment edge (nginx) or at the suite-service level.

Concern Where it's set Notes
Backend API URL nginx proxy_pass (nginx.conf) — same nginx config across stage / prod Base URLs are intra-cluster service names (http://annotations:8080, etc.); the URL difference between environments is hidden by the orchestrator's DNS
Auth cookie domain Set by suite admin/ service on Set-Cookie UI does not control
Refresh-token lifetime Set by suite admin/ service UI tolerates any TTL
Satellite tile provider URL (main SPA) .env.example declares VITE_SATELLITE_TILE_URL; resolved at build time via getTileUrl() (src/features/flights/types.ts) with DEFAULT_SATELLITE_TILE_URL fallback. Cycle 2 / AZ-498.
Satellite tile provider URL (mission-planner) mission-planner/.env.example declares its own independent VITE_SATELLITE_TILE_URL mission-planner only; not deployed
OpenWeatherMap API key + base URL (main SPA) .env.example declares VITE_OWM_API_KEY + VITE_OWM_BASE_URL; resolved by getOwmBaseUrl() and the flightPlanUtils.ts builder. Closed AZ-448 / AZ-449 (no longer hardcoded).
OpenWeatherMap API key + base URL (mission-planner) mission-planner/.env.example declares VITE_OWM_API_KEY + VITE_OWM_BASE_URL; WeatherService.getWeatherData(lat, lon) returns null and issues NO outbound fetch when the key is unset (fail-soft). Closed cycle 2 / AZ-499. The previously-committed literal value MUST be revoked at the OWM dashboard (manual deliverable — AC-42 / AZ-499 AC-7); STC-SEC1C defends against re-introduction.
Google Geocode API key (mission-planner) mission-planner/.env.example declares VITE_GOOGLE_GEOCODE_KEY; GeocodeService.geocodeAddress(address) returns null and issues NO outbound fetch when the key is unset (fail-soft, console.warn). Closed cycle 2 / AZ-501 (AC-43). The previously-committed literal value MUST be revoked at the Google Cloud Console (manual deliverable — AC-43 / AZ-501 AC-6); STC-SEC1D defends against re-introduction.
AZAION_REVISION Stamped into image at build time For diagnostics

3. .env strategy

Step 4 testability + cycle 2 added a workspace .env.example (resolved by Vite at build time via import.meta.env.VITE_*). Today it declares: VITE_OWM_API_KEY, VITE_OWM_BASE_URL (AZ-448 / AZ-449), and VITE_SATELLITE_TILE_URL (AZ-498). mission-planner/.env.example mirrors the OWM pair (AZ-499), declares its own independent VITE_SATELLITE_TILE_URL, and (AZ-501) adds VITE_GOOGLE_GEOCODE_KEY for the address-search lookup.

Trade-off: Vite resolves import.meta.env.VITE_* at build time, so dist/ is environment-specific once a non-empty VITE_OWM_API_KEY is baked in — the OpenWeatherMap key (and any future build-time config) cannot be changed without a rebuild. This trades promotability for the air-gap-friendly pattern that lets a deploy ship with VITE_OWM_API_KEY="" (no OWM call, fail-soft null return) when the deployment must not touch the internet.

Future direction (still open):

  • Move the OpenWeatherMap call server-side (flights/ service) — would eliminate the bundled key entirely; the env-var hardening in cycle 2 reduces the urgency but does not remove the option.
  • Introduce a runtime /config.json that nginx serves — would let ops change feature flags / tile URLs without rebuilding.
  • OR keep the static bundle and continue using Vite's import.meta.env for build-time injection of safe-to-publish values (current approach).

4. Promotability

The same image (:dev-arm, :stage-arm, :main-arm) is built per branch from the same Dockerfile. Theoretically the :dev-arm image is functionally identical to the :main-arm image except for the AZAION_REVISION label.

In practice: branch separation is the gating mechanism. Once dev → stage → main propagation is normalized, the safer pattern is to build ONE image per commit and re-tag it across environments (immutable image promotion). The Woodpecker pipeline does not implement this today; it rebuilds per-branch.

5. Local-dev quirks

  • Vite dev proxy (vite.config.ts) requires the suite to be reachable on http://localhost:8080. If the parent suite's docker-compose binds to a different port, the developer must edit vite.config.ts (no env-driven override today).
  • bun.lock: committed (per package.json's packageManager field). package-lock.json is gitignored.
  • .idea/, .claude/, .superpowers/: gitignored — IDE / agent metadata.
  • Playwright entries in .gitignore: present but aspirational — Playwright is not installed (Step 57 territory).
  • mission-planner: has its own .env.example declaring VITE_SATELLITE_TILE_URL, (cycle 2 / AZ-499) VITE_OWM_API_KEY + VITE_OWM_BASE_URL, and (cycle 2 / AZ-501) VITE_GOOGLE_GEOCODE_KEY. Runs as a sibling Vite app; not bundled into the deployed image (per AC-31 / NFT-RES-LIM-04). Despite not being deployed, the keys must still be revoked at their respective dashboards because the literals were committed and exist in git history.