163 lines
10 KiB
Markdown
163 lines
10 KiB
Markdown
# Актуальный технический аудит RF4 Spotter — 20 сентября 2026
|
||
|
||
База аудита: ветка `main`, commit `d438c40`, рабочая копия проверена 20.09.2026.
|
||
Изменения до аудита уже существовали в рабочем дереве только в `README.md` и
|
||
`docs/ROADMAP.md`; они сохранены и не смешаны с результатами аудита.
|
||
|
||
Цель — отделить фактически проверенное локально от исторических результатов,
|
||
которые требуют повторного Docker/browser/production-прогона.
|
||
|
||
## Итог
|
||
|
||
Проект представляет собой функциональный single-owner alpha MVP на Astro SSR,
|
||
FastAPI, PostgreSQL, MinIO и Caddy. Кодовая база сейчас проходит локальные
|
||
quality gates: Python — `190 passed, 1 skipped`, Astro check — `0 errors / 0
|
||
warnings / 0 hints`, production build — успешен, web unit — `1 passed`, media
|
||
audit — без issues и orphan-файлов. Production Compose файл корректно
|
||
интерполируется с безопасными временными значениями, а Alembic graph имеет
|
||
единственную голову `0020`.
|
||
|
||
Открытая альфа ещё не готова к объявлению production-ready. Не подтверждены в
|
||
этой сессии: запуск чистого полного Compose stack, фактический `alembic current`
|
||
против PostgreSQL, внешний DNS/TLS/backup/restore, browser acceptance тем,
|
||
административных сценариев и B25 media. Это инфраструктурные и приёмочные
|
||
ограничения, а не обнаруженная ошибка сборки.
|
||
|
||
## Архитектура и границы ответственности
|
||
|
||
| Слой | Текущее состояние | Оценка |
|
||
|---|---|---|
|
||
| Caddy | Production proxy, TLS/Basic Auth для `/admin`, API routing, headers, CSP | готово локально; внешний TLS не проверен |
|
||
| Astro | SSR Node adapter, public/admin pages, server-side form/API bridges | сборка и check проходят |
|
||
| FastAPI | роутеры activity/catalog/media/public/admin/submissions, health/readiness | API contract и тесты проходят |
|
||
| PostgreSQL | SQLAlchemy 2, Alembic, persistent rate-limit/import history | миграционный graph проверен, живая БД не запущена |
|
||
| MinIO/S3 | отдельный app user/policy, Git media proxy и provenance | offline media audit проходит |
|
||
| Scheduler/import | opt-in Compose profiles, общий cooldown/backoff контур | запуск источников намеренно не включён по умолчанию |
|
||
|
||
Архитектурное решение Astro + FastAPI + PostgreSQL сохраняется. API уже
|
||
разделён на роутеры, поэтому старое замечание о монолитном `main.py` из аудита
|
||
10 сентября больше не актуально. `main.py` оставляет composition root,
|
||
middleware, health/readiness и регистрацию роутеров.
|
||
|
||
## Проверки и доказательства
|
||
|
||
| Проверка | Результат | Комментарий |
|
||
|---|---:|---|
|
||
| `.venv/bin/pytest -q` | `190 passed, 1 skipped` | 72 deprecation warnings FastAPI/`asyncio.iscoroutinefunction`; skip — PostgreSQL integration |
|
||
| `npm --prefix apps/web run check` | 0/0/0 | 61 Astro files inspected |
|
||
| `npm --prefix apps/web run build` | passed | SSR Node production build |
|
||
| `npm --prefix apps/web run test:unit` | `1 passed` | Node unit suite |
|
||
| `media_cli --audit` | 704 entries, 0 issues | 466 approved, 226 superseded, 1 duplicate, 11 invalid; no orphans |
|
||
| `media_cli --quality-report` | 253 fish published | 252 are 1024×1024 WebP; one 48×48 fallback remains |
|
||
| `docker compose -f compose.production.yaml config --quiet` | passed | checked with temporary non-secret values only |
|
||
| dev `docker compose up --build --wait` | passed | PostgreSQL, MinIO, API and web healthy; migration service exited 0 |
|
||
| live `/health`, `/ready`, public routes | passed | health/readiness and public `/`, `/waterbodies/`, `/records/` returned expected responses from container network |
|
||
| Alembic `heads` / live `current` | `0020 (head)` | both repository graph and running PostgreSQL verified |
|
||
| waterbody catalog import/audit | `19/19`, 0 failures | canonical snapshot applied; no missing, duplicate or provenance issues |
|
||
| OpenAPI | passed after Q16 fix | `apps/api/export_openapi.py --check` passes with `36 paths`; artifact regenerated from FastAPI, not manually edited |
|
||
| Browser acceptance | not confirmed | in-app browser backend unavailable in the current session |
|
||
|
||
The dev stack was stopped after the checks without removing its named volumes.
|
||
This is a local integration gate, not a production deployment or external
|
||
browser acceptance.
|
||
|
||
## Backend and data layer
|
||
|
||
### Strengths
|
||
|
||
- API endpoints are separated into focused routers and have a tracked OpenAPI
|
||
generator/artifact; Q16 was closed by regenerating the artifact and passing
|
||
the deterministic check.
|
||
- Alembic migrations are linear through `0020`; latest migrations cover
|
||
waterbody provenance, coordinate precision, fish counts and detail fields.
|
||
- Official/community import paths preserve old data on incomplete or failed
|
||
responses, use provenance, and keep network fetching opt-in.
|
||
- Admin media publish/rollback keeps fallback assets and provenance; public
|
||
media is content-addressed and served locally rather than hotlinked.
|
||
- Rate limiting uses a persistent, privacy-preserving HMAC client hash and
|
||
trusted-proxy handling.
|
||
|
||
### Remaining risks
|
||
|
||
- The single-owner admin model still uses a shared Bearer token and proxy Basic
|
||
Auth. A05 (personal accounts, roles, revocation and operator IDs) is correctly
|
||
deferred until the pilot has more than one operator.
|
||
- Public cache is process-local; shared invalidation/Redis is explicitly a
|
||
post-pilot decision and should not be added before measured need.
|
||
- Production query p95 and real data growth are not measured in this workspace.
|
||
The existing query-plan gate is a local fixture gate, not a production SLO.
|
||
- The waterbody canonical index has 19 verified entries, but detail snapshots
|
||
currently cover only the first waterbody. W02–W08 remain open.
|
||
|
||
## Frontend, accessibility and visual system
|
||
|
||
Astro SSR pages include public catalogs, fish/waterbody/spot detail, official
|
||
records, reports, status, media and admin screens. The current implementation
|
||
has semantic light/dark tokens, system/manual theme selection, forced-colors
|
||
rules, nonce-based JSON-LD CSP, noindex/no-store handling for admin/error
|
||
surfaces, responsive pagination and reduced-motion styles.
|
||
|
||
Automated structural checks pass, but visual acceptance is not equivalent to
|
||
`astro check`. B25, D05/D07 and A06 remain open for desktop/mobile light/dark,
|
||
forced-colors, focus order, long data, empty/error states and screenshots.
|
||
|
||
## Security and operations
|
||
|
||
### Confirmed in code/config
|
||
|
||
- Production settings reject demo/short admin, rate-limit and S3 credentials.
|
||
- Production CORS requires explicit HTTPS origins; demo seeding is forbidden.
|
||
- Caddy and API set HSTS, `nosniff`, restrictive referrer/permissions policy,
|
||
anti-framing headers and CSP; Astro uses a per-response nonce for JSON-LD.
|
||
- Production MinIO app credentials are separated from root credentials and
|
||
limited to one bucket's list/location/get/put/delete operations.
|
||
- CI contains locked dependency installation, pip-audit, clean migration,
|
||
Compose E2E and scheduled production-bootstrap drill definitions.
|
||
|
||
### Not yet proven for release
|
||
|
||
- No production server, DNS, TLS certificate, real secrets or external backup
|
||
restore were exercised here.
|
||
- `compose.yaml` intentionally contains local demo defaults; only
|
||
`compose.production.yaml` has fail-fast production secret requirements.
|
||
- The scheduled bootstrap workflow exists, but its latest successful run is a
|
||
repository history fact, not a fresh verification in this workspace.
|
||
- The Docker operator account remains a high-privilege operational boundary;
|
||
SSH/firewall/VPN restrictions belong to deployment hardening.
|
||
|
||
## Media and provenance snapshot
|
||
|
||
The manifest contains 704 records: 466 approved, 226 superseded, one
|
||
provenance-only duplicate and 11 invalid records. Fish quality-upgrade processing
|
||
completed for 226 alternatives; 253 fish assets are published, 252 with
|
||
1024×1024 WebP and one explicit low-resolution fallback. Offline media audit
|
||
reports no checksum/dimension/MIME/provenance/orphan problems.
|
||
|
||
This does not close B25: browser checks for broken images, responsive overflow,
|
||
light/dark presentation and source links are still required. It also does not
|
||
grant new source permissions; Q01 remains the source-rights gate.
|
||
|
||
## Prioritized action plan reflected in ROADMAP
|
||
|
||
1. **Release blockers:** repeat the clean production Compose/bootstrap gate;
|
||
verify readiness, migration current, proxy routing, backup/restore and
|
||
production secret/preflight checks (A07 and open-alpha gate).
|
||
2. **Browser gates:** complete B25 media, A06 admin/accessibility and D07 full
|
||
visual matrix when a Chromium/browser backend is available.
|
||
3. **Waterbody data:** process the remaining 18 detail snapshots under the
|
||
shared cooldown, then complete W03–W08 without assigning unreviewed media
|
||
roles.
|
||
4. **Source governance:** attach durable primary permission evidence and image
|
||
rights before expanding public catalog coverage (Q01).
|
||
5. **After pilot:** personal admin identities (A05/M06), shared cache only after
|
||
measurement, production p95 and external search/analytics integrations.
|
||
|
||
## Scope decisions
|
||
|
||
- No Next.js/Vinext migration, Redis addition, broad CSS rewrite or unrelated
|
||
refactor is justified by this audit.
|
||
- No external source was fetched during this audit.
|
||
- No media was downloaded, replaced or automatically promoted.
|
||
- Historical audits remain historical; this document and `ROADMAP.md` are the
|
||
current decision context.
|