diff --git a/README.md b/README.md index f14a5b7..4d0692e 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,8 @@ RF4DB/RF4-STAT/RF4MAP/RF4 Posts сначала принимаются в изо Production release отделяет Alembic от runtime: одноразовый `migrate` должен успешно завершиться до запуска новой версии API. Перед изменением схемы создаётся backup; совместимый rollback возвращает предыдущие images, несовместимый — восстанавливает предрелизную копию данных вместо непроверенного `alembic downgrade`. +Путь обновления схемы проверяется изолированным `deploy/test-release-upgrade.sh`: предыдущая ревизия получает контрольную запись, обновляется до head, после чего проверяются версия, сохранность записи и новые колонки. + После повторных ошибок scheduler увеличивает паузу экспоненциально до 24 часов и возвращается к 30 минутам после успеха. Публичная страница `/status` показывает свежесть и состояние источников без URL запросов, внутренних ошибок и другой диагностической информации. Подробный план и актуальные чекбоксы находятся в [`docs/ROADMAP.md`](docs/ROADMAP.md). Результаты проверки интерфейса и пять приоритетных UX-пакетов описаны в [`docs/UI_UX_AUDIT.md`](docs/UI_UX_AUDIT.md). diff --git a/deploy/README.md b/deploy/README.md index e2ec59b..4e55169 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -63,6 +63,12 @@ curl -fsS -H "Authorization: Bearer $ADMIN_TOKEN" -o rf4spotter-diagnostics.json ./deploy/test-production-bootstrap.sh ``` +Отдельный upgrade-drill проверяет путь от предыдущей Alembic-ревизии к текущему head и сохранность контрольных данных: + +```bash +./deploy/test-release-upgrade.sh +``` + По умолчанию временно используются только loopback-порты `14321` и `18000`; PostgreSQL и MinIO наружу не публикуются. Контур и volumes удаляются после проверки. Drill успешно пройден 6 сентября 2026 года. Одноразовый `migrate` применяет Alembic до rollout API; при ошибке новый runtime не запускается. API при старте выполняет только идемпотентный seed: в production он добавляет минимальные справочники и точки, а демонстрационные уловы жёстко отключены `SEED_DEMO_DATA=false`. diff --git a/deploy/test-release-upgrade.sh b/deploy/test-release-upgrade.sh new file mode 100755 index 0000000..5d5cecd --- /dev/null +++ b/deploy/test-release-upgrade.sh @@ -0,0 +1,40 @@ +#!/bin/sh +set -eu + +repo=$(CDPATH= cd -- "$(dirname "$0")/.." && pwd) +cd "$repo" +project="rf4-upgrade-$$" +export COMPOSE_PROJECT_NAME="$project" +export POSTGRES_PASSWORD=upgrade-drill-postgres-password +export DATABASE_URL=postgresql+psycopg://rf4:upgrade-drill-postgres-password@db:5432/rf4_spotter +compose="docker compose --env-file .env.production.example -f compose.production.yaml" +previous_revision=48094a7d1b92 +head_revision=20260910_recovery +probe_id=00000000-0000-0000-0000-000000000099 + +cleanup() { + status=$? + if [ "$status" -ne 0 ]; then + $compose ps >&2 || true + $compose logs --no-color db migrate >&2 || true + fi + $compose down --volumes --remove-orphans >/dev/null 2>&1 || true +} +trap cleanup EXIT INT TERM + +$compose up --build -d --wait db +$compose run --rm migrate alembic upgrade "$previous_revision" + +$compose exec -T db psql -v ON_ERROR_STOP=1 -U rf4 -d rf4_spotter -c \ + "insert into fish(id,slug,name_ru,trophy_weight_g) values ('$probe_id','upgrade-probe','Проверка обновления',1234)" >/dev/null + +$compose run --rm migrate + +db_revision=$($compose exec -T db psql -At -U rf4 -d rf4_spotter -c 'select version_num from alembic_version') +probe_count=$($compose exec -T db psql -At -U rf4 -d rf4_spotter -c "select count(*) from fish where id='$probe_id' and slug='upgrade-probe' and trophy_weight_g=1234") +recovery_columns=$($compose exec -T db psql -At -U rf4 -d rf4_spotter -c "select count(*) from information_schema.columns where table_schema='public' and ((table_name='submission_attempt' and column_name in ('idempotency_key','catch_report_id','payload_hash')) or (table_name='import_record_event' and column_name in ('changes','provenance')))") + +test "$db_revision" = "$head_revision" +test "$probe_count" = "1" +test "$recovery_columns" = "5" +printf 'Release upgrade passed: %s -> %s, control data preserved\n' "$previous_revision" "$head_revision" diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 491a703..fd046cd 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -44,7 +44,7 @@ - [x] **Q06 · Performance baseline.** На локальной production-сборке после оптимизации hero: performance 100, LCP 1,66 с, FCP 1,15 с, CLS 0,023, TBT 9 мс. Устранены найденные Lighthouse проблемы контраста и accessible name; методика и бюджеты записаны в [performance-baseline.md](performance-baseline.md). Полевой INP измеряется только после запуска. - [x] **Q07 · Нагрузочная методика.** Добавлен read-only runner для activity, records, staging и moderation с warm-up, p50/p95/max, распределением HTTP-кодов и ограниченной concurrency. Методика фиксирует контекст запуска, ступени нагрузки и бюджеты, но не объявляет результатов до трёх прогонов на целевом сервере. - [x] **Q08 · Политика MinIO.** Production bootstrap создаёт bucket и отдельную policy только с bucket location/list и get/put/delete его объектов. App credentials проверяются через bucket stat и отрицательную проверку глобального list; API больше не требует `ListAllMyBuckets` и не пытается создавать bucket. Root credentials остаются только у init-задачи. -- [ ] **Q09 · Release-процедура — код готов.** Миграции вынесены из API runtime в одноразовый `migrate` service; API запускается только после успешного Alembic upgrade. Документированы backup, rollout и два варианта отката. Осталось проверить upgrade с предыдущей ревизии на копии данных в изолированном Compose drill. +- [x] **Q09 · Release-процедура.** Миграции вынесены из API runtime в одноразовый `migrate` service; API запускается только после успешного Alembic upgrade. Документированы backup, rollout и два варианта отката. Изолированный drill поднимает предыдущую ревизию схемы, добавляет контрольные данные, обновляет до head и проверяет их сохранность и новые колонки. - [ ] **Q10 · Документальная ревизия.** После каждого пакета обновлять этот файл и README, не возвращая закрытые R/A/T-задачи в активный backlog. ### Дополнения после ревизии PROJECT_AUDIT_2026-09-10