Files
ksv741 329d66e767
Specs security / security (push) Successful in 8s
Specs verify / verify (push) Successful in 11s
spec: finalize wealth-ledger SDD migration
2026-10-09 21:14:22 +03:00

180 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Context
Согласован отдельный репозиторий `deploy` и команда `./deploy.sh <tag>` по 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 |