[P0] Off-box бэкап tradein-postgres + restore-тест + hardening backup-скрипта #2203
Closed
opened 2026-07-02 19:17:23 +00:00 by lekss361
·
9 comments
No Branch/Tag specified
main
fix/3469-showcase-schedule
fix/3443-caddy-selfdowntime
fix/3463-db-statement-timeout
fix/3448-caddy-only-detection
fix/metrics-deploy-reloads-prometheus
feat/landing-showcase-band
fix/3452-corridor-advisory-zone
fix/alert-value-is-not-the-ratio
fix/3449-geocoder-cancel-orphan
fix/3451-tvf-deals-rooms
fix/msk-collector-net-retry
feat/msk-yandex-import
fix/3051-fetch-deals-rooms-dropped
feat/msk-collector-cian
fix/3256-asking-to-sold-buckets
fix/3083-estimate-throughput
fix/3274-part2b-gate
fix/3274-part2a-caddy-retry
fix/perimeter-smoke-retry-on-no-response
fix/3274-zero-downtime-frontend
fix/3274-part1-deploy-swap
fix/3412-cian-instance-relaunch
fix/3415-bucket-done-only-if-phases-ok
chore/backend-pool-wiring-tails
fix/3398-pool-ops-off-event-loop
fix/3402-followups-ban-kinds-curl
feat/3404-proxy-run-attribution
fix/cian-captcha-is-platform-refusal
refactor/3390-single-runs-module
fix/3398-estimator-valuations-proxy-pool
fix/3386-estimator-imv-proxy-pool
fix/3394-cian-sweep-houses-proxy-pool
fix/3393-interrupted-runs-outside-streaks
fix/drain-marks-inflight-app-tasks
fix/3384-no-proxy-at-batch-start
fix/3197-yandex-newbuilding-proxy-pool
fix/3376-price-history-decimal-slips
fix/backend-proxy-pool-flags
fix/3197-cian-history-backfill-proxy-pool
fix/3288-sidecar-ban-status-code
fix/3375-yandex-fullload-on-bucket-contract
fix/3380-deploy-metrics-alloy-recreate
fix/3354-alloy-query-secret-scrub
fix/3360-admin-prefix-anon-404
fix/3368-yandex-leaf-complete-flag
fix/3369-domclick-cancel-checkpoint
fix/3225-domklik-diff-percent
fix/smoke-history-path
fix/3288-breaker-block-kind
fix/3355-drain-mark-fullloads
fix/3191-yandex-detail-completeness
fix/3359-containment-cian-yandex
fix/3323-payment-init-fail-409
fix/3172-freshness-by-data
fix/3288-avito-ban-per-source
fix/3253-domclick-house-fields
fix/3312-defer-interval-minutes
fix/3324-rbac-401-oracle
fix/3274-deploy-window-error-page
fix/3343-auth-latency-flaky
fix/3315-exhaustive-containment-skip
fix/3338-backfill-save-false
fix/3339-thin-market-badge
fix/3154-glitchtip-secret-log-leak
fix/3333-drain-mark-all-sweeps
fix/3323-imv-thin-market-gate
fix/3324-mera-perimeter
fix/3323-coverage-copy-honesty
fix/3332-domclick-counter-identity
fix/3324-ptica-deploy-gate
fix/3316-role-single-source
fix/3319-citysweep-checkpoint
fix/3322-rosseti-stable-key
fix/3320-v2-honest-zeros
fix/3321-draft-fields-survive
fix/mera-mobile-nav-and-sticky
fix/audit-form-ux
fix/audit-coverage-500
fix/audit-dkp-price
fix/audit-accuracy-window
fix/audit-faq-contradiction
fix/perimeter-smoke-after-payments
feat/b2c-landing-honest-copy
feat/b2c-landing-live-numbers
feat/b2c-v3-becomes-root
feat/b2c-v3-port-v1-blocks
feat/b2c-report-redesign
feat/b2c-landing-v3-full
feat/3192b-yandex-phones
feat/3168-backfill-cursor-resume
fix/3118-domclick-no-proxy
fix/3170-yandex-combo-checkpoint
feat/3074-newbuilding-sweep-resume
fix/3163-infra-topic-default
fix/3156-tgbot-error-type
feat/3163-infra-topic-split
fix/3161-alertmanager-route-prefix
fix/3155-prometheus-no-alertmanager
feat/2997-drop-listings-geom-idx
fix/3122-boot-reap-observable
feat/3122-boot-reap
feat/3051-houses-region-code
feat/3074-cian-anchor-checkpoint
feat/3051-region-registry
fix/2656-anchor-ratio-freshness
fix/3114-scrub-credentials-in-logs
fix/3078-grafana-single-auth
fix/3081-honest-progress
fix/3063-pro-seller-derive
fix/3074-checkpoint-survives-claim
fix/3082-estimate-concurrency
fix/3044-enriched-total-seen
fix/telegram-pin-selectel-override
chore/compose-host-parameterised-resources
fix/revisit-floor-lateral-lookup
fix/avito-detail-fields
fix/3034-avito-fingerprint
fix/avito-offers-per-page
feat/3033-avito-secondary-filter
fix/2203-restore-drill-readiness
feat/2203-backup-staleness-and-forgejo
fix/2990-clean-start-initdb
fix/2924-yandex-jk-resolve-tried-at
fix/2992-upsert-distinct-gate
fix/2998-rosreestr-q2-partitions
feat/2936-null-penalty-flag
fix/2996-mislocated-houses-watchdog
fix/1781-secondary-only-param
fix/2934-risks-coverage
fix/2464-three-small
fix/2464-two-docstrings
fix/2464-zouit-label
fix/2464-building-pct-guard
fix/2464-download-binary-retry
fix/2986-permits-key
fix/2464-tep-docstring
fix/2464-act-date-backfill
fix/2464-area-bin-null
fix/2464-act-date-citation
fix/2464-detect-kind
fix/2464-status-negation
fix/2464-objective-zombie-sweep
fix/2464-inert-retry-config
fix/2464-default-profile-unique
fix/2464-zombie-any-running
fix/2464-catalog-skipped-counter
fix/2464-heat-loader-tx
fix/2464-objective-run-stuck
fix/2464-catalog-waf-breaker
fix/2464-lock-key-order
fix/2464-backfill-waf-abort
fix/2464-docs-vs-code
fix/2464-land-reservation-dedup
fix/2464-manual-list-validation
fix/2464-capacity-savepoints
fix/2464-leads-window-naming
fix/2464-zouit-count-label
fix/2464-catalog-batch-commits
fix/2464-html-zoning-fallback
fix/2950-lock-wait-observable
fix/2956-freshness-counts-failed-harvest
fix/2950-host-lock
fix/2953-nominatim-throttle
fix/2950-deploy-docker-lock
fix/2464-ird-lookups-savepoint
fix/2464-parcels-savepoint-pair
fix/2674-deal-floor-display
docs/2854-stale-justifications
chore/2857-drop-placeholder-columns
fix/2855-probe-protected-path
fix/2674-has-panorama
fix/house-imv-anchor-era
fix/2674-quality-cadastre-column
fix/sber-freshness-guard
fix/dkp-corridor-as-of
fix/scheduler-resume-checkpoint
fix/quarter-target-from-neighbour
fix/2687-domclick-ban-kind-platform
fix/2814-address-backfill
fix/2677-house-anchor-renovation
feat/tradein-paid-retention
chore/ci-config-cleanup
feat/mera-b2c-privacy
feat/tradein-payments-schema
chore/2674-dead-code-sweep
fix/2674-matching-tiers-honesty
fix/2674-avito-full-load-coverage
fix/2674-admin-metrics-honesty
fix/2674-writers-honor-schema
fix/2674-alerts-actually-fire
fix/2679-scraper-deploy-parity
fix/2674-house-imv-params
fix/2666-discount-plausibility-gate
feat/2435-cian-house-enrichment
fix/2657-domclick-block-not-done
feat/2571-login-throttle
fix/2660-display-freshness-segment
fix/2658-loud-skip-status
fix/2603-geocode-city-hint-tails
feat/2600-per-source-proxy-health
feat/tradein-v2-exposure-in-result-card
fix/tradein-avito-browser-proxy-pool
chore/tradein-cut-wasteful-scraping
fix/tradein-v2-deals-fallback-visible
fix/tradein-city-stamp-geo-guard
fix/tradein-cian-oblast-secondary
fix/tradein-implausible-build-year
fix/tradein-snapshot-query-perf
fix/tradein-asking-sold-city-scope
chore/tradein-purge-dead-mobileproxy
feat/tradein-asocks-rotation
fix/tradein-region-code-foreign-cities
fix/tradein-proxy-pool-self-healing
fix/tradein-backfill-listing-city-from-url
fix/tradein-geocode-queue-active-only
fix/tradein-geocode-city-hint
chore/tradein-remove-yandex-scripts
fix/tradein-listing-city-from-sweep
chore/tradein-remove-yandex-geocoder
chore/tradein-remove-n1
fix/tradein-geocoder-fail-closed
fix/tradein-ui-city-label-clip
feat/tradein-ui-city-hint
fix/tradein-coords-backfill-city-gate
fix/tradein-geocoder-city-default
fix/tradein-anchor-geo-scope
fix/tradein-avito-detail-oblast
feat/tradein-price-bands-refresh
feat/tradein-caddy-cutover
fix/tradein-team-nav-and-401
feat/tradein-team-dashboard
fix/tradein-team-list-order
feat/tradein-team-api
feat/tradein-login-ui
feat/tradein-auth-core
feat/tradein-auth-password-foundation
feat/tradein-auth-users-schema
fix/tradein-rbac-test-user2-expired
fix/tradein-auth-revoke-user2
fix/2013-avito-cohort-null
fix/rbac-test-user2-expired
fix/expire-brusnika-trial-access
feat/tradein-domclick-house-sku-schema
chore/design-sync-tradein
fix/tradein-deploy-scraper-paths-filter
fix/tradein-no-numberless-house-insert
fix/tradein-dedup-fias-pass-no-geoguard
feat/tradein-fias-estimate-frontend
fix/tradein-dedup-by-fias
feat/tradein-fias-tier-matching
fix/tradein-v2-uiux-p1
fix/objective-lots-dedup-1964
fix/audit-followups-1953
feat/concept-house-picker-1965-stage3b
feat/concept-house-catalog-1965-stage3a
feat/concept-live-massing-1965-stage2b
feat/concept-recompute-1965-stage2a
feat/concept-section-1965-stage1
fix/best-layouts-per-object-snapshot-1956
fix/deficit-segmentation-1959
feat/tradein-hedonic-ground-floor
fix/report-map-points-1961
fix/report-microcopy-1963
fix/report-nspd-zoning-1962
fix/report-frontend-display-1953
perf/tradein-estimate-audit
perf/best-layouts-objects-first
fix/171-migration-path
perf/171-objective-crm-report-month-idx
fix/1926-app-log-stdout
fix/estimator-tiebreaker-nanalogs
fix/1917-fetch-json-network-retry
fix/1926-scrape-runs-total-seen
fix/1781-house-fk-source-identity
feat/39-osrm-per-category
feat/1746-utility-infra-map
fix/test-849-savepoint-count
fix/parking-economics-by-class
fix/zouit-engineering-area-gate
fix/zoning-resolution-decouple
feat/dcf-velocity-schedule
feat/zone-regulation-backfill
chore/mock-financial-estimate
fix/finmodel-split-disclosure-threshold
feat/finmodel-financing
feat/finmodel-sitefinder-bridge
feat/finmodel-dcf
feat/finmodel-price-calibration
feat/finmodel-cost-cascade
audit/1871-p2-estimator-dedup-split
audit/1871-p2-avito-coord
audit/1871-p3-uiux
audit/1871-p2-invest-moi
audit/1871-p2-velocity-market
audit/1871-p1-3-isreal-stubs
audit/1871-p1-2-ghost-anchor-guard
audit/1871-p1-scenarios-collapse
revert/site-finder-v2
fix/v2-remove-resource-legend
fix/v2-map-legend-position
feat/site-finder-v2-map-light-polish
rollback/site-finder-home-light
feat/site-finder-v2-cockpit
rollback/sf-old-analysis-design
feat/ptica-tabs-6-6-reports-params
fix/ptica-vri-row
feat/ptica-map-glyphs-sitefinder-dark
fix/ptica-3d-preview-product-verdict
fix/ptica-button-fontsize
fix/ptica-parity-data-mapping
chore/ptica-iso-preview-spin
fix/ptica-inter-map-product
fix/ptica-visual-parity
fix/ptica-left-rail
feat/ptica-cockpit-complete-bottom
feat/ptica-default-and-rich-map
feat/ptica-real-ksit-frontend
feat/tradein-ekb-geoportal-buildings
fix/sf-feedback-batch
feat/avito-newbuilding-sweep
feat/browser-concurrent-pool
fix/backfill-kadastr-column
fix/avito-proactive-ip-rotate
feat/activate-domclick-sweep
feat/avito-newbuilding-capture
fix/house-id-fk-realtime-link
fix/migration-162-table-if-exists
feat/riasurt-sverdl-layers-108
fix/sber-dataset-paths-902
fix/conflict-resolution-freshness-1539
feat/objective-lots-history-writer-307-obj6
feat/velocity-mv-61
fix/objective-mapping-is-reviewed-gate-307-obj2
fix/cian-detail-rich-fields
fix/avito-novostroyki-segment
feat/yandex-novostroyki-newflat
fix/ci-dedup-runner-storm-1709
fix/emiss-pk-granularity-1687
feat/listings-segment-param-1188
fix/inn-regex-word-boundary-1682
fix/excel-deficit-horizon-1590
fix/admin-scrape-validation
fix/admin-leads-interval-cast-1694
fix/dkp-corridor-doc-p10p90-1695
fix/weather-wind-d-allnone
test/residential-zone-rawprops-1681
fix/domrf-badge-regex-narrow-1686
feat/yandex-camoufox-transport
fix/score-sat-factor-1509
fix/base-pace-room-bucket-1593
fix/gate-verdict-no-blocker-1617
fix/confidence-deal-count-window-1637
fix/match-economics-1511-1512
fix/listings-partial-indexes-1398
fix/smart-suggestions-threshold-1503
fix/dkp-corridor-percentile-1520
fix/enrich-economics-window-1513
fix/leads-stats-window-1383
fix/poi-score-scale-1486
fix/geo-weight-floor-1633
fix/inn-regex-context-1640
fix/domrf-status-classify-1609
fix/emiss-period-dedup-1606
fix/cian-paginate-tail-1393
fix/normalize-zero-fill-guard-1638
fix/supply-view-devgroup-key-1650
fix/residential-zone-detect-1353
fix/score-label-threshold-1357
fix/trend-ratio-vprior-zero-1508
fix/district-median-dedup-1352
fix/supply-layers-overlap-1355
fix/pdf-expires-at-1530
fix/quartirography-area-bucket-1406
fix/cad-zones-multipolygon-1344
fix/sold-pct-market-verdict-1407
fix/week-review-finish
fix/week-review-backend-v2
feat/plan-vectorization-spike-299
fix/1668-analyze-confidence
fix/1667-metro-block
fix/1666-layout-velocity-beat
chore/remove-n1-scraper
fix/cian-kitchen-area
feat/yandex-detail-backfill
feat/avito-detail-backfill
fix/best-layouts-bucket-normalization
fix/gknspecial-incremental-commit-per-prefix
fix/okn-objects-full-registry-load
fix/parcel-ird-overlap-except-expand
fix/report-assembler-confounded-keys
fix/job-settings-json-persist-v2
fix/nspd-geo-soft-time-limit-passthrough
fix/nspd-soft-time-limit-v2
fix/pilot-request-modal-validation
fix/recommend-mix-saturation-latest-snapshot
fix/scrape-cadastre-fail-counter-v2
fix/izyatie-ocr-cad-normalize
fix/job-settings-panel-json-state-persist
fix/noise-loader-savepoint-per-row
fix/objective-sync-config-bare-except
fix/parcel-snapshot-mdash-double-escape
fix/poi-loader-leap-year-date-replace
fix/scrape-cadastre-permanent-fail-counter
fix/usermenu-analyst-role-label
feat/location-948b-r
feat/location-entity-948b
feat/insight-entity-948a
feat/analyst-role-audit-962
feat/cbr-inflation-macro-946
feat/cian-zhk-resolve-972
perf/forecast-parallel-horizons-1129
feat/newbuilding-enrich-backfill-972
feat/emiss-macro-indicators-946
feat/rosstat-emiss-macro-946
ci/frontend-vitest-job
chore/frontend-vitest-wkt-tests
feat/forecast-meta-footer
feat/forecast-future-supply-competitors
feat/forecast-docx-pptx-buttons
feat/forecast-scoring-panel
feat/forecast-product-tz-block
feat/market-map-layers-999
feat/forecast-chart-section6
feat/forecast-export-pptx-959
feat/forecast-export-docx-959
feat/forecast-export-ui-959
feat/forecast-export-telegram-959
feat/forecast-export-md-959
feat/analyze-response-contract-961
feat/competitor-velocity-spatial-fallback-968
fix/frontend-healthcheck-hostname
feat/analyze-market-coords-999
fix/site-finder-entry-crash-1001
feat/horizon-selector-996
feat/forecast-section-998
feat/forecast-endpoint-horizon-enqueue
feat/forecast-celery-task-persist
feat/forecast-orchestrator-service
feat/demand-supply-months-of-inventory
feat/wire-district-resolver
feat/district-vocab-reconciliation
fix/affordability-market-spread
fix/backtest-sig-gate
feat/wire-978-almon-rate-regime
feat/backtest-oos-almon-seasonal
ci/forgejo-pytest-gate
fix/tradein-praktika-logo-form-scroll
feat/yandex-exhaustive-price-room
feat/794-sber-time-adjust
chore/bot-harness-tuning
docs/agent-usage-throttle-qa-terminal
fix/avito-sweep-single-run-guard
chore/analyst-inbound-queue-tradein-db
feat/801-preview-full-wt
chore/bot-safety-followups
feat/tradein-avito-imv-fix
feat/tradein-repair-coef-calibration
feat/tradein-avito-houses-fix
feat/tradein-address-precision
feat/tradein-backfill-prioritize-listings
feat/tradein-geocode-deals-nominatim
feat/tradein-geocode-deals-from-houses
feat/tradein-same-building-match
feat/claude-envvars-and-stale-cron
No results found.
Labels
Clear labels
Находки полного мульти-агентного ревью (Claude Fable 5, 2026-06-09)
Новое ТЗ от Ген Геныча (июнь 2026): Site Finder v2 — ИИ-прогноз продуктовой стратегии девелопера. Актуальный приоритет.
Admin UI / internal tools / pipeline tracker
Аналитика данных / matching
Authentication / authorization / multi-tenancy
Автоматизация / cron / scheduler
Something isn't working
Коммерческая воронка / пилоты / pipeline / реестр ПО
Operational housekeeping
Forgejo Actions / build pipeline
152-ФЗ / реестр ПО / legal / TOS
Data sources, parsers, ETL
Уникальные данные — sales tracker, CRM aggregation
README / runbooks / onboarding
This issue or pull request already exists
Developer experience / build speed
New feature or request
Feedback from Max (Senior partner)
Generative Design — concept generation engine
Pending team sync / decision
Human review/decision required
Monitoring / metrics / logs / Sentry / Uptime
Kill-switch — all autonomous bots pause
Latency / throughput / DB query tuning
Critical / production-blocker
High priority
Normal priority
Низкий приоритет (follow-up, tech-debt)
Backend Python — FastAPI, Celery, scrapers
DB migrations, indexes, SQL
docker-compose, Caddy, workflows
Frontend — Next.js, React, TypeScript
Tests, smoke, Playwright
Скрапперы (Avito/Cian/Yandex/Rosreestr)
Security audit / secrets / vulnerabilities
Site Finder scoring quality & data layer
Stage 1: Generative MVP (нед 2-7)
Stage 2: Site Finder MVP (нед 8-12)
Blocked — needs human intervention
Closed, completed
Raw/fuzzy task filed by human — auto-analyst подхватывает: code-archeology + декомпозиция в actionable scope/* + status/ready (или split на под-issues)
Reviewer/QA вернул worker на доработку — worker сам чинит свой PR (fixup), НЕ требует human (в отличие от status/blocked)
PR merged, awaiting smoke test
Ready for pickup by worker bot
PR open, awaiting code review
Work in progress (worker claimed)
Технический долг
Trade-In MVP проект
User experience / responsive / conversion
Week review 1 — находки multi-agent аудита проекта (2026-06-14)
This will not be worked on
Исходно-разрешительная документация — слой ограничений участка для analyze-таблицы
Trade-In Estimator — проект оценки вторичного жилья
Fable 5 ревью
Находки полного мульти-агентного ревью (Claude Fable 5, 2026-06-09)
GG-форсайт
Новое ТЗ от Ген Геныча (июнь 2026): Site Finder v2 — ИИ-прогноз продуктовой стратегии девелопера. Актуальный приоритет.
admin
Admin UI / internal tools / pipeline tracker
analytics
Аналитика данных / matching
auth
Authentication / authorization / multi-tenancy
automation
Автоматизация / cron / scheduler
bug
Something isn't working
business
Коммерческая воронка / пилоты / pipeline / реестр ПО
chore
Operational housekeeping
ci
Forgejo Actions / build pipeline
compliance
152-ФЗ / реестр ПО / legal / TOS
data
Data sources, parsers, ETL
data-moat
Уникальные данные — sales tracker, CRM aggregation
docs
README / runbooks / onboarding
duplicate
This issue or pull request already exists
dx
Developer experience / build speed
enhancement
New feature or request
feedback/max
Feedback from Max (Senior partner)
generative
Generative Design — concept generation engine
needs-discussion
Pending team sync / decision
needs-human
Human review/decision required
observability
Monitoring / metrics / logs / Sentry / Uptime
pause-bots
Kill-switch — all autonomous bots pause
performance
Latency / throughput / DB query tuning
priority/p0
Critical / production-blocker
priority/p1
High priority
priority/p2
Normal priority
priority/p3
Низкий приоритет (follow-up, tech-debt)
scope/backend
Backend Python — FastAPI, Celery, scrapers
scope/db
DB migrations, indexes, SQL
scope/devops
docker-compose, Caddy, workflows
scope/frontend
Frontend — Next.js, React, TypeScript
scope/qa
Tests, smoke, Playwright
scrapers
Скрапперы (Avito/Cian/Yandex/Rosreestr)
security
Security audit / secrets / vulnerabilities
site-finder
Site Finder scoring quality & data layer
stage/1
Stage 1: Generative MVP (нед 2-7)
stage/2
Stage 2: Site Finder MVP (нед 8-12)
status/blocked
Blocked — needs human intervention
status/done
Closed, completed
status/needs-analysis
Raw/fuzzy task filed by human — auto-analyst подхватывает: code-archeology + декомпозиция в actionable scope/* + status/ready (или split на под-issues)
status/needs-fix
Reviewer/QA вернул worker на доработку — worker сам чинит свой PR (fixup), НЕ требует human (в отличие от status/blocked)
status/qa
PR merged, awaiting smoke test
status/ready
Ready for pickup by worker bot
status/review
PR open, awaiting code review
status/wip
Work in progress (worker claimed)
tech-debt
Технический долг
tradein
Trade-In MVP проект
ux
User experience / responsive / conversion
week ревью 1
Week review 1 — находки multi-agent аудита проекта (2026-06-14)
wontfix
This will not be worked on
ИРД
Исходно-разрешительная документация — слой ограничений участка для analyze-таблицы
вторичка
Trade-In Estimator — проект оценки вторичного жилья
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
ИРД
вторичка
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#2203
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Эпик: #2200
Находка (Ops, CRITICAL, verified): все бэкапы локальные —
/opt/gendesign/backups/tradein/на том же/dev/vda1, что и/var/lib/docker.backup-tradein-db.sh:16-42не имеет remote-upload; S3-путь вops/backup.shмёртв (нет/etc/default/gendesign-backup). Один сбой диска/компрометация/rm= БД (4.3ГБ корпуса за месяцы) + 7 дампов + Forgejo одновременно. Плюсbackup-tradein-db.sh:27pg_dump 2>/dev/nullглотает stderr (тихий partial-дамп проходит), логи в/tmp(стёрты на reboot).Acceptance:
MIN_DUMP_BYTESfloor, stderr не глотать, алерт если cron не отработал..env.runtime(иначе pgp_sym_encrypted CIAN-cookie в дампах недекодируемы).Scope:
tradein-mvp/deploy/backup-tradein-db.sh,ops/. needs-human: внешнее хранилище/креды.needs-human (night shift, 2026-07-03): off-box бэкап tradein-postgres требует внешнего хранилища и кредов вне коробки — провижининг за человеком. Что нужно: (1) выбрать хранилище (S3-совместимое / другой VPS / rclone-таргет), (2) создать креды и положить их на VPS вне git, (3) сказать боту — скрипт pg_dump+ротация+restore-тест в PR сделаем по готовому таргету (код-часть bot-doable, отмечено в issue). Без off-box копии единственный бэкап живёт на той же коробке, что и БД (single point of loss).
По решению user (2026-07-03): оставляем открытым, приоритет понижен до минимального (p0 → p3). Off-box бэкап остаётся в бэклоге как tech-debt-страховка.
Проверено на проде 2026-08-20 — за 7 недель ничего не изменилось, находка полностью актуальна.
Свежие доказательства
В логе бэкапа за сегодня буквально:
/etc/default/gendesign-backupпо-прежнему не существует. В/opt/gendesign/backups— 12 ГБ дампов на том же диске, что и базы: gendesign 7 × 1.4 ГБ, tradein 7 × 285 МБ. Диск занят на 69 % (99 из 145 ГБ).Уточнение к области поражения: на той же машине лежит ещё и Forgejo со всем исходным кодом. То есть одна виртуалка держит прод обоих продуктов, обе базы, все бэкапы и git-сервер — отказ диска или блокировка аккаунта уносят всё одновременно, и восстанавливаться будет не из чего и нечем.
Два дефекта сверх перечисленных в issue
pg_dumpне включает роли иGRANTпо определению — нужен отдельныйpg_dumpall --globals-only. Без них восстановление в чистый кластер даёт базу без прав доступа.gzip -tи трейлер-- PostgreSQL database dump complete. Тихо обрезанный архив пройдёт проверкуMIN_DUMP_BYTESкак здоровый.Плюс к пункту про restore-тест:
ops/restore.shльёт в боевую базу (psql -d $DB_NAMEна проде, дамп с--clean --if-exists). Для учебного восстановления он не годится — нужен одноразовый контейнерpostgis/postgis, и сверять не «завелось», а количество строк ключевых таблиц против прода плюс наличие расширений PostGIS.Куда выгружать — цены проверены 2026-08-20
Требования: локация РФ (в дампах ПДн), провайдер отличный от того, где прод, Object Lock.
Ловушка: ледяные классы под 7-дневную ротацию не годятся. У Yandex минимальный тарифицируемый срок хранения в ледяном — 12 месяцев, удалили дамп через неделю и платите за оставшиеся 11,8. У Selectel штрафа за раннее удаление нет (подтверждено в анонсе) — это редкое исключение.
Про ключ
Ключ лежит на той самой машине, которую бэкапит, — скомпрометировали сервер, скомпрометировали и бэкапы. Правильно: на проде ключ только на запись (
Allow PutObject, явныйDenyнаDeleteObject,DeleteObjectVersion,PutLifecycleConfiguration), ключ на восстановление хранится отдельно, Object Lock в режиме COMPLIANCE страхует от подмены политики. Шифровать клиентски (age/gpg) до загрузки — SSE провайдера не спасает от сценария «скомпрометирован провайдер».Смежное: #2989 (пересборка базы при переезде) — там же оценка, что реальный логический payload базы всего 285 МБ в gzip.
Ре-верификация на живом проде 2026-08-21 — основное закрыто, issue оставляю открытым из-за трёх хвостов
Проверял не по коду в репозитории, а по факту на машине.
Работает
Конфиг существует и с правильными правами:
/etc/default/gendesign-backup,root:gendesign 640. Именно640с группой, а не600 root:rootкак было написано в шапке скрипта — cron запускает бэкапы отgendesign, и «правильная» по документации раскладка давалаPermission denied.Обе базы уезжают за пределы машины, ежедневно. Лог прогона за сегодня:
Оба новых дефекта из ре-верификации 2026-08-20 закрыты:
pg_dumpall --globals-only— есть, файлы*_globals_*.sql.gzлежат и в бакете, и локально;ops/restore.shбольше не заряженное ружьё: требуетRESTORE_CONFIRM=yes, иначе отказ с явным предупреждением проDROP. Плюс появился отдельныйops/restore-drill.sh, который поднимает одноразовый контейнер на unnamed-volume и никогда не касается боевой БД — с явным предупреждением в шапке, что для репетиции нужен именно он.Хардening на месте:
MIN_DUMP_BYTES(пол 50 KiB),gzip -t, sentinel по трейлеру-- PostgreSQL database dump completeчерезgrep -qF --(без--проверка целостности проваливалась всегда и скрипт удалял только что созданный дамп),AWS_CA_BUNDLEдля aws-cli.Что осталось — поэтому не закрываю
ops/restore-drill.shнаписан, но запуска не было, и в cron его нет. Пункт acceptance «restore-тест в чистую БД» формально не выполнен. Перед окном миграции это надо прогнать хотя бы один раз на реальном свежем дампе — иначе бэкап остаётся непроверенным предположением.ops/backup.shнет sentinel-файла с меткой времени и нет проверки возраста. Если cron перестанет отрабатывать, никто не узнает — ровно тот класс тихого отказа, который уже дал четыре штуки на этом же пути.PutObjectтолько наarn:aws:s3:::gendsgn-backups/forgejo/*— иначе Beget нечем писать бэкап кода, а текущий writer-ключ выписан прод-хосту. Без этого весь код Forgejo остаётся в одном экземпляре на одной машине.Отдельно, к сведению
Отзыв ключа у Selectel не мгновенный — удалённый через панель ключ продолжал аутентифицироваться ещё 8 минут. Отличать живой от отозванного надо ответом на
GetBucketPolicy:InvalidAccessKeyId— мёртв,AccessDenied— жив, просто не пускает.Refs #2989
Прошёл по всем четырём пунктам приёмки. Три из них уже закрыты — hardening и off-box выгрузка сделаны и работают, что видно по логам прода, а не по коду. Открытым был только restore-тест; прогнал его, и он попутно ответил на чужой открытый вопрос.
Что уже работает (проверено на проде, не по диффу)
tradein-mvp/deploy/backup-tradein-db.shнаforgejo/mainи задеплоенный на VM — побайтово один и тот же файл (md575486a86…совпал). В нём уже есть:MIN_DUMP_BYTES=10240— floor вместо одной проверки на непустоту2>/dev/nullубран — прямо помечено «до #2203»)gzip -tплюс проверка трейлера дампа — то есть ловится и «gz валидный, но дамп обрезан»SENTINEL_FILE=.last_success+ ежечасныйops/check-backup-staleness.shв cron с порогом 26 ч — на все три бэкапа (main, tradein, forgejo)Off-box выгрузка тоже живая. Из лога прогона 23.08:
314 МБ уехали за 19 секунд. Плюс отдельно выгружаются
globals— то, чего в исходной постановке не было.Restore-тест — прогнал, результат ниже
Восстанавливал реальный последний бэкап (
tradein-20260823-013001.sql.gz, 314 МБ) в чистую БДtradein_backup_testна Poincare — потоком, без промежуточного файла, чтобы не занимать диск Beget:Poincare выбран намеренно: 798 ГБ свободно и нулевое влияние на прод (на Beget оставалось 45 ГБ и работали скрапперы).
Время: 59 секунд. Ошибок — 10, все одна и та же:
role "gendesign_reader" does not exist— этоGRANTна роль, которой нет в целевом кластере. На данные не влияет, но при восстановлении «в чистое» роль надо создавать заранее, иначе права не приедут. Стоит добавить в раннбук.Сверка row-counts
scrape_runs(≤ момента дампа)listing_source_snapshots(≤ даты дампа)listingslisting_sourceshousesoffer_price_historyДве таблицы, где есть колонка времени и можно отсечь прод ровно по моменту дампа, сошлись в точности. Остальные расходятся только на прирост за сутки с момента дампа — и расходятся пропорционально, без выбросов.
Схема
publicscrape_proxies— 4 строки, то есть таблицы с зашифрованными полями тоже приехали.Побочно: восстановление объяснило раздутие базы
Восстановленная БД занимает 2 272 МБ. Прод — 21 ГБ. Те же самые данные, тот же набор индексов.
Это ~9-кратное раздутие на проде, и оно же объясняет, почему restore занял 59 секунд, а не полчаса. Аудит скрапперов (24.08) отдельно отмечал «TOAST-раздутие
listings19 ГБ при ~3.3 ГБ heap+индексов, причина не установлена» — вот независимое подтверждение: причина не в объёме данных.Практический вывод для переезда: перенос через dump/restore сам по себе освободит ~19 ГБ и ускорит всё, что упирается в размер. Отдельный
VACUUM FULLдо окна не нужен — окно его и сделает.Статус приёмки
gendsgn-backups, 7 дампов + 4 globalsMIN_DUMP_BYTES, stderr не глотается, алерт на непрошедший cron — всё есть.env.runtime— остаётся за владельцем (работа с секретами)Тестовая база удалена сразу после сверки, в
pg-rehearsalостались только штатныеtradein_reh/gendesign_reh.Что стоит добавить в раннбук #3057
gendesign_reader(иначе 10GRANTмолча не применятся).Поправка к моему же предыдущему комментарию. Я записал пункт «алерт если cron не отработал» как закрытый — это неверно. Механизм есть, но доставки нет.
Всплыло случайно: после мержа #3070 я прогнал
notify()на проде, чтобы убедиться, что поведение не изменилось, и получилСначала решил, что это артефакт моего теста (запускал от
gendesign, а файл-rw-r----- root:gendesign). Проверил — файл читается, переменных в нём просто нет.Замер по всем трём env-файлам
TELEGRAM_BOT_TOKEN/CHAT_ID/etc/default/gendesign-backup/opt/gendesign/secrets/forgejo-backup.env/etc/default/gendesign-uptimeНи в одном. То есть
notify()во всех трёх бэкап-путях — no-op: он пишет строку в лог и возвращает 0.Подтверждение из логов: 5 строк
NOTIFY (telegram disabled ...)за месяц. Ни одной строки об успешной отправке или оtelegram sendMessage failed— то есть curl к Telegram не вызывался ни разу.Что это значит
Цепочка выглядела рабочей на каждом звене по отдельности:
check-backup-staleness.sh— работает, логи есть:Сейчас чекер печатает
OK, поэтому разницы не видно. Разница появится ровно в тот момент, когда бэкап не отработает: чекер честно определит проблему, напишет её в файл в/tmp— и на этом всё.Это тот же класс, что и остальное найденное за эту ночь: механизм есть, счётчик считает, вывода из счётчика никто не делает.
Отношение к #3070
PR #3070 (смержен, на проде проверен) эту дыру не закрывает, но делает громкой. Раньше при ненастроенном Telegram в лог шла нейтральная строка
NOTIFY (telegram disabled ...), которая читается как «уведомления выключены, так и задумано». Теперь следом идёт:Проверено на проде после деплоя — обе строки присутствуют,
rc=0, поведение остальных путей не изменилось.Что нужно сделать (владелец, работа с секретами)
Один из двух вариантов, любой закрывает пункт:
TELEGRAM_BOT_TOKEN/TELEGRAM_CHAT_IDв/etc/default/gendesign-backup— вернуть исходную задумку.ALERT_SMTP_*/ALERT_MAIL_*переменных туда же — включить запасной канал из #3070.Лучше оба, и вот почему это не перестраховка: после переезда Telegram с нового хоста висит на единственном живом адресе
149.154.167.220(#3059), а канал оповещения о его отказе шёл бы через него же.Проверить после настройки просто — принудительно состарить sentinel или временно опустить порог, и убедиться, что уведомление дошло.
Исправленный статус приёмки
MIN_DUMP_BYTES✅, stderr не глотается ✅, алерт если cron не отработал — механизм есть, доставки нет ❌.env.runtimeПункт «алерт, если cron не отработал» закрыт — доставка включена и проверена на обоих хостах
23.08 я записал этот пункт как закрытый, потом сам же поправился: механизм есть, доставки нет.
notify()во всех трёх путях был no-op — переменныеTELEGRAM_*не заданы ни в одном env-файле, за месяц ни одного вызоваcurlк Telegram.Сегодня владелец дал координаты канала, и разрыв закрыт.
Куда шлём
Бот
MERAsupport_bot— тот же, что уже пересылает сообщения, отдельный заводить не потребовалось. Форум «МЕРА»,chat_id = -1004443088679, тема «алерты» — 158.Что включено
gendesign, бэкапtradein, оба сторожа устареванияПроверено живым вызовом
notify(), а не чтением конфига — сообщения из обоих хостов доставлены.Показательная деталь
Отправка с Poincare прошла с третьей попытки:
Это ровно та флапающая маршрутизация до Telegram, которую замерили в #3059 (с нового хоста отвечает один ДЦ из четырёх). Одиночный
curl, какимnotify()был до #3095, этот алерт бы потерял — и потерял бы молча, потому что запасной канал (почта) сжигался бы на первом же неудавшемся SYN. Ретрай, который тогда выглядел перестраховкой, окупился на первом же боевом сообщении.Как устроено на Beget, чтобы потом не удивляться
/etc/default/gendesign-backupтам принадлежитroot:gendesign 640, а passwordless sudo на машине нет — дописать в него я не могу. Поэтому переменные лежат в/opt/gendesign/secrets/backup-notify.env(600, владелецgendesign), а cron-строки сторожей и бэкапа CouchDB указывают на него черезBACKUP_ENV_FILE=— механизм, которыйnotify()уже поддерживает (lib-backup.sh:35). Бэкап Forgejo получил те же переменные в свойforgejo-backup.env.Крон сохранён перед правкой:
/opt/gendesign/logs/crontab.bak-2026-08-27.Известное ограничение
notify()не умеетmessage_thread_id, поэтому сообщения бэкапов падают в общую тему форума, а не в «алерты». Функционально не мешает, но шумит не там. Поправлю отдельным PR — параметр опциональный, при незаданномTELEGRAM_TOPIC_IDповедение прежнее бит в бит.Состояние приёмки
MIN_DUMP_BYTES, stderr не глотается, целостность архива — и теперь алерт реально доходитops/backup-forgejo.sh:303он намеренно оставлен ручным действием владельца: файл с ключами шифрования не должен уезжать теми же автоматическими путями, что и дампы. Без него дампы восстановятся, ноpgp_sym_encrypt-поля (CIAN-cookie) расшифровать будет нечем.Issue оставляю открытым ровно из-за последнего пункта.
Пункт «реальный restore-тест» закрыт — теперь автоматически, а не разовым прогоном
Проверял заново, а не полагался на прогон 23.08: с тех пор сменился хост, был десятичасовой простой и падали выгрузки в S3. Дампы с тех пор снимались на другой машине, и «оно же работало» перестало быть аргументом.
Дыра, которой не видел ни один из прошлых заходов
Дрель стоит в cron с #3085, но её строка берёт только
gendesign_*. База tradein — клиентские оценки, листинги, дома, сделки — автоматически на восстановимость не проверялась ни разу. Дампы снимались, уезжали в S3, и никто не знал, разворачиваются ли они.Сам
ops/restore-drill.shправить не пришлось: он с самого начала умеет оба проекта (находитtradein-globals-<ts>.sql.gz, подставляет свой список таблиц). Не хватало вызова — PR #3141 добавляет одну строку вops/crontab-poincare.cron, еженедельно по понедельникам.Прогон на боевом дампе 27.08
Гонял ровно тот скрипт, что пойдёт по расписанию (оповещение заглушено через
BACKUP_ENV_FILE, чтобы не слать в канал ложную тревогу):Сверка восстановленной базы с боевой:
Расходятся ровно две таблицы, и ровно те, что пополняются в реальном времени — на строки, созданные после снятия дампа (11:11, сверка в 11:49). Это и есть признак верного дампа: совпадение «в ноль» по неподвижным таблицам и движение вперёд только у живых.
Зашифрованные поля на месте (2 колонки) — то есть содержимое дампа полное, а не усечённое.
Побочно: одна ошибка в первом заходе была моя, не бэкапа
Первый прогон дал 10 ошибок
role "gendesign_reader" does not exist. Проверил — роль в дампе ролей есть (2CREATE ROLE, 4 упоминания), а ошибки возникли потому, что я в своём черновом скрипте пропустил накат globals. Отмечаю, чтобы это не осело в issue как дефект бэкапа: дамп ролей полон.Остаётся открытым только четвёртый пункт
MIN_DUMP_BYTES, stderr не глотается, алерт о непрошедшем cron — доставка включена 27.08).env.runtimeПоследний пункт — за владельцем: нужно решить, куда её класть. Сам файл я трогать не буду, а без него
pgp_sym_encrypt-поля в дампах не расшифровать, то есть восстановление будет неполным именно в той части, ради которой сложность и заводилась.Четвёртый пункт закрыт на живом хосте — и по дороге нашлось, что два cron-задания из main вообще не запускались
PR #3146 смержен в 14:00, скрипт доехал на Poincare (md5 совпал с main). Но «лежит в репозитории» и «работает на машине» — разные вещи, и здесь они разошлись.
Расхождение живого crontab с эталоном
Активный
crontab -u gendesignбыл от 25.08 и отставал отops/crontab-poincare.cronровно на две строки:Первая — та самая еженедельная дрель tradein, которую я в комментарии от 12:01 записал как «теперь еженедельная, с оповещением при провале». Она не запускалась ни разу: строка была в эталонном файле в репозитории, в живой crontab её никто не устанавливал. Деплой
ops/*.cronнамеренно не исполняет (это эталоны, ставятся вручную), а я тогда проверил файл, а неcrontab -l.Это ровно тот же класс, что и «
notify()— механизм есть, доставки нет» тремя комментариями выше. Проверять надо конечное звено, а не то, что перед ним.Установлено из эталона, расхождений больше нет: 11 активных строк, diff с
ops/crontab-poincare.cronпуст. Прежний crontab сохранён в/opt/gendesign/logs/crontab.bak-20260827-142001.Парольная фраза заведена
ENV_OFFBOX_PASSPHRASEдописан в/etc/default/gendesign-backup, права файла не изменились (root:gendesign 640), пользовательgendesignфразу читает — проверено запуском от него, а не чтением конфига. Сама фраза лежит в волте (meta/00_credentials.md), то есть на другой машине — иначе она погибла бы вместе с той, ради спасения от чего копия и делается.Боевой прогон
В бакете:
env/env-runtime-Poincare-20260827_142054.gpg, 901 байт,2026-08-27 14:21:09.Чего проверить с прода нельзя — и это правильно
Сверить выгруженный экземпляр обратной расшифровкой с самого прода невозможно: тамошний ключ write-only,
ListObjectsV2иGetObjectотвечаютAccessDenied. Так и задумано (#2203, разделение writer/reader), и это подтвердилось на практике впервые. Проверка целостности при этом не теряется: скрипт расшифровывает ровно те байты, что уходят в S3, ещё до выгрузки, и при провале ничего не выгружает.В раннбук #3057, к прошлым двум пунктам
При восстановлении с машины с графическим окружением
gpg --passphraseбез--pinentry-mode loopbackмолча игнорируется: gpg 2.x лезет за фразой в GUI-пинентри, а в headless-скрипте просто отказывает. В самомbackup-env-offbox.shэтого класса нет — фраза уходит дескриптором.Известное ограничение, не дефект
Ретеншена на префиксе
env/в S3 нет — локальноKEEP=14, в бакете копии накапливаются (≈900 байт/сутки, ~330 КБ в год). Удалять их автоматически и не хотелось бы: копия, снятая до правки конфига, — единственный способ прочитать дамп того же периода.Состояние приёмки — все четыре
MIN_DUMP_BYTES, stderr не глотается, алерт о непрошедшем cron доставляетсяЗакрываю.