Files
specs/openspec/changes/containerized-application-delivery/tasks.md
T
ksv741 b34f23a230
Specs security / security (pull_request) Successful in 6s
Specs verify / verify (pull_request) Successful in 8s
Conventional commits / commits (pull_request) Successful in 11s
Specs security / security (push) Successful in 6s
Specs verify / verify (push) Successful in 9s
spec: define containerized application delivery #10
2026-09-16 09:41:59 +03:00

220 lines
26 KiB
Markdown
Raw 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.
# Контейнерная разработка и поставка WealthLedger
Основание — утверждённые [Proposal](proposal.md),
[Delta Specs](specs/application-delivery/spec.md) и [Design revision 1](design.md).
UI/UX package неприменим: пользовательские экраны и interactions не меняются.
Checkbox закрывается только после выполнения действия и его Verification.
Перед Node-командами активируется `.nvmrc` соответствующего независимого
репозитория. Git-команды выполняются из репозитория-владельца; production data,
secrets и опубликованные release tags не используются как test fixtures.
Задачи выполняются по порядку разделов. Frontend 2.1–2.2 и backend 3.1–3.2
могут идти параллельно после 1.2. Workspace orchestration начинается после
готовности обоих component images. Реальный server rollout выполняется только
после локального production smoke и документированного backup.
## 1. SDD и внешние prerequisites
- [x] 1.1 [specs] Проверить утверждённый SDD package закреплённым OpenSpec CLI и сохранить canonical change структурно валидным до Apply.
- **Covers:** `N/A` — обязательный gate canonical SDD authority; он не добавляет runtime behavior, но разрешает реализацию утверждённых требований и Design.
- **Verification:** с версией из `openspec/.cli-version` выполнить `openspec schema validate wealth-ledger-sdd --verbose`, `openspec validate containerized-application-delivery --type change --strict --store wealth-ledger-specs`, `openspec validate --specs --strict --store wealth-ledger-specs`, затем `npm run verify`.
- **Result (2026-09-16):** по явному уточнению владельца использован установленный OpenSpec 1.13.0 вместо 1.10.0. Все четыре проверки прошли; 25 specs passed, 0 failed. Repository-wide pin не изменён.
- [ ] 1.2 [workspace] Подтвердить prerequisites выбранного Solution Assessment: Docker Compose на development/server hosts, Docker-capable Gitea runner, Container Registry и раздельные package write/read credentials.
- **Covers:** `N/A` — техническое предусловие утверждённой Compose/Registry delivery; оно не вводит самостоятельное поведение приложения и блокирует custom fallback при отсутствии platform capability.
- **Verification:** зафиксировать поддерживаемые Docker/Compose и Gitea versions; `docker version`, `docker compose version`, успешные authenticated registry login для CI publisher и server pull-only identity без вывода credentials.
- **Partial result (2026-09-16):** локально Docker Desktop 4.91.0, Engine 29.8.0 (Linux arm64), Compose 5.5.1; Gitea API сообщает 1.27.3. Server Docker/Compose и Docker-capable runner пока не подтверждены. MCP identity не имеет доступа к Actions secrets (`user should be the owner of the repo`); раздельные publisher/pull-only login не проверены. Publication и server rollout остаются внешними gates; независимая локальная реализация продолжается.
## 2. Frontend image и ingress
- [x] 2.1 [frontend] Добавить development и production image targets: Dockerized Vite watch с same-origin `/api/` proxy и nginx runtime со SPA fallback, API proxy, runtime DNS re-resolution, cache policy и non-root-compatible filesystem.
- **Covers:** `application-delivery` — `Локальная среда воспроизводит границы поставленного приложения`; `application-delivery` — `Серверное приложение имеет одну внешнюю точку входа`.
- **Verification:** собрать оба targets; development container через container network отдаёт HMR и сохраняет `/api/v1/...`; production container отдаёт SPA/deep link, проксирует API без rewrite, не раскрывает backend port и после backend recreation подключается к новому container address.
- [ ] 2.2 [frontend] Добавить release-tag workflow публикации frontend image с проверкой версии, canonical frontend gate, OCI revision metadata и immutable semver tags без `latest`.
- **Covers:** `application-delivery` — `Поставка допускает независимое обновление компонентов`.
- **Verification:** workflow syntax принимается Gitea; controlled candidate run после `npm run verify` публикует image, registry возвращает digest, clean pull по digest запускает тот же static artifact; credential отсутствует в logs и image history.
- [x] 2.3 [frontend] Выполнить frontend repository completion gate после packaging и routing changes.
- **Covers:** `N/A` — repository-owned проверка реализации Design и отсутствие regression в существующем frontend; отдельного observable requirement не создаёт.
- **Verification:** `npm ci`, `npm run verify`, `git diff --check`; вручную просмотреть новые Docker/nginx/workflow files и отсутствие secrets.
### Результаты frontend (2026-09-16)
- 2.1: оба targets собраны на Linux arm64; Vite HMR WebSocket connected,
`/api/v1/probe?check=path` сохранён. nginx read-only + tmpfs отдаёт deep link
с `no-cache`, proxy сохраняет path/query/host/proto/request ID. Backend без
host port пересоздан с другим IP (.2 → .5); nginx восстановил proxy без restart.
- 2.2: release-tag workflow реализован с `ubuntu-latest` (label подтверждён
владельцем). Реальный runner Docker access, registry write/read credentials,
Gitea workflow acceptance и controlled publication пока не проверены.
- 2.3: `npm ci`, `npm run verify`, `git diff --check` прошли. Docker context
ограничен allowlist; `.env`, credentials и host dependencies не копируются.
Новые Docker/nginx/workflow files просмотрены; publication secrets идут
только в отдельный Docker login, не в image build arguments.
## 3. Backend image, migration и readiness
- [x] 3.1 [backend] Добавить development и production image targets с Linux native dependencies, compiled application, generated Prisma client, runtime Prisma CLI/migrations, T-Bank proto assets, non-root process и выделенным data path.
- **Covers:** `application-delivery` — `Локальная среда воспроизводит границы поставленного приложения`; `application-delivery` — `Постоянное состояние и секреты переживают штатный lifecycle`; `application-delivery` — `Обновление API сохраняет целостность данных`.
- **Verification:** development target выполняет Nest watch; production target стартует из чистого image, находит proto contracts, принимает config только из environment, пишет только в data path; одноразовый `prisma migrate deploy` проходит на fresh и representative existing SQLite, а приложение не стартует после контролируемой migration failure.
- [ ] 3.2 [backend] Добавить release-tag workflow публикации backend image с проверкой версии, полными backend gates, OCI revision metadata и immutable semver tags без `latest`.
- **Covers:** `application-delivery` — `Поставка допускает независимое обновление компонентов`.
- **Verification:** workflow syntax принимается Gitea; controlled candidate run выполняет `npm run verify` и `npm run test:e2e`, публикует image и получает digest; clean pull по digest выполняет migration и production start, credential отсутствует в logs и image history.
- [x] 3.3 [backend] Выполнить backend repository completion gates и проверить container readiness без нового публичного endpoint.
- **Covers:** `N/A` — repository-owned проверка packaging, existing auth boundary и SQLite integration из Design; самостоятельного нового API behavior нет.
- **Verification:** `npm ci`, `npm run verify`, `npm run test:e2e`, `git diff --check`; healthcheck принимает завершённый HTTP-ответ existing auth route, а stopped/uninitialized process остаётся unhealthy.
## 4. Workspace Compose orchestration
- [x] 4.1 [workspace] Добавить production Compose topology с version-tagged frontend/backend references, migration service, healthchecks, persistent host data directory, internal-only backend и единственным configurable frontend loopback port.
- **Covers:** `application-delivery` — `Серверное приложение имеет одну внешнюю точку входа`; `application-delivery` — `Поставка допускает независимое обновление компонентов`; `application-delivery` — `Постоянное состояние и секреты переживают штатный lifecycle`; `application-delivery` — `Обновление API сохраняет целостность данных`.
- **Verification:** `docker compose config` с non-secret fixture environment; rendered config содержит один host port, один backend replica, одинаковый backend image reference у migration/runtime и отдельный data mount; missing required image/config/secret values дают blocking configuration/start failure.
- [x] 4.2 [workspace] Добавить development Compose override с local image targets, source watch/mounts, container-owned dependencies, отдельным local data volume и одним frontend browser origin.
- **Covers:** `application-delivery` — `Локальная среда воспроизводит границы поставленного приложения`; `application-delivery` — `Постоянное состояние и секреты переживают штатный lifecycle`.
- **Verification:** с чистыми local volumes запустить Compose; frontend edit появляется через HMR, backend edit перезапускает Nest, `/api/v1/...` идёт через frontend origin, host `node_modules` не используется, restart сохраняет local data, production data path отсутствует в rendered config.
- [x] 4.3 [workspace] Обновить root tracking allowlist и README entrypoints без custom scripts или нового root CI, затем проверить orchestration configuration.
- **Covers:** `N/A` — root только связывает независимые component repositories и объясняет стандартные Compose entrypoints согласно Design; runtime behavior реализуется component images и Compose tasks 4.1–4.2.
- **Verification:** `docker compose config` для production и development variants, `git diff --check`, просмотр `git status --short` и staged paths подтверждают только явно разрешённые root files; root workflow остаётся только commitlint.
## 5. Эксплуатационная документация
- [x] 5.1 [docs] Добавить ADR об ограниченном single-server SQLite deployment и обновить container architecture фактической Docker/Caddy topology, secret и persistence boundaries.
- **Covers:** `application-delivery` — `Серверное приложение имеет одну внешнюю точку входа`; `application-delivery` — `Постоянное состояние и секреты переживают штатный lifecycle`.
- **Verification:** ADR явно связывает решение с прежним local-only baseline, одним backend instance и triggers пересмотра; architecture diagram показывает только frontend port наружу, internal backend и persistent SQLite; ссылки и термины согласованы.
- [x] 5.2 [docs] Описать development, first deployment, independent component update, stopped-backend backup, compatibility check, rollback и explicit restore runbooks.
- **Covers:** `application-delivery` — `Локальная среда воспроизводит границы поставленного приложения`; `application-delivery` — `Поставка допускает независимое обновление компонентов`; `application-delivery` — `Обновление API сохраняет целостность данных`; `application-delivery` — `Восстановление не выдаёт откат приложения за откат данных`.
- **Verification:** dry-run runbook на disposable data проходит без неописанного шага; frontend-only и backend-only paths не пересоздают другой component; restore требует отдельного решения и сообщает о потере данных после backup.
- [ ] 5.3 [docs] Выполнить docs repository completion gate.
- **Covers:** `N/A` — repository-owned проверка durable as-built documentation и ссылок без нового runtime behavior.
- **Verification:** `npm ci`, `npm run verify`, `git diff --check`; проверить Mermaid rendering, взаимные ADR/architecture/runbook links и отсутствие credentials или host-private values.
## 6. Сквозная проверка поставки
- [x] 6.1 [workspace] Проверить development Compose на чистом checkout и production Compose на локально собранных release-equivalent images.
- **Covers:** `application-delivery` — `Локальная среда воспроизводит границы поставленного приложения`; `application-delivery` — `Серверное приложение имеет одну внешнюю точку входа`.
- **Verification:** development подтверждает HMR/watch и same-origin login; production smoke подтверждает SPA deep link, registration/login/refresh, API proxy, отсутствие host backend port и clean startup через migration service.
- [x] 6.2 [workspace] На disposable representative SQLite проверить persistence, frontend-only update, backend-only update, migration failure и rollback boundaries.
- **Covers:** `application-delivery` — `Поставка допускает независимое обновление компонентов`; `application-delivery` — `Постоянное состояние и секреты переживают штатный lifecycle`; `application-delivery` — `Обновление API сохраняет целостность данных`; `application-delivery` — `Восстановление не выдаёт откат приложения за откат данных`.
- **Verification:** restart сохраняет user/session/card data и decryptable test connection; frontend update не recreates backend/data, backend update не recreates frontend; failed migration не делает backend healthy; возврат совместимого image сохраняет current data, а restore отдельной backup copy выполняется только в изолированном scenario с явной проверкой потерянного интервала.
- [ ] 6.3 [workspace] Проверить release images из Gitea по выбранным version tags перед первым server rollout и сохранить точную установленную пару версий.
- **Covers:** `application-delivery` — `Поставка допускает независимое обновление компонентов`; `application-delivery` — `Постоянное состояние и секреты переживают штатный lifecycle`.
- **Verification:** pull-only server identity получает оба versioned images; `docker image inspect` подтверждает expected revisions; production smoke проходит на этих images с disposable config/data, после чего оператор записывает выбранные image references без secrets.
## Apply verification — 2026-09-16
### Backend (3.1–3.3)
- Development и production targets собраны на Linux arm64 / Node 24.21.0.
Node/nginx base images закреплены digest; OS packages — точными версиями.
Чистый production runtime обнаружил неверный прежний fallback proto path:
Nest копирует assets в `dist/src`; loader теперь использует `__dirname`.
Nest watch использует `ps`; `procps` добавлен только в development target.
- `npm ci`, `npm run verify` — PASS (35 suites). `npm audit` при переносе
существующего Prisma 7.10.0 в runtime dependencies — 0 vulnerabilities.
- `npm run test:e2e` на macOS дважды завершился native Node SIGABRT
(`RemoveEnvironmentCleanupHook`, `env != nullptr`). Тот же штатный gate
выполнен в Linux development image: **8 suites / 98 tests PASS**. Это
Linux delivery proof; macOS native cleanup limitation не скрывается.
- `npm run test:container -- wealthledger-backend:production` — runnable
image regression: fresh/existing migration, runtime без source/.env/compiler,
non-root + read-only filesystem, существующий auth readiness, user/session
persistence. Он же вызывается publish workflow после clean pull.
- Controlled broken SQLite migration возвращает non-zero; backend остаётся
остановленным. После возвращения исправного data path migration идемпотентна.
- 3.2 остаётся открытой: YAML и shell syntax проверены локально, но Gitea
acceptance, authenticated publication и pull по registry digest не выполнены.
### Compose, docs и lifecycle (4–6)
- Production/development `docker compose config` — PASS. Проверены один
loopback host port, backend scale 1, общий backend image/data mount у
migration/runtime, readiness dependency и отсутствие production bind mount
в development services. Пустая production environment блокирует config.
- `docker compose up -d --wait` — PASS для development и production на
локально собранных release-equivalent images. Production smoke использовал
временный override local image references; canonical config остаётся
digest-pinned. Реальный Gitea digest pull этим не подменяется.
- Development: source edit вызвал HMR event и изменённый HTTP module, backend
source edit — новый Nest process и готовый API. Временные изменения
восстановлены. Same-origin registration/login/refresh и data restart PASS.
- Clean checkout proof: отдельный HEAD export + task diff, без host .env и
node_modules, новый Compose project/volume; startup и HMR/watch PASS.
- Browser proof (bundled Playwright/Chrome): clean development и production
registration/login/reload-refresh PASS; все API requests same-origin,
httpOnly/path сохранены, production cookie Secure. Caddy/TLS вне локальной проверки.
- Production: SPA deep link, registration/login/refresh, неизменённый API path,
отсутствие backend host port, non-root read-only runtime — PASS.
- Representative disposable SQLite содержит user/session/card и connection,
зашифрованный настоящим TbankCrypto на вымышленном token. Restart, migrations
и independent recreation сохраняют данные и расшифровку без внешнего T-Bank.
- Отдельные local fixture image IDs проверили frontend-only/backend-only
update без recreation другого компонента. Возврат прежнего совместимого
backend image сохраняет запись после backup. Это compatibility fixture,
не обещание совместимости произвольных будущих релизов.
- Stopped-backend backup и isolated restore с отдельным project/port/data path
— PASS: login, карта до backup и decryptable connection доступны; запись
после backup отсутствует в восстановленной копии. Текущая база не заменялась.
- Docs: ADR 015 расширяет ADR 001; topology и runbook взаимно связаны.
`npm ci`, `npm run verify` — PASS (44 Markdown files), `git diff --check`
— PASS. Mermaid source семантически просмотрен, но renderer в доступном
окружении не найден; **5.3 оставлена открытой до проверки rendering**.
- Root Boy Scout/allowlist review: только Compose, два безопасных env examples,
README и .gitignore; новых root scripts/dependencies/CI нет. Source markers
watch checks восстановлены. Чужие runtime data и checkout changes сохранены.
- Docker disk был заполнен. После адресной очистки intermediates этой задачи
и отдельно разрешённой очистки unused build cache старше суток проверки
продолжены; чужие images/containers/volumes не удалялись.
### Оставшиеся внешние gates
- 1.2: server Docker/Compose, Docker capability runner `ubuntu-latest`,
раздельные package writer и server pull-only authenticated login.
- 2.2/3.2: реальные Gitea candidate workflows и публикация frontend/backend,
OCI revisions, registry digests, clean pull и отсутствие credentials в logs.
Нужны Actions secrets `REGISTRY_USERNAME`/`REGISTRY_TOKEN` в каждом component
repo и отдельная server identity. Workflow не публикует `latest` и fail-closed
отказывается от overwrite или недоказанного отсутствия tag.
- 6.3: smoke опубликованной пары version tags на disposable server config/data,
запись installed image references/revisions до первого server rollout.
Server rollout, Caddy, TLS и реальный финансовый запрос не выполнялись.
### Упрощение deployment configuration по запросу владельца
Обязательные `FRONTEND_DIGEST`/`BACKEND_DIGEST` и отдельные repository fields
заменены на `FRONTEND_IMAGE`/`BACKEND_IMAGE` с release version tags.
Design и runbook синхронизированы. Результаты выше описывают первоначальную
проверку; обязательный digest pinning более не является deployment contract.
Migration и backend по-прежнему используют один image reference.
Verification упрощения: production/development `docker compose config` PASS;
разные version tags выбираются независимо, migration/runtime получают один
backend image, один loopback port и development volume сохранены. Пустые
image/secret values блокируют config. Docs `npm run verify`, OpenSpec strict
change validation и `git diff --check` в affected repos — PASS.
По следующему запросу владельца из `FROM` удалены base image digests:
используются `node:24.21.0-bookworm-slim` и `nginx:1.28.0-alpine`.
Version tags не гарантируют неизменность содержимого базового image.
Verification: повторная сборка production/development targets обоих компонентов
— PASS (с использованием Docker cache). Dockerfile остаются в component repos,
чтобы standalone build и release CI не зависели от root checkout.
По запросу владельца удалены дополнительные commit tags из обоих workflows;
release tag защищён от перезаписи, revision остаётся в OCI label. Production
Compose наследует healthchecks из images; development содержит собственные
checks с прежними таймингами, migration отключает check.
Verification: production/development Compose config и invariants, healthchecks
локальных production images, shell syntax обоих workflows, docs verify,
OpenSpec strict validation и diff checks — PASS. Registry publication остаётся
внешней непроверенной частью задач 2.2/3.2.