## Context Согласован отдельный репозиторий `deploy` и команда `./deploy.sh ` по SSH. Тег принадлежит комплекту, а не компоненту; соответствие пары хранится в `release.env`. Решения приняты в обсуждении с владельцем и записаны в ADR 016 репозитория docs; эти артефакты готовят реализацию, не подтверждают её выполнение. На сервере уже есть Compose project `wealthledger`, SQLite, постоянные ключи и read-only mount `certs/tbank-ca.pem` через `TBANK_CA_CERT_PATH`. Внешний HTTPS и Docker подготовлены. Образы публикуются в Nexus независимыми релизами. `containerized-application-delivery` остаётся отдельным active change; его runtime-контракт используется без редактирования или преждевременного archive. ## Goals / Non-Goals **Goals:** небольшой комплект с воспроизводимой парой образов, одним entrypoint, безопасным обновлением SQLite и понятным восстановлением существующего сервера. **Non-Goals:** provisioning, CI/CD автодеплой, новый registry, Kubernetes, Ansible-инфраструктура, blue-green, замена БД, backup daemon, автоматическая ротация копий, собственная система миграций или управление HTTPS. ## Decisions ### Комплект и постоянные ресурсы Минимальное содержимое `deploy`: `compose.yaml`, `release.env`, `.env.example`, `deploy.sh`, README и одна исполняемая проверка сценариев. Compose использует готовые frontend/backend images, migration запускается из backend image. Production-комплект самодостаточен и не требует соседних checkout. Существующие root Compose-файлы для development не удаляются этим change. На сервере checkout располагается отдельно от `data/`, `certs/`, `backups/` и защищённого server env. Например, checkout — `/opt/wealthledger/deploy`, остальное — соседние пути в `/opt/wealthledger`. Существующий data path не переименовывается; пути bind mounts абсолютные. Ключи не генерируются повторно. Root filesystem остаётся read-only, процесс non-root, backend не получает host port; сертификат доверия монтируется read-only без отключения TLS. `release.env` содержит только полные versioned image references из Nexus; `latest` исключён. Server env хранит настройки и секреты, но не выбирает пару. Переменные окружения вызывающего shell не должны переопределять выбранные images или Compose project. Env-файлы обрабатываются Compose как данные, не выполняются shell через `source`. Полный config с секретами не печатается. ### Исполнение выбранной версии Entrypoint получает тег только из настроенного доверенного `origin`, разрешает его в commit и использует содержимое этого commit для всей операции, включая версию deploy-логики. Полученный ранее тег не перезаписывается при расхождении. Работа идёт из временного snapshot выбранного commit; запущенный скрипт и операторские изменения checkout не перезаписываются переключением ветки. Compose file, env files и project `wealthledger` задаются явно: временная директория не должна создать второй project или изменить пути данных. До остановки выполняются проверки входов, ресурсов, конфигурации и загрузка образов. Поддерживаемый target — один Linux Docker host; Git, Bash и `flock` входят в перечисленные README предпосылки. Архитектура опубликованных образов должна соответствовать серверу; multi-platform поддержку этот change не добавляет. ### Обновление, повтор и состояние Один `flock` на установку исключает конкурирующие запуски. Не добавляется сервис блокировок. Файл блокировки и минимальные служебные записи находятся вне checkout, с ограниченными правами, без секретов. Нужны только запись последнего успешного релиза и маркер незавершённого обновления: выбранный commit, фактические images, этап и расположение backup. Маркер сохраняется до первого изменения runtime; успешная запись атомарно обновляется только после готовности затронутых сервисов. При прерывании маркер остаётся для диагностики; новый запуск требует ручного разбора по README. Это не журнал всех deployments и не отдельная база состояний. При первом переходе предыдущая версия описывается фактической парой images: несуществующий тег прежнего комплекта не придумывается. План изменений сверяет желаемые images и Compose service configuration с фактическими контейнерами. Для сравнения использовать native Compose service hash и Docker labels, если их соответствие подтверждено проверкой. Секреты не записываются в служебные файлы. Отсутствие достоверного baseline не разрешает frontend-only shortcut: первый переход с серверного Compose выполняется как полное обновление с backup. Успешная запись сама по себе не заменяет проверку фактически работающих контейнеров. При обновлении API: stop backend → проверка отсутствия migration writer → новый уникальный каталог backup → копия всего data directory, включая WAL/SHM → одноразовая migration → backend readiness. Для существующей установки отсутствие `wealthledger.db` — ошибка. Только явный первый запуск `--init` на пустом каталоге без прежнего runtime допускает создание новой базы без backup. Копия отмечается пригодной для восстановления только после успешного окончания копирования; незавершённый каталог не выдаётся за готовый backup. Неизменный frontend не пересоздаётся; обновление только frontend не запускает зависимости. При обновлении обоих компонентов новый frontend запускается после готовности backend. Healthchecks используются из готовых images через Compose; новый HTTP endpoint не нужен. Browser smoke через HTTPS остаётся отдельной проверкой выпуска: container health не доказывает login/refresh. Backup failure и migration failure прекращают последовательность. При провале readiness backend останавливается. Провал frontend не останавливает исправный backend. Любая ошибка оставляет релиз неподтверждённым, текущую БД и backup неизменёнными процедурой восстановления; диагностика не выводит secrets. ### Выпуск и инструкция После публикации компонентов оператор меняет пару в `release.env`, проверяет её на disposable установке и выпускает отдельный неизменяемый `vX.Y.Z` тег `deploy`. Компонентные pipeline не связываются автоматическим publisher. Первый комплект закрепляет реально доступные образы, не демонстрационные версии. README описывает подготовку Docker/Git/registry/HTTPS, разрешения каталогов, сохранение ключей, подключение действующего Compose project, install/update, диагностику незавершённой операции, ручную очистку backups и recovery. ## UI/UX Applicability and Package **Applicability and scope:** `N/A` — браузерный интерфейс и его состояния не меняются; оператор использует терминал и README. Макеты не нужны. ## Delivery Map | Area | Status | Architectural outcome or N/A reason | | --- | --- | --- | | frontend | `N/A` | Готовый image переиспользуется, UI и pipeline не меняются | | backend | `N/A` | Готовые runtime, healthcheck и migrations переиспользуются | | specs | `affected` | Контракт deployment-bundle и план его проверки | | docs | `affected` | ADR 016 и обновлённый эксплуатационный маршрут после реализации | | deploy | `affected` | Самодостаточный комплект, сценарии проверки и README | | root | `affected` | Только навигация README к production-комплекту; development Compose не меняется | Уточнение старого шаблона: обязательные четыре области сохранены; добавлен реальный repository owner `deploy`, явно выбранный пользователем, и `root` для необходимой поправки workspace-навигации. В Tasks используются `[deploy]` и `[root]`, а не фиктивный `[backend]` или `[workspace]`. Это локальное расширение перечня owners для данного change; глобальная переработка SDD schema и process specs в scope не входит. Native structural validation не доказывает соответствие этому уточнению или semantic approval. ## Solution Assessment | Вариант | Fit, зрелость и безопасность | Стоимость и ограничения | | --- | --- | --- | | Только Docker Compose | Зрелый runtime, зависимости, healthchecks и выбор images уже покрыты | Не выполняет stop/copy/migrate и не исключает две операторские операции | | Bash + Git + Compose + flock | Native инструменты владеют загрузкой, запуском и блокировкой; shell связывает существующий безопасный порядок | Небольшой branching требует проверок ошибок и прерываний; подходит одному Linux host | | Ansible | Зрелый механизм управления серверами, но backup/migration порядок всё равно надо определить | Добавляет control environment, inventory и роль при уже подготовленном одном сервере | Выбран второй вариант. Чистого Compose недостаточно для согласованной копии при остановленной записи; отдельный provisioning stack не соответствует согласованному отсутствию управления серверной инфраструктурой. Новый package manager, framework или сторонняя runtime-зависимость не вводятся. ## Risks / Trade-offs - Краткий простой и единственный writer сохраняются; внешние процессы записи должны быть исключены оператором при подключении существующей установки. - Локальный backup не спасает от потери диска; свободное место и ручная очистка остаются эксплуатационной обязанностью. Ошибка копирования блокирует миграции. - Native hash может измениться между версиями Compose: сомнение приводит к полному безопасному обновлению, а не к пропуску backup. - Прерванная migration требует разбора, а не слепого повторения команды. Ни служебный маркер, ни последний успешный тег не являются копией базы. - Доверие к Git origin и неизменяемым Nexus release tags остаётся существующей границей поставки; собственная система подписей здесь не добавляется. ## Migration Plan Подготовить самодостаточный комплект и проверить безопасный lifecycle на disposable данных. Затем обновить docs, сохранив development-инструкцию. Для действующего сервера сохранить старые настройки и соответствие images, подключить существующие абсолютные пути и project, выполнить первый полный переход с backup. Старый способ запуска не выполнять параллельно. ### Rollback Contract | Field | Decision | | --- | --- | | Status | `required` | | Trigger | Ошибка migration/readiness, прерывание либо выявленная регрессия | | Actions | Остановить API при риске для данных; отдельно выбрать совместимый image либо explicit restore; незавершённый маркер снять только после проверки состояния | | Data safety | Не восстанавливать БД автоматически; перед explicit restore сохранить текущий каталог, выбрать копию, подтвердить потерю новых записей и наличие прежнего ключа | | Verification | На отдельной копии проверить целостность БД, совместимость схемы, auth/cards и расшифровку подключения; после восстановления повторить smoke через HTTPS |