From dfc72b1d694d4b69a6a50cd374f1e65409844a69 Mon Sep 17 00:00:00 2001 From: mrleo1nid <43583385+mrleo1nid@users.noreply.github.com> Date: Wed, 21 Oct 2026 09:03:06 +0300 Subject: [PATCH] chore(deploy): leave database backups to external tools The app no longer dumps Postgres, restores it, or checks copies in CI. Co-authored-by: Cursor --- .gitea/workflows/ci-db.yml | 25 ------- deploy/backup.sh | 139 ------------------------------------- deploy/compose.yaml | 20 ------ deploy/install.sh | 2 +- deploy/restore.sh | 34 --------- deploy/update.sh | 8 +-- docs/README.md | 4 +- docs/admin-guide.md | 27 ++----- docs/ci-cd.md | 2 +- docs/deployment.md | 22 ------ docs/install-guide.md | 19 +---- docs/roadmap.md | 8 +-- scripts/release.mjs | 6 -- 13 files changed, 16 insertions(+), 300 deletions(-) delete mode 100755 deploy/backup.sh delete mode 100755 deploy/restore.sh diff --git a/.gitea/workflows/ci-db.yml b/.gitea/workflows/ci-db.yml index ba78f04..ba698f2 100644 --- a/.gitea/workflows/ci-db.yml +++ b/.gitea/workflows/ci-db.yml @@ -10,13 +10,11 @@ on: paths: - 'services/api/**' - 'services/recommender/**' - - 'deploy/backup.sh' - '.gitea/workflows/ci-db.yml' pull_request: paths: - 'services/api/**' - 'services/recommender/**' - - 'deploy/backup.sh' - '.gitea/workflows/ci-db.yml' concurrency: @@ -84,26 +82,3 @@ jobs: run: | uv sync --frozen uv run pytest -q tests/test_db_integration.py - # База уже наполнена сценариями выше — проверяем настоящий цикл копия → проверка → восстановление. - - name: Бэкап, проверка и восстановление (deploy/backup.sh) - env: - PGHOST: postgres - PGUSER: pipu - PGPASSWORD: pipu - PGDATABASE: pipu - BACKUP_DIR: /tmp/backups - VERIFY_EXACT: "1" - run: | - SUDO=$(command -v sudo || true) - $SUDO install -d /usr/share/postgresql-common/pgdg - $SUDO curl -fsSLo /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc https://www.postgresql.org/media/keys/ACCC4CF8.asc - echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt $(. /etc/os-release && echo "$VERSION_CODENAME")-pgdg main" | $SUDO tee /etc/apt/sources.list.d/pgdg.list >/dev/null - $SUDO apt-get update -qq && $SUDO apt-get install -y -qq postgresql-client-17 >/dev/null - export PATH=/usr/lib/postgresql/17/bin:$PATH - before=$(psql -Atc "SELECT count(*) FROM tracks") - file=$(bash deploy/backup.sh once) - bash deploy/backup.sh verify "$file" - bash deploy/backup.sh restore "$file" - after=$(psql -Atc "SELECT count(*) FROM tracks") - echo "tracks: $before → $after" - test "$before" = "$after" diff --git a/deploy/backup.sh b/deploy/backup.sh deleted file mode 100755 index fc75c24..0000000 --- a/deploy/backup.sh +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env bash -# Резервные копии PostgreSQL (docs/deployment.md#бэкапы). Работает в контейнере backup (compose.yaml) и в CI; -# подключение — стандартные PGHOST, PGUSER, PGPASSWORD, PGDATABASE. -# backup.sh loop — каждый день в BACKUP_HOUR (UTC): копия и ротация; раз в неделю — проверка восстановления -# backup.sh once — копия сейчас; печатает путь к файлу -# backup.sh verify FILE — восстановить FILE во временную базу и сверить таблицы и число строк -# backup.sh restore FILE — заменить рабочую базу копией (сервисы, пишущие в базу, должны быть остановлены); -# прежняя база остаётся рядом как _before_restore_<время> -set -euo pipefail - -DIR="${BACKUP_DIR:-/backups}" -DB="${PGDATABASE:-pipu}" -KEEP_DAILY="${BACKUP_KEEP_DAILY:-14}" -KEEP_WEEKLY="${BACKUP_KEEP_WEEKLY:-8}" - -log() { echo "$(date -u +%FT%TZ) backup: $*" >&2; } - -# Число строк в каждой таблице базы $1: «таблицастрок», по алфавиту. -counts() { - psql -X -d "$1" -Atq -F $'\t' -c " - SELECT table_name, - (xpath('/row/c/text()', query_to_xml(format('SELECT count(*) AS c FROM %I.%I', table_schema, table_name), - false, true, '')))[1]::text - FROM information_schema.tables - WHERE table_schema = 'public' AND table_type = 'BASE TABLE' - ORDER BY 1" -} - -rotate() { - # shellcheck disable=SC2012 # имена файлов наши, без пробелов - ls -1t "$DIR"/daily/pipu-*.dump 2>/dev/null | tail -n +$((KEEP_DAILY + 1)) | xargs -r rm -f -- - # shellcheck disable=SC2012 - ls -1t "$DIR"/weekly/pipu-*.dump 2>/dev/null | tail -n +$((KEEP_WEEKLY + 1)) | xargs -r rm -f -- - find "$DIR/daily" "$DIR/weekly" -name '*.counts' | while read -r c; do - [ -f "${c%.counts}.dump" ] || rm -f -- "$c" - done -} - -once() { - mkdir -p "$DIR/daily" "$DIR/weekly" - local name file - name="pipu-$(date -u +%Y%m%d-%H%M%S)" - file="$DIR/daily/$name.dump" - pg_dump -Fc -d "$DB" -f "$file.part" - pg_restore -l "$file.part" >/dev/null # оглавление читается — архив не обрезан - counts "$DB" >"$file.counts" # для verify: что было в базе в момент копии - mv "$file.part" "$file" - # Еженедельная копия — первая за 7 дней (не зависит от того, в какой день сервер был выключен). - if ! find "$DIR/weekly" -name 'pipu-*.dump' -mtime -7 | grep -q .; then - cp "$file" "$DIR/weekly/$name.dump" - cp "$file.counts" "$DIR/weekly/$name.dump.counts" - fi - rotate - log "$file ($(du -h "$file" | cut -f1))" - echo "$file" -} - -verify() { - local file="$1" tmpdb="${DB}_verify" got want - [ -f "$file" ] || { log "нет файла $file"; return 1; } - dropdb --if-exists "$tmpdb" - createdb "$tmpdb" - if ! pg_restore --no-owner --exit-on-error -d "$tmpdb" "$file"; then - dropdb --if-exists "$tmpdb" - log "ПРОВЕРКА НЕ ПРОЙДЕНА: $file не восстанавливается" - return 1 - fi - got="$(counts "$tmpdb")" - dropdb "$tmpdb" - want="$(cat "$file.counts" 2>/dev/null || counts "$DB")" - # Таблица пропала или опустела — копия негодна. Расхождение в числе строк — рабочая база менялась во время - # копии (предупреждение); VERIFY_EXACT=1 (CI, база в покое) — тоже ошибка. - local bad=0 table n m - while IFS=$'\t' read -r table n; do - m="$(printf '%s\n' "$got" | awk -F'\t' -v t="$table" '$1 == t { print $2 }')" - if [ -z "$m" ]; then - log "в копии нет таблицы $table" - bad=1 - elif [ "$m" = 0 ] && [ "$n" != 0 ]; then - log "в копии пуста таблица $table (было $n)" - bad=1 - elif [ "$m" != "$n" ]; then - log "$table: $m строк в копии, $n при копировании" - [ "${VERIFY_EXACT:-}" = 1 ] && bad=1 - fi - done <<<"$want" - if [ "$bad" = 1 ]; then - log "ПРОВЕРКА НЕ ПРОЙДЕНА: $file" - return 1 - fi - log "проверено: $file восстанавливается ($(printf '%s\n' "$got" | wc -l) таблиц)" - date -u +%FT%TZ >"$DIR/.last-verify" -} - -restore() { - local file="$1" old - verify "$file" - old="${DB}_before_restore_$(date -u +%Y%m%d%H%M%S)" - psql -X -d postgres -Atqc "SELECT pg_terminate_backend(pid) FROM pg_stat_activity - WHERE datname = '$DB' AND pid <> pg_backend_pid()" >/dev/null - psql -X -d postgres -qc "ALTER DATABASE \"$DB\" RENAME TO \"$old\"" - createdb "$DB" - if ! pg_restore --no-owner --exit-on-error -d "$DB" "$file"; then - dropdb "$DB" - psql -X -d postgres -qc "ALTER DATABASE \"$old\" RENAME TO \"$DB\"" - log "восстановление не удалось — рабочая база не тронута" - return 1 - fi - log "база $DB восстановлена из $file; прежняя сохранена как $old (удалить: dropdb $old)" -} - -loop() { - local hour="${BACKUP_HOUR:-3}" now next file - log "ежедневная копия в $hour:30 UTC, хранится $KEEP_DAILY ежедневных и $KEEP_WEEKLY еженедельных" - while true; do - now="$(date -u +%s)" - next="$(date -u -d "today $hour:30" +%s)" - [ "$next" -gt "$now" ] || next="$(date -u -d "tomorrow $hour:30" +%s)" - sleep $((next - now)) - if ! file="$(once)"; then - log "КОПИЯ НЕ СДЕЛАНА" - continue - fi - if [ -z "$(find "$DIR" -maxdepth 1 -name .last-verify -mtime -7)" ]; then - verify "$file" || true - fi - done -} - -case "${1:-}" in - loop) loop ;; - once) once ;; - verify) verify "${2:?укажите файл копии}" ;; - restore) restore "${2:?укажите файл копии}" ;; - *) - sed -n '2,9p' "$0" >&2 - exit 2 - ;; -esac diff --git a/deploy/compose.yaml b/deploy/compose.yaml index 5bc2f2c..41dfe6e 100644 --- a/deploy/compose.yaml +++ b/deploy/compose.yaml @@ -145,26 +145,6 @@ services: interval: 5s retries: 20 - # Ежедневная копия базы и еженедельная проверка восстановления (deploy/backup.sh, docs/deployment.md#бэкапы). - backup: - <<: *restart - image: pgvector/pgvector:0.8.7-pg17 - entrypoint: ["bash", "/backup.sh"] - command: ["loop"] - environment: - PGHOST: postgres - PGUSER: pipu - PGPASSWORD: ${POSTGRES_PASSWORD} - PGDATABASE: pipu - BACKUP_HOUR: ${BACKUP_HOUR:-3} - BACKUP_KEEP_DAILY: ${BACKUP_KEEP_DAILY:-14} - BACKUP_KEEP_WEEKLY: ${BACKUP_KEEP_WEEKLY:-8} - volumes: - - ./backup.sh:/backup.sh:ro - - ${PIPU_DATA:-/srv/pipu}/backups:/backups - depends_on: - postgres: { condition: service_healthy } - redis: <<: *restart image: redis:7.4-alpine diff --git a/deploy/install.sh b/deploy/install.sh index 8a7f4de..23ec914 100755 --- a/deploy/install.sh +++ b/deploy/install.sh @@ -10,7 +10,7 @@ OWNER="${SUDO_USER:-root}" DATA="${PIPU_DATA:-/srv/pipu}" echo "→ каталоги в $DATA" -mkdir -p "$DATA"/{library,library-host,cache/transcode,cache/covers,postgres,meili,redis,models,updates,uploads,backups,caddy/data,caddy/config} +mkdir -p "$DATA"/{library,library-host,cache/transcode,cache/covers,postgres,meili,redis,models,updates,uploads,caddy/data,caddy/config} # Каталоги, куда пишут сервисы без root: api (distroless nonroot, uid 65532) и analyzer (uid 10001). # Без рекурсии: файлы внутри создают сами сервисы, а повторный запуск не обходит весь кэш. diff --git a/deploy/restore.sh b/deploy/restore.sh deleted file mode 100755 index 6a13220..0000000 --- a/deploy/restore.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash -# Восстановление базы из резервной копии (docs/deployment.md#бэкапы). -# ./restore.sh — список копий -# ./restore.sh daily/pipu-20261020-033000.dump -# Сервисы, пишущие в базу, останавливаются на время восстановления; прежняя база сохраняется рядом. -set -euo pipefail -cd "$(dirname "$0")" - -[ -f .env ] || { echo "нет .env — сначала sudo ./install.sh" >&2; exit 1; } -DATA="$(sed -n 's/^PIPU_DATA=//p' .env)" -DATA="${DATA:-/srv/pipu}" - -if [ -z "${1:-}" ]; then - echo "Копии в $DATA/backups (новые сверху):" - (cd "$DATA/backups" && ls -1t daily/*.dump weekly/*.dump 2>/dev/null) || echo " копий нет" - exit 0 -fi - -rel="${1#"$DATA/backups/"}" -[ -f "$DATA/backups/$rel" ] || { echo "нет файла $DATA/backups/$rel" >&2; exit 1; } - -echo "→ восстановление из $rel: api, рекомендации и анализ будут остановлены на время восстановления" -read -r -p "Продолжить? [y/N] " yes -[ "$yes" = y ] || [ "$yes" = Y ] || exit 1 - -docker compose stop api recommender analyzer storage-agent -if docker compose run --rm backup restore "/backups/$rel"; then - status=0 -else - status=1 -fi -docker compose up -d -[ "$status" = 0 ] || { echo "восстановление не удалось — база не изменена" >&2; exit 1; } -echo "готово. Поиск переиндексируется при старте api (или вручную: «Администрирование → Библиотека»)." diff --git a/deploy/update.sh b/deploy/update.sh index b6319d2..0022d64 100755 --- a/deploy/update.sh +++ b/deploy/update.sh @@ -88,19 +88,13 @@ tgt_core="$(core "$TARGET" || true)" if [ -n "$cur_core" ] && [ -n "$tgt_core" ] && [ "$cur_core" != "$tgt_core" ] && [ "$(printf '%s\n%s\n' "$cur_core" "$tgt_core" | sort -V | head -1)" = "$tgt_core" ]; then echo "внимание: $CURRENT → $TARGET — это откат. Миграции БД не откатываются;" >&2 - echo " сделайте резервную копию (docs/deployment.md) и проверьте, что старая версия совместима со схемой." >&2 + echo " копию базы сделайте внешними средствами и проверьте, что старая версия совместима со схемой." >&2 if [ "${PIPU_ALLOW_DOWNGRADE:-}" != 1 ]; then echo " Чтобы продолжить: PIPU_ALLOW_DOWNGRADE=1 ./update.sh $REF" >&2 exit 1 fi fi -# Копия базы перед обновлением: миграции назад не откатываются (deploy/restore.sh — вернуть). -if [ -n "$(docker compose ps -q --status running postgres 2>/dev/null)" ]; then - echo "→ резервная копия базы" - docker compose run --rm --no-deps backup once >/dev/null -fi - echo "→ переключаемся на $REF" if git show-ref --verify --quiet "refs/remotes/origin/$REF"; then git checkout --quiet "$REF" diff --git a/docs/README.md b/docs/README.md index 08e96eb..68d61bb 100644 --- a/docs/README.md +++ b/docs/README.md @@ -23,8 +23,8 @@ Pipu Music — self-hosted музыкальный сервис (веб + Android | [testing.md](testing.md) | Стратегия тестирования | | [ci-cd.md](ci-cd.md) | Gitea Actions: проверки и релиз по тегу | | [install-guide.md](install-guide.md) | **Пошагово:** установка сервера на домен с HTTPS, подключение веба и Android | -| [admin-guide.md](admin-guide.md) | **Администратору:** пользователи, хранилища, очередь, волна, обновления, бэкапы, диагностика | -| [deployment.md](deployment.md) | Справочник по развёртыванию: сервисы, каталоги, переменные, бэкапы | +| [admin-guide.md](admin-guide.md) | **Администратору:** пользователи, хранилища, очередь, волна, обновления, диагностика | +| [deployment.md](deployment.md) | Справочник по развёртыванию: сервисы, каталоги, переменные | | [conventions.md](conventions.md) | Соглашения по коду, git, версиям | | [roadmap.md](roadmap.md) | Этапы разработки и критерии готовности | diff --git a/docs/admin-guide.md b/docs/admin-guide.md index fc91a5b..d8298f3 100644 --- a/docs/admin-guide.md +++ b/docs/admin-guide.md @@ -1,7 +1,7 @@ # Руководство администратора Повседневная работа с сервером после установки ([install-guide.md](install-guide.md)): пользователи, музыка, -очередь на добавление, «Моя волна», обновления, бэкапы и диагностика. Все команды — из каталога +очередь на добавление, «Моя волна», обновления и диагностика. Все команды — из каталога `/opt/pipu-music/deploy`. Справочник по сервисам и переменным — [deployment.md](deployment.md). ## 1. Первый вход @@ -90,7 +90,7 @@ ./update.sh ``` -Скрипт делает копию базы, переключается на последний релиз, собирает образы, перезапускает сервисы и ждёт +Скрипт переключается на последний релиз, собирает образы, перезапускает сервисы и ждёт готовности; миграции применяются при старте api. Конкретная версия — `./update.sh v1.0.0`; откат на старую версию требует `PIPU_ALLOW_DOWNGRADE=1` (миграции не откатываются — сначала проверьте совместимость). Перед обновлением прочитайте заметки к релизу на странице релизов Gitea. @@ -99,33 +99,18 @@ Android-приложение обновляется само: при запус Раздать приложение — ссылка `https://<ваш-домен>/android` (без входа): кнопка «Скачать APK» последнего релиза, адрес сервера для копирования и короткая инструкция; та же страница — внизу экрана входа и в меню профиля. -## 7. Бэкапы и восстановление - -- Каждую ночь (`BACKUP_HOUR`, по умолчанию 3:30 UTC) контейнер `backup` делает копию базы в - `/srv/pipu/backups/daily` (14 последних) и раз в неделю — в `weekly` (8 последних). -- Раз в неделю копия **проверяется восстановлением** во временную базу. Результат: - `docker compose logs backup | tail`; при ошибке в логе — «ПРОВЕРКА НЕ ПРОЙДЕНА». -- Копия сейчас: `docker compose run --rm backup once`. -- Восстановление: `./restore.sh` — список копий, `./restore.sh daily/<файл>` — восстановить. Прежняя база - остаётся рядом как `pipu_before_restore_<время>`; убедившись, что всё в порядке, удалите её: - `docker compose exec postgres dropdb -U pipu pipu_before_restore_<время>`. -- В копию входит всё, что нельзя пересоздать: пользователи, история, лайки, состояние плеера, очередь на добавление, - результаты аудиоанализа и модели волны. Поиск, обложки и транскоды восстанавливаются сами. -- **Сама музыка не бэкапится** приложением — это ваш диск или NFS. Каталог бэкапов тоже лежит на сервере: - копируйте `/srv/pipu/backups` на другую машину, например `rsync` по cron. - -## 8. Наблюдение +## 7. Наблюдение | Что | Как | |---|---| | Сервер жив и готов | `curl -s https://music.example.com/readyz` → все зависимости `ok` | | Состояние сервисов | `docker compose ps` | -| Логи | `docker compose logs -f --tail=100 api` (или `recommender`, `analyzer`, `storage-agent`, `backup`) | -| Место на диске | `df -h /srv/pipu`; больше всего занимают `cache/transcode` (чистится сам) и `backups` | +| Логи | `docker compose logs -f --tail=100 api` (или `recommender`, `analyzer`, `storage-agent`) | +| Место на диске | `df -h /srv/pipu`; больше всего занимает `cache/transcode` (чистится сам) | | Версия | `grep PIPU_VERSION .env`, `GET /api/v1/server-info`; Android — внизу вкладки «Профиль» | | Нагрузка | `tests/load/smoke.js` — см. [testing.md](testing.md#нагрузочный-smoke) | -## 9. Частые ситуации +## 8. Частые ситуации | Ситуация | Что делать | |---|---| diff --git a/docs/ci-cd.md b/docs/ci-cd.md index 2adf49b..b96c6ae 100644 --- a/docs/ci-cd.md +++ b/docs/ci-cd.md @@ -77,7 +77,7 @@ jobs: - **изменения** — коммиты (Conventional Commits) с прошлого тега по разделам «Новое», «Исправления», «Сборка и CI» и т. д., отдельно — несовместимые (`feat!:`); для финального релиза отсчёт от прошлого финального, а не от последнего `-rc`; ссылка на полный diff; -- **обновление сервера** — бэкап, `./update.sh vX.Y.Z`, проверка версии; **установка APK** и проверка SHA-256. +- **обновление сервера** — `./update.sh vX.Y.Z`, проверка версии; **установка APK** и проверка SHA-256. Job `android`: Android SDK, `expo prebuild`, `./gradlew assembleRelease --build-cache` (только arm64-v8a), подпись `apksigner`, затем `release.mjs android success ` прикладывает APK и `.sha256` и меняет статус. При любом сбое — diff --git a/docs/deployment.md b/docs/deployment.md index fcad397..a8eed59 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -25,7 +25,6 @@ ├── models/ # модели Essentia (скачиваются при первом старте analyzer) ├── updates/ # кэш APK релизов ├── uploads/ # staging очереди на добавление (размер ≈ лимит очереди, по умолчанию 10 ГБ) -├── backups/ └── caddy/ # сертификаты Let's Encrypt (если используется compose.tls.yaml) ``` @@ -95,27 +94,6 @@ Пошаговая установка на домен — [install-guide.md](install-guide.md). -## Бэкапы - -- Контейнер `backup` (`deploy/backup.sh loop`): каждый день в `BACKUP_HOUR`:30 UTC (по умолчанию 3:30) — - `pg_dump -Fc` → `/srv/pipu/backups/daily/`, хранится `BACKUP_KEEP_DAILY` = 14 последних; первая копия за неделю - копируется в `weekly/` (`BACKUP_KEEP_WEEKLY` = 8). Рядом с копией — `*.counts`: число строк в каждой таблице. -- Раз в неделю копия **проверяется восстановлением**: разворачивается во временную базу `pipu_verify`, сверяются - таблицы и число строк, база удаляется; время последней успешной проверки — `backups/.last-verify`, ошибки — - в `docker compose logs backup` («ПРОВЕРКА НЕ ПРОЙДЕНА»). Тот же цикл копия → проверка → восстановление - выполняется в CI (`ci / db`) на базе после сквозного сценария. -- `update.sh` перед обновлением делает внеочередную копию. -- Вручную: `docker compose run --rm backup once` — копия сейчас; `docker compose run --rm backup verify /backups/daily/<файл>`. -- Восстановление: `./restore.sh` — список копий, `./restore.sh daily/pipu-….dump` — останавливает api, рекомендации и - анализ, проверяет копию, переименовывает текущую базу в `pipu_before_restore_<время>` (страховка; удалить — - `docker compose exec postgres dropdb -U pipu <имя>`), восстанавливает и запускает сервисы; поиск переиндексируется - при старте api. Redis (сессии волны, очереди) не восстанавливается — пользователи просто начнут новую волну. -- Копии лежат на том же сервере: для защиты от потери диска синхронизируйте `/srv/pipu/backups` на другую машину - (например, `rclone sync` или `rsync` по cron). -- Meilisearch, кэши и модели **не бэкапятся** — восстанавливаются (`reindex`, повторный транскод / анализ). -- Признаки анализа хранятся в Postgres — после восстановления из бэкапа повторный многочасовой анализ не нужен. -- Сама музыка — на NFS, вне зоны ответственности приложения. - ## Обновление ```bash diff --git a/docs/install-guide.md b/docs/install-guide.md index 5e39e2c..23a90f5 100644 --- a/docs/install-guide.md +++ b/docs/install-guide.md @@ -304,7 +304,7 @@ curl -s https://music.example.com/readyz --- -## 11. Обновление, бэкапы, удаление +## 11. Обновление и удаление Обновление до последнего релиза: @@ -314,22 +314,7 @@ cd /opt/pipu-music/deploy && ./update.sh Конкретная версия или откат: `./update.sh v0.2.0`. Скрипт делает `git fetch`, переключается на тег, пересобирает образы и перезапускает сервисы; старые образы удаляются. Миграции БД применяются -автоматически при старте API. - -Бэкапы базы делаются сами: каждую ночь в `/srv/pipu/backups`, раз в неделю копия проверяется восстановлением, -перед каждым `update.sh` — внеочередная копия. Всё остальное восстанавливается само — см. -[deployment.md](deployment.md#бэкапы). Копия сейчас и восстановление: - -```bash -cd /opt/pipu-music/deploy && docker compose run --rm backup once -``` - -```bash -cd /opt/pipu-music/deploy && ./restore.sh -``` - -Без аргумента `restore.sh` показывает список копий; с именем файла (`./restore.sh daily/pipu-20261020-033000.dump`) -восстанавливает базу, сохранив прежнюю рядом. +автоматически при старте API. Копии базы и музыки приложение не делает. Остановить сервис, сохранив данные: diff --git a/docs/roadmap.md b/docs/roadmap.md index 1cde8b1..d63a09a 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -53,11 +53,9 @@ критерий проверяется по метрикам версий в админке («Библиотека → Моя волна») и NDCG в `model_versions`. ## M7 — Стабилизация (v1.0) -- Нагрузочный smoke, бэкапы и восстановление (проверено), документация администратора, - доступность, полировка анимаций, багфиксы. -- **Состояние:** v1.0 — бэкапы с еженедельной проверкой восстановления (и цикл копия → проверка → восстановление - в CI), [руководство администратора](admin-guide.md), аудит доступности WCAG 2.1 AA, k6-smoke - (`tests/load/smoke.js`, запускается вручную на сервере перед релизом). +- Нагрузочный smoke, документация администратора, доступность, полировка анимаций, багфиксы. +- **Состояние:** v1.0 — [руководство администратора](admin-guide.md), аудит доступности WCAG 2.1 AA, k6-smoke + (`tests/load/smoke.js`, запускается вручную на сервере перед релизом). Копии базы и музыки — внешними средствами. ## Дальше (идеи) - Плейлисты, волна по исполнителю / треку, ежедневные подборки, тексты песен, Chromecast / DLNA, diff --git a/scripts/release.mjs b/scripts/release.mjs index 5fa4523..def3c11 100644 --- a/scripts/release.mjs +++ b/scripts/release.mjs @@ -109,12 +109,6 @@ export function renderNotes({ version, tag, prevTag, prerelease, repoUrl, groups '', '## Обновление сервера', '', - 'Перед обновлением сделайте бэкап базы:', - '', - '```bash', - 'cd /opt/pipu-music/deploy && docker compose exec -T postgres pg_dump -U pipu -Fc pipu > /srv/pipu/backups/pipu-$(date +%F).dump', - '```', - '', 'Обновление:', '', '```bash',