spec: define versioned deployment bundle #14
@@ -0,0 +1,2 @@
|
|||||||
|
schema: wealth-ledger-sdd
|
||||||
|
created: 2026-09-20
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
## 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 |
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
## Why
|
||||||
|
|
||||||
|
После выпуска компонентов оператор вручную выбирает совместимые версии
|
||||||
|
и повторяет порядок обновления. Нужен один выбранный релиз всей установки
|
||||||
|
и одна команда, сохраняющая данные и настройки существующего сервера.
|
||||||
|
|
||||||
|
## What Changes
|
||||||
|
|
||||||
|
- Версионируемый комплект закрепляет проверенную пару версий интерфейса и API.
|
||||||
|
- Оператор явно выбирает релиз; публикация компонента не обновляет сервер.
|
||||||
|
- Обновление выполняется одной командой с предварительными проверками,
|
||||||
|
сохранением данных и диагностируемым результатом.
|
||||||
|
- Обновление только интерфейса не прерывает работу API и не затрагивает базу.
|
||||||
|
- Перед обновлением API создаётся согласованная резервная копия. Неудачное
|
||||||
|
обновление не запускает автоматическое восстановление или откат.
|
||||||
|
- Инструкция охватывает подготовку сервера, первую установку, подключение
|
||||||
|
существующей установки, выпуск комплекта, обновление и ручное восстановление.
|
||||||
|
|
||||||
|
Non-goals: настройка серверной инфраструктуры командой развёртывания,
|
||||||
|
автоматическое обновление по выходу компонента, непрерывная доступность,
|
||||||
|
несколько экземпляров API, автоматическая очистка копий и внешнее backup-хранилище.
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
### New Capabilities
|
||||||
|
|
||||||
|
- `specs/deployment-bundle/spec.md`: выбор полного релиза, безопасная автоматизация
|
||||||
|
обновления и сохранение существующей установки.
|
||||||
|
|
||||||
|
### Modified Capabilities
|
||||||
|
|
||||||
|
Нет. Новый контракт дополняет контейнерную поставку; существующий active change
|
||||||
|
`containerized-application-delivery` и его capability `application-delivery`
|
||||||
|
не изменяются и не архивируются в рамках этой работы.
|
||||||
|
|
||||||
|
## Impact
|
||||||
|
|
||||||
|
Основной пользователь — оператор одной установки WealthLedger. Изменяются
|
||||||
|
комплект развёртывания, эксплуатационная документация и требования к обновлению.
|
||||||
|
Прикладные функции интерфейса и API остаются прежними.
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
## Purpose
|
||||||
|
|
||||||
|
Определяет установку выбранного релиза WealthLedger одной командой,
|
||||||
|
сохранение состояния сервера и безопасный результат успешного или неудачного обновления.
|
||||||
|
|
||||||
|
## ADDED Requirements
|
||||||
|
|
||||||
|
### Requirement: Релиз определяет полную пару компонентов
|
||||||
|
|
||||||
|
Комплект SHALL иметь отдельную неизменяемую версию, однозначно определяющую
|
||||||
|
проверенную пару версий интерфейса и API. Оператор MUST явно выбирать релиз
|
||||||
|
комплекта. Публикация компонента MUST NOT автоматически выпускать комплект
|
||||||
|
или обновлять сервер; локальные настройки MUST NOT незаметно подменять пару.
|
||||||
|
|
||||||
|
#### Scenario: Установка выбранного релиза
|
||||||
|
|
||||||
|
- **WHEN** оператор выбирает опубликованный релиз комплекта
|
||||||
|
- **THEN** устанавливается ровно закреплённая в нём пара, даже если опубликованы
|
||||||
|
более новые версии компонентов
|
||||||
|
|
||||||
|
#### Scenario: Отсутствующий или изменённый релиз
|
||||||
|
|
||||||
|
- **WHEN** выбранный релиз отсутствует либо ранее полученная версия теперь
|
||||||
|
указывает на другое содержимое
|
||||||
|
- **THEN** операция завершается ошибкой до изменения работающей установки
|
||||||
|
|
||||||
|
### Requirement: Проверки предшествуют изменению установки
|
||||||
|
|
||||||
|
Одна команда SHALL выполнять установку выбранного релиза на подготовленном
|
||||||
|
сервере. До остановки приложения она MUST проверить доступность комплекта,
|
||||||
|
его компонентов, обязательных настроек и постоянных ресурсов.
|
||||||
|
Отсутствующая база существующей установки MUST NOT трактоваться как новая
|
||||||
|
пустая установка. Секреты MUST NOT попадать в диагностический вывод.
|
||||||
|
|
||||||
|
#### Scenario: Компонент недоступен
|
||||||
|
|
||||||
|
- **WHEN** выбранный компонент нельзя получить или обязательный сертификат
|
||||||
|
либо каталог данных недоступен
|
||||||
|
- **THEN** обновление завершается с понятной ошибкой, не останавливая
|
||||||
|
работающие компоненты и не создавая замену отсутствующим данным
|
||||||
|
|
||||||
|
#### Scenario: Новая установка
|
||||||
|
|
||||||
|
- **WHEN** оператор явно подготовил новую установку с отдельным пустым
|
||||||
|
хранилищем и необходимыми настройками
|
||||||
|
- **THEN** команда подготавливает данные и запускает выбранный релиз,
|
||||||
|
не требуя предыдущей установленной версии
|
||||||
|
|
||||||
|
### Requirement: Существующая установка сохраняет состояние
|
||||||
|
|
||||||
|
Подключение существующей установки и последующие обновления MUST сохранять
|
||||||
|
её пользовательские данные, сессии, ключи шифрования и настройки доверия
|
||||||
|
внешнему провайдеру. Эти ресурсы MUST храниться независимо от обновляемого
|
||||||
|
комплекта. Команда MUST NOT запускать второй API на той же базе или генерировать
|
||||||
|
новые ключи вместо действующих.
|
||||||
|
|
||||||
|
#### Scenario: Переход с прежнего способа запуска
|
||||||
|
|
||||||
|
- **WHEN** оператор подключает существующую установку к комплекту
|
||||||
|
- **THEN** используются её прежние данные и ключи; после запуска доступны
|
||||||
|
существующие записи и расшифровка сохранённого подключения
|
||||||
|
|
||||||
|
### Requirement: Обновление затрагивает только изменённые компоненты
|
||||||
|
|
||||||
|
Если меняется только интерфейс, команда MUST сохранять работающий API,
|
||||||
|
не изменять данные и не запускать миграции или резервное копирование.
|
||||||
|
Изменение настроек API SHALL считаться изменением API, даже при той же версии.
|
||||||
|
Обновление только API MUST NOT пересоздавать неизменный интерфейс.
|
||||||
|
Повторное применение уже установленного исправного релиза с теми же настройками
|
||||||
|
MUST NOT выполнять ненужное обновление или резервное копирование.
|
||||||
|
|
||||||
|
#### Scenario: Новый интерфейс при прежнем API
|
||||||
|
|
||||||
|
- **WHEN** выбранный релиз меняет только интерфейс, а API и его настройки
|
||||||
|
подтверждённо совпадают с установленными
|
||||||
|
- **THEN** обновляется только интерфейс, API продолжает работу без миграций
|
||||||
|
и резервного копирования для этой операции
|
||||||
|
|
||||||
|
#### Scenario: Та же версия API с другими настройками
|
||||||
|
|
||||||
|
- **WHEN** версия API прежняя, но его настройки изменились
|
||||||
|
- **THEN** применяется безопасная процедура обновления API
|
||||||
|
|
||||||
|
#### Scenario: Повтор успешно установленного релиза
|
||||||
|
|
||||||
|
- **WHEN** выбран уже установленный исправный релиз без изменений настроек
|
||||||
|
- **THEN** команда сообщает, что обновление не требуется, без остановки
|
||||||
|
компонентов и без новой резервной копии
|
||||||
|
|
||||||
|
### Requirement: Обновление API сохраняет согласованную копию
|
||||||
|
|
||||||
|
Перед обновлением API существующей установки команда MUST остановить запись
|
||||||
|
и успешно сохранить согласованную копию всех постоянных данных до миграций.
|
||||||
|
Копии MUST находиться вне обновляемого комплекта; команда MUST NOT удалять
|
||||||
|
или перезаписывать прежние копии автоматически. Неуспешная копия MUST
|
||||||
|
блокировать миграции. Новая пустая установка не требует фиктивного backup.
|
||||||
|
|
||||||
|
#### Scenario: Подготовка обновления API
|
||||||
|
|
||||||
|
- **WHEN** выбран релиз с изменением API существующей установки
|
||||||
|
- **THEN** до миграций сохраняется отдельная согласованная копия при отсутствии
|
||||||
|
пишущих процессов, и оператор получает её расположение
|
||||||
|
|
||||||
|
#### Scenario: Копию сохранить не удалось
|
||||||
|
|
||||||
|
- **WHEN** резервное копирование завершилось ошибкой
|
||||||
|
- **THEN** миграции и запуск новой версии не выполняются, существующие данные
|
||||||
|
и прежние копии сохраняются, операция сообщает ошибку
|
||||||
|
|
||||||
|
### Requirement: Неудачное обновление не скрывает риск для данных
|
||||||
|
|
||||||
|
Ошибка миграции MUST блокировать запуск новой версии API. Если после миграции
|
||||||
|
API не готов, команда MUST остановить неисправный API и завершиться с ошибкой.
|
||||||
|
Любая неуспешная проверка обновляемого компонента MUST блокировать отметку
|
||||||
|
релиза как успешно установленного. Диагностика SHALL указывать этап сбоя,
|
||||||
|
предыдущую версию и доступный backup без раскрытия секретов.
|
||||||
|
Автоматический откат или восстановление данных MUST NOT выполняться.
|
||||||
|
|
||||||
|
#### Scenario: Миграция не прошла
|
||||||
|
|
||||||
|
- **WHEN** подготовка схемы завершается ошибкой
|
||||||
|
- **THEN** API остаётся остановленным, а результат содержит сведения для
|
||||||
|
отдельного решения о восстановлении
|
||||||
|
|
||||||
|
#### Scenario: Новый API не готов
|
||||||
|
|
||||||
|
- **WHEN** миграция завершилась успешно, но проверка готовности API не прошла
|
||||||
|
- **THEN** неисправный API останавливается без автоматического запуска старой
|
||||||
|
версии или восстановления базы
|
||||||
|
|
||||||
|
#### Scenario: Неудачное обновление интерфейса
|
||||||
|
|
||||||
|
- **WHEN** при обновлении только интерфейса его проверка запуска не прошла
|
||||||
|
- **THEN** операция завершается ошибкой, API продолжает работу, база не
|
||||||
|
восстанавливается, релиз не отмечается успешно установленным
|
||||||
|
|
||||||
|
### Requirement: Повтор и конкуренция не нарушают порядок обновления
|
||||||
|
|
||||||
|
Команда MUST исключать одновременные изменения одной установки несколькими
|
||||||
|
запусками. Прерванное или неуспешное обновление MUST отличаться от успешно
|
||||||
|
установленного релиза. Повтор команды после потенциального изменения данных
|
||||||
|
MUST NOT скрывать незавершённую операцию или автоматически восстанавливать данные.
|
||||||
|
|
||||||
|
#### Scenario: Второе обновление
|
||||||
|
|
||||||
|
- **WHEN** для установки уже выполняется обновление
|
||||||
|
- **THEN** второй запуск завершается без изменения её состояния
|
||||||
|
|
||||||
|
#### Scenario: Процесс прерван после начала обновления
|
||||||
|
|
||||||
|
- **WHEN** предыдущая операция прервана после остановки API или начала миграции
|
||||||
|
- **THEN** следующий запуск сообщает о незавершённой операции и необходимости
|
||||||
|
проверки состояния до нового обновления
|
||||||
|
|
||||||
|
### Requirement: Оператор располагает полным порядком эксплуатации
|
||||||
|
|
||||||
|
Инструкция комплекта SHALL описывать последовательность подготовки сервера,
|
||||||
|
первой установки и подключения существующей установки, подготовку проверенной
|
||||||
|
пары и выпуск релиза, обновление, диагностику, откат версии и отдельное
|
||||||
|
восстановление базы. Она MUST указывать сохранение ключей, ручную очистку
|
||||||
|
локальных копий и отсутствие защиты от потери диска только локальным backup.
|
||||||
|
Восстановление MUST требовать явного выбора копии и принятия потери более
|
||||||
|
новых данных; откат API — проверки совместимости с текущей схемой.
|
||||||
|
|
||||||
|
#### Scenario: Оператор восстанавливает установку
|
||||||
|
|
||||||
|
- **WHEN** оператор использует инструкцию после неудачного обновления
|
||||||
|
- **THEN** он может отдельно выбрать совместимую версию приложения или
|
||||||
|
восстановление конкретной копии с явным учётом потери новых данных
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
## 1. Самодостаточный комплект
|
||||||
|
|
||||||
|
- [x] 1.1 [deploy] Создать production Compose, release.env и пример server env, переиспользовав существующие images/migration/healthchecks и сохранив read-only CA mount и постоянные абсолютные пути.
|
||||||
|
- **Covers:** `deployment-bundle` — `Релиз определяет полную пару компонентов`; `deployment-bundle` — `Существующая установка сохраняет состояние`
|
||||||
|
- **Verification:** `docker compose --env-file <disposable-server.env> --env-file release.env -f compose.yaml config --quiet`; inspect подтверждает выбранную пару, один backend, общий data mount migration/backend, отсутствие host port API и read-only сертификат; exported image variables не подменяют релиз через entrypoint.
|
||||||
|
|
||||||
|
- [x] 1.2 [deploy] Реализовать получение выбранного тега, выполнение snapshot его commit, preflight, flock и минимальные записи состояния в одном deploy.sh согласно Solution Assessment.
|
||||||
|
- **Covers:** `deployment-bundle` — `Релиз определяет полную пару компонентов`; `deployment-bundle` — `Проверки предшествуют изменению установки`; `deployment-bundle` — `Повтор и конкуренция не нарушают порядок обновления`
|
||||||
|
- **Verification:** `bash -n deploy.sh`; сценарная проверка отсутствующего/переназначенного тега, недоступного image/CA/data, отказа второго запуска и отсутствия изменений runtime при preflight failure; snapshot использует deploy-логику выбранного commit.
|
||||||
|
|
||||||
|
## 2. Безопасный lifecycle и его доказательство
|
||||||
|
|
||||||
|
- [x] 2.1 [deploy] Реализовать first install/adoption, выбор изменённых сервисов, stop/backup/migration/readiness и остановку последовательности при ошибке без автоматического rollback.
|
||||||
|
- **Covers:** `deployment-bundle` — `Проверки предшествуют изменению установки`; `deployment-bundle` — `Существующая установка сохраняет состояние`; `deployment-bundle` — `Обновление затрагивает только изменённые компоненты`; `deployment-bundle` — `Обновление API сохраняет согласованную копию`; `deployment-bundle` — `Неудачное обновление не скрывает риск для данных`; `deployment-bundle` — `Повтор и конкуренция не нарушают порядок обновления`
|
||||||
|
- **Verification:** На disposable Compose project проверить явный `--init`, adoption существующей тестовой БД, обновление обоих компонентов и API отдельно, неизменность container ID API при frontend-only update, отсутствие повторного backup при healthy no-op; изменение backend config включает backup даже с прежним image.
|
||||||
|
|
||||||
|
- [x] 2.2 [deploy] Добавить одну исполняемую проверку tests/deploy.sh без нового test framework и закрепить локальный gate для shell и сценариев обновления.
|
||||||
|
- **Covers:** `deployment-bundle` — `Релиз определяет полную пару компонентов`; `deployment-bundle` — `Проверки предшествуют изменению установки`; `deployment-bundle` — `Существующая установка сохраняет состояние`; `deployment-bundle` — `Обновление затрагивает только изменённые компоненты`; `deployment-bundle` — `Обновление API сохраняет согласованную копию`; `deployment-bundle` — `Неудачное обновление не скрывает риск для данных`; `deployment-bundle` — `Повтор и конкуренция не нарушают порядок обновления`
|
||||||
|
- **Verification:** `bash -n deploy.sh tests/deploy.sh`, `bash tests/deploy.sh`, `git diff --check`; fault injection доказывает отсутствие migration после failed copy, отсутствие backend start после failed migration, stop после backend readiness failure, сохранение backend после frontend failure, неизменность данных/старых backups, блокировку конкуренции и незавершённой операции. Проверка использует временные данные; production paths недопустимы.
|
||||||
|
|
||||||
|
## 3. Эксплуатация и документация
|
||||||
|
|
||||||
|
- [x] 3.1 [deploy] Описать в README подготовку сервера, сохранение старых ключей и Compose project, install/update, выпуск тега с проверенной парой, диагностику, ручной rollback/restore и очистку backups; закрепить реально опубликованную первую пару перед выпуском.
|
||||||
|
- **Covers:** `deployment-bundle` — `Оператор располагает полным порядком эксплуатации`; `deployment-bundle` — `Релиз определяет полную пару компонентов`
|
||||||
|
- **Verification:** Пройти инструкцию на изолированной установке с тестовыми данными; проверить login/refresh через HTTPS, сохранение записей и расшифровку тестового подключения прежним ключом, `PRAGMA integrity_check` на копии и explicit restore; сравнить actual images с release.env. Первый тег не публиковать до проверки пары.
|
||||||
|
|
||||||
|
- [x] 3.2 [docs] Завершить ADR 016 и glossary, обновить production-раздел контейнерной поставки под deploy с сохранением development-инструкции и границ ручного recovery.
|
||||||
|
- **Covers:** `N/A` — docs объясняет поставленный механизм из Design и направляет оператора к единственному README комплекта; самостоятельного runtime behavior не добавляет.
|
||||||
|
- **Verification:** После `nvm use --silent` выполнить `npm run verify` в docs; проверить маршрут README → deployment → ADR и отсутствие обещаний ещё не реализованных операций или дублирующего production runbook.
|
||||||
|
|
||||||
|
- [x] 3.3 [root] Направить production-раздел root README к комплекту deploy, сохранив существующие development-команды.
|
||||||
|
- **Covers:** `N/A` — workspace-навигация должна вести к владельцу production lifecycle из Design; поведение приложения и root tooling не меняются.
|
||||||
|
- **Verification:** `git diff --check` в root; просмотр маршрута root README → deploy README и docs/architecture/deployment.md, проверка неизменности development-команд.
|
||||||
|
|
||||||
|
## 4. Сверка поставки
|
||||||
|
|
||||||
|
- [x] 4.1 [specs] Сверить артефакты с фактической реализацией, сохранить coverage всех требований и проверить canonical change без изменения чужого containerized-application-delivery.
|
||||||
|
- **Covers:** `N/A` — requirements и checklist должны оставаться контрактом реализованного комплекта; задача поддерживает точность SDD, а не вводит новое поведение приложения.
|
||||||
|
- **Verification:** После `nvm use --silent`: `openspec schema validate wealth-ledger-sdd --verbose`; `openspec validate versioned-deployment-bundle --type change --strict --store wealth-ledger-specs`; `openspec validate --specs --strict --store wealth-ledger-specs`; `npm run verify`; вручную проверить task coverage и соответствие дополнительному owner deploy из Delivery Map.
|
||||||
|
|
||||||
|
- [x] 4.2 [workspace] Выполнить итоговую сверку сценариев установки, ошибок и восстановления с готовыми образами и результатами локальных gates затронутых репозиториев.
|
||||||
|
- **Covers:** `N/A` — объединяет доказательства deploy/specs/docs для согласованной пары, не владеет реализацией какого-либо репозитория и не заменяет independent review.
|
||||||
|
- **Verification:** На disposable данных сверить успешный update, frontend-only, interrupted update и recovery с Delta Specs; зафиксировать фактические версии и результаты gates. Проверки реального сервера не подменять локальным smoke; production rollout не входит в эту задачу.
|
||||||
|
|
||||||
|
## 5. Implementation checkpoint
|
||||||
|
|
||||||
|
2026-09-20: implementation-owned задачи выполнены; готово к независимой Validation.
|
||||||
|
Change остаётся active. Первый тег deploy не опубликован, рабочий сервер не изменялся.
|
||||||
|
|
||||||
|
- Deploy: `bash -n deploy.sh tests/deploy.sh`, `bash tests/deploy.sh` — PASS.
|
||||||
|
Проверены selective update/no-op, config drift, сохранение ключей, symlink guard,
|
||||||
|
ошибки pull/preflight/copy/migration/backend/frontend, concurrent lock и pending.
|
||||||
|
- `DOCKER_DEFAULT_PLATFORM=linux/amd64 bash tests/deploy.sh --docker-restore` — PASS:
|
||||||
|
заменённый bind-каталог читается после force-recreate. Без пересоздания исходный
|
||||||
|
live repro читал старые данные; README recovery исправлен по этому результату.
|
||||||
|
- Disposable smoke с реальными Nexus images `0.2.3` — PASS: init, no-op по native
|
||||||
|
Compose hash, frontend-only/backend-only config update, stopped backup,
|
||||||
|
`PRAGMA integrity_check`, HTTPS deep link, registration, Secure-cookie и refresh.
|
||||||
|
- Explicit restore на синтетических данных — PASS: login, карта и её баланс,
|
||||||
|
отсутствие более новой карты и расшифровка тестового токена штатным TbankCrypto.
|
||||||
|
Оба тестовых Compose projects удалены; настоящие пользовательские данные
|
||||||
|
и реальное подключение к T-Bank не использовались.
|
||||||
|
- OCI revisions совпали с Git tags компонентов: frontend
|
||||||
|
`f486ae4fb2d06e71779901bde283950542f27ed2`, backend
|
||||||
|
`0862d56c4e4d9dd554556c3992cc073193020ff1`.
|
||||||
|
- Среда интеграционной проверки: Docker Desktop, Linux amd64 images через
|
||||||
|
эмуляцию на arm64 Mac, Compose 5.5.1; host flock в smoke заменён stdlib fcntl.
|
||||||
|
Это не проверка конфигурации целевого Linux-сервера или его registry login.
|
||||||
Reference in New Issue
Block a user