Files
Oleksandr Bezdieniezhnykh 51b572108a
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
[AZ-484] Cycle 1 Steps 12-16: docs, security, perf, deploy report
Captures the post-implementation autodev gates for AZ-484 multi-source
tile storage:

- Step 12 (Test-Spec Sync): added 7 AC rows (AZ-484 AC-1..AC-7) and a
  PT-07 NFR row to traceability-matrix.md; added PT-07 scenario to
  performance-tests.md.
- Step 13 (Update Docs): refreshed data_model.md (tiles columns +
  indexes + selection rule + UPSERT contract + migrations 012/013),
  module-layout.md (Common/Enums section with L-001 guidance,
  DataAccess imports-from now lists 6 sites), 6 module / component
  docs to reflect the new repo signatures, source/captured_at fields,
  and Dapper enum bypass workaround. ripple_log_cycle1.md records
  zero out-of-scope ripple.
- Step 14 (Security Audit): PASS_WITH_WARNINGS - 0 Critical, 0 High,
  5 Medium, 5 Low. AZ-484 itself added zero new findings. Hardening
  items (Postgres default creds, .env in build context, GMaps key
  rotation, ASP.NET Core 8.0.21 -> 8.0.25, rate limiter) recorded
  for separate tickets.
- Step 15 (Performance Test): all PT-01..PT-07 scenarios Unverified
  (non-blocking); PT-07 baseline-comparison harness deferred to a
  leftover for next cycle.
- Step 16 (Deploy): cycle deploy report covering migration safety,
  rollback path, post-deploy verification, security caveats.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 10:03:05 +03:00

6.1 KiB

Deploy Report — Cycle 1 (AZ-484)

Date: 2026-05-11 Cycle: 1 Scope: Multi-source tile storage schema (AZ-484) and supporting documentation/security artifacts.

What is shipping

Code changes (already committed)

Commit Subject
5ba58b6 [AZ-484] [AZ-483] Add task spec + tile-storage v1.0.0 contract draft
687d6bd [AZ-484] Multi-source tile storage: source + captured_at
e9d6db0 [AZ-484] Fix multi-source tile reads: drop Dapper enum handler

Database migration

  • 013_AddTileSourceAndCapturedAt.sql — runs on first startup of the new image. Transactional (BEGIN; … COMMIT;), idempotent against partial replays. Adds source (VARCHAR(32) NOT NULL DEFAULT 'google_maps') + captured_at (TIMESTAMP NOT NULL); backfills both for every pre-existing row; replaces 4-col idx_tiles_unique_location with 5-col idx_tiles_unique_location_source.

Documentation, test-spec, audit artifacts (uncommitted in working tree, scoped to this deploy commit below)

  • _docs/02_document/data_model.md, module-layout.md, 6 module / component docs — Step 13 (Update Docs).
  • _docs/02_document/ripple_log_cycle1.md — Step 13 ripple analysis.
  • _docs/02_document/tests/performance-tests.md, traceability-matrix.md — Step 12 (Test-Spec Sync) — added AZ-484 ACs and PT-07.
  • _docs/05_security/ (5 files) — Step 14 (Security Audit) — verdict PASS_WITH_WARNINGS.
  • _docs/06_metrics/perf_2026-05-11_cycle1_az484.md — Step 15 (Performance Test) — all scenarios Unverified, non-blocking.
  • _docs/_process_leftovers/2026-05-11_perf-pt07-harness.md — deferred PT-07 harness work.
  • _docs/_autodev_state.md — autodev pointer.

Pre-deploy checks (recap)

Gate Outcome
Step 11 — Run Tests All unit + integration tests pass against the post-AZ-484 build (213 unit + 5 new AZ-484 integration).
Step 14 — Security Audit PASS_WITH_WARNINGS — 0 Critical, 0 High, 5 Medium, 5 Low. AZ-484 itself added zero new findings. Top hardening items recorded in _docs/05_security/security_report.md.
Step 15 — Performance Test All scenarios Unverified (PT-07 harness deferred to next cycle). Non-blocking per test-run perf-mode rules.
dotnet format whitespace --verify-no-changes Passed (part of scripts/run-tests.sh).

Migration safety

  • Idempotent: re-running migration 013 against an already-migrated database is a no-op (ADD COLUMN IF NOT EXISTS, DROP INDEX IF EXISTS, CREATE UNIQUE INDEX IF NOT EXISTS patterns).
  • Backwards compatible: pre-AZ-484 application code that reads tiles still works — source defaults to 'google_maps', captured_at is backfilled to created_at. Vestigial columns version / maps_version are preserved nullable.
  • No data loss: the only DDL change is dropping idx_tiles_unique_location (replaced by idx_tiles_unique_location_source); rows are not touched except by the backfill UPDATE.
  • Lock duration: ALTER TABLE on a tiles table with O(100K-1M) rows takes a few seconds for ADD COLUMN (metadata-only in PG 11+) and a few seconds for the UPDATE backfill on existing data. Acceptable for a maintenance window-free deploy assuming current row counts (_docs/02_document/data_model.md storage estimate: 100K-1M tiles).

Rollback plan

The migration is forward-only by DbUp design (no automatic down migrations). In the unlikely event AZ-484 needs to be reverted in production:

  1. Re-deploy the previous image (registry.../azaion/satellite-provider:<previous-tag>). The pre-AZ-484 code reads * from tiles and ignores the new columns — it will function correctly against the migrated schema.
  2. The 5-col idx_tiles_unique_location_source is a strict superset of the pre-AZ-484 4-col index for the only producer pre-AZ-484 sees (source = 'google_maps'); pre-AZ-484 UPSERT on (lat, lon, tile_zoom, tile_size_meters, version) would fail conflict detection against the new index — so do not roll the schema back, only roll the application back. The schema is forward-compatible with the old code.
  3. If a true schema rollback is ever needed, write a follow-up migration 014_RevertAz484.sql rather than editing 013 in place.

Post-deploy verification

After the new image is deployed and migrations have run:

  1. Hit GET /api/satellite/region/{any-existing-region-id} — confirm 200 + status JSON (smoke test that the tiles reads still parse with the new entity shape).
  2. Hit GET /api/satellite/tiles/latlon?Latitude=...&Longitude=...&ZoomLevel=18 for a known cell — confirm 200 + tile bytes.
  3. Run a single psql query: SELECT count(*) FROM tiles WHERE source IS NULL OR captured_at IS NULL; — expected 0.
  4. Tail Serilog logs for Slow GetTilesByRegionAsync warnings (>500ms) for the first hour. A spike here would be the earliest signal of a perf regression vs. the (unmeasured) pre-AZ-484 baseline.

CI/CD path

The project's .woodpecker/02-build-push.yml builds and pushes the image on push to dev, stage, main. The dev branch is the standard target per .cursor/rules/git-workflow.mdc. Pushing the new commit to origin/dev triggers the pipeline; no manual deploy steps are needed beyond the git push.

Push policy: per git-workflow.mdc, the autodev does NOT push without explicit user request. The next user prompt will offer the push as an explicit option.

Security caveats carried into this deploy

The Security Audit (Step 14) flagged 5 Medium findings that should be tracked as separate hardening tasks before public-network exposure but do NOT block this internal deploy:

  • S1+S2+I5 — Postgres default credentials in appsettings.json + docker-compose.yml; .env not in .dockerignore.
  • S4 — Google Maps API key needs rotation + .env.example.
  • D1 — Bump Microsoft.AspNetCore.OpenApi 8.0.21 → 8.0.25 (CVE-2026-26130 SignalR DoS — not reachable in this app).
  • I3 — Wire Microsoft.AspNetCore.RateLimiting.

None of these are AZ-484 regressions; they are pre-existing items that today's audit surfaced. Tracking them as separate Jira tickets is recommended but not enforced by this gate.