chore(release): 0.1.1 #12
@@ -7,20 +7,20 @@
|
||||
|
||||
Если нужна существующая behavioral spec, выбери точный target через
|
||||
[AI_INDEX](AI_INDEX.md). Specs не являются вторым editable HTTP OpenAPI:
|
||||
backend публикует контракт, а frontend доверяет предоставленному snapshot и
|
||||
локально проверяет generated types; flow описан в
|
||||
[docs](../docs/architecture/http-api.md#источник-контракта).
|
||||
HTTP-провайдер публикует контракт, а потребитель получает отдельный artifact
|
||||
и локально проверяет generated types. Specs фиксируют behavioral requirements;
|
||||
другие checkout не нужны для чтения и native validation этого store.
|
||||
|
||||
Архивы и чужие active changes сохраняй. Для правки индекса проверь targets,
|
||||
anchors и `git diff --check`; application gates принадлежат affected repos.
|
||||
Если явно запрошена работа через OpenSpec, следуй
|
||||
[локальным инструкциям OpenSpec](README.md#начало-работы)
|
||||
и используй store `wealth-ledger-specs`. Перед Node-командами выбери frontend
|
||||
`.nvmrc` через `nvm use --silent`, если здесь нет своей.
|
||||
и используй store `wealth-ledger-specs`. Перед Node-командами активируй
|
||||
местную `.nvmrc` через `nvm use --silent`.
|
||||
|
||||
## Ветки и релизы
|
||||
|
||||
Работа — в отдельной ветке от `develop`, затем PR в `develop`; в `main` напрямую
|
||||
не пушить. Release/hotfix и синхронизация веток — по [root README](../README.md#релизы-и-ветки).
|
||||
не пушить. Release/hotfix и синхронизация веток — по [README](README.md#релизы).
|
||||
Commits и заголовки PR — Conventional Commits; для спецификаций допустим `spec:`.
|
||||
Перед подготовкой релиза прочитай root README; версии вручную не повышать.
|
||||
Перед подготовкой релиза прочитай местный README; версии вручную не повышать.
|
||||
|
||||
+4
-3
@@ -3,13 +3,14 @@
|
||||
Эти существующие specs — источник сохранённых требований по конкретной теме.
|
||||
Читай нужный requirement/scenario, если задача зависит от него; не загружай всё
|
||||
дерево и не создавай OpenSpec change для обычной разработки.
|
||||
As-built факты и принятие решений — через [docs index](../docs/README.md).
|
||||
Этот индекс и основные specs читаются без соседних checkout. Внешние
|
||||
сведения о реализации служат справочными свидетельствами, когда предоставлены.
|
||||
При конфликте с текущим поведением установи расхождение; не копируй устаревшее
|
||||
правило или случайный код молча.
|
||||
|
||||
HTTP OpenAPI имеет единственный editable source в backend, а не здесь.
|
||||
Frontend доверяет предоставленному snapshot и локально проверяет generated
|
||||
types: [Источник HTTP-контракта](../docs/architecture/http-api.md#источник-контракта).
|
||||
Потребитель доверяет предоставленному artifact и локально проверяет generated
|
||||
types. CI каждого участника использует только его собственные входы.
|
||||
|
||||
| Тема / trigger | Existing spec |
|
||||
| --- | --- |
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# Changelog
|
||||
|
||||
## [0.1.1](https://git.personal.ksv741.ru/WealthLedger/specs/compare/v0.1.0...v0.1.1) (2026-09-16)
|
||||
|
||||
### Documentation
|
||||
|
||||
* make specs instructions self-contained ([e4f10de](https://git.personal.ksv741.ru/WealthLedger/specs/commit/e4f10dedefde06d5c710ea36ab99b199cf2c1f7f))
|
||||
|
||||
### Specifications
|
||||
|
||||
* define containerized application delivery [#10](https://git.personal.ksv741.ru/WealthLedger/specs/issues/10) ([b34f23a](https://git.personal.ksv741.ru/WealthLedger/specs/commit/b34f23a23034195a6ae0ff324c20182e664bb26d))
|
||||
|
||||
## 0.1.0 (2026-09-14)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -20,10 +20,42 @@ openspec validate --specs --strict --store wealth-ledger-specs
|
||||
|
||||
Structural validation не заменяет semantic verification и independent read-only review перед archive.
|
||||
|
||||
Node задаётся собственной `.nvmrc`; после `nvm use --silent` выполните `npm ci`.
|
||||
`npm run verify` проверяет diff. OpenSpec validation остаётся отдельной проверкой
|
||||
при изменениях требований. История релизов — [CHANGELOG](CHANGELOG.md).
|
||||
|
||||
## Релизы
|
||||
|
||||
Node задаётся собственной `.nvmrc`; после `nvm use --silent` выполните `npm ci`.
|
||||
`npm run verify` проверяет diff. Release tooling проверяется из root командой
|
||||
`node test-release.cjs specs`. OpenSpec validation остаётся отдельной проверкой
|
||||
при изменениях требований. [Ветки и выпуск](../README.md#релизы-и-ветки),
|
||||
[история релизов](CHANGELOG.md).
|
||||
Репозиторий выпускается независимо. `develop` — интеграция, `main` — принятые
|
||||
релизы. Работа: `codex/<task>` от актуального `develop`, PR в `develop`.
|
||||
Обычные PR допускают squash; release и обратная синхронизация сохраняют историю.
|
||||
Commits и PR titles — Conventional Commits, включая `spec:`. Версии вручную не повышай.
|
||||
|
||||
1. Получи `main`, `develop` и теги: `git fetch origin --tags`. Убедись, что
|
||||
`develop` содержит последний релиз. Создай `release/<name>` от проверенного
|
||||
`develop`; `nvm use --silent`, `npm ci`. Hotfix начинается от `main` в
|
||||
`release/hotfix-<name>` и проходит тот же процесс.
|
||||
2. На чистой ветке выполни `npm run release:preview`, просмотри версию/changelog,
|
||||
затем `npm run release:prepare`. Команда создаёт `chore(release): X.Y.Z`,
|
||||
обновляет manifest/lockfile/CHANGELOG; тег и push не выполняет. Не обходи
|
||||
guards ветки, чистого дерева, отсутствующих тегов или уже подготовленной версии.
|
||||
3. Проверь diff и штатные gates этого репозитория. Отправь только release-ветку,
|
||||
открой PR в `main` с заголовком `chore(release): X.Y.Z`. После зелёных
|
||||
`verify`, `security`, `commits` выполни fast-forward-only merge. Если `main`
|
||||
изменился, согласуй историю и повтори проверки кандидата.
|
||||
4. Получи удалённый `main`, сравни его HEAD с проверенным release SHA и версией
|
||||
manifest/lockfile. Создай аннотированный `vX.Y.Z` именно на этом SHA:
|
||||
`git tag -a vX.Y.Z <release-sha> -m "Release X.Y.Z"`, затем отправь только
|
||||
`git push origin refs/tags/vX.Y.Z`. Не запускай release-it повторно на `main`.
|
||||
5. Верни release-коммит через PR `main → develop` без squash/rebase; проверь,
|
||||
что `develop` содержит тег. Опубликованные теги не перемещай. При сбое после
|
||||
merge создай отсутствующий тег без нового bump; до merge исправь и проверь
|
||||
существующий кандидат без повторного повышения версии.
|
||||
|
||||
`feat:` повышает minor, `fix:`/`perf:` и прочие разрешённые типы — patch;
|
||||
`!`/`BREAKING CHANGE:` — major, включая версии до 1.0. `chore(release):`
|
||||
исключён из рекомендации и changelog. Конфигурация — `.release-it.json`.
|
||||
В Gitea для `main`/`develop` должны быть запрещены прямой/force push и обход
|
||||
администратором, обязательны `verify`, `security`, `commits`; теги `v*` защищены.
|
||||
Workflow сам не включает эти настройки. Отдельное review approval для одного
|
||||
владельца не требуется. Npm publishing, deploy и Gitea Releases не включены.
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: wealth-ledger-sdd
|
||||
created: 2026-09-16
|
||||
@@ -0,0 +1,247 @@
|
||||
## Context
|
||||
|
||||
Frontend и backend выпускаются из независимых Git-репозиториев. Frontend —
|
||||
Vite SPA, backend — NestJS API с embedded SQLite, Prisma migrations, native
|
||||
Node dependencies и runtime `.proto` contracts. Браузерная сессия использует
|
||||
Bearer access token и Secure httpOnly refresh-cookie с path `/api/v1/auth`.
|
||||
|
||||
На production-сервере уже работает Caddy. Он должен знать только домен и один
|
||||
loopback port WealthLedger; TLS и server-wide routing остаются вне приложения.
|
||||
Краткий простой обновляемого компонента допустим. Текущие кэши, rate limiter и
|
||||
connection generation допускают только один активный backend instance.
|
||||
|
||||
Root workspace связывает независимые checkout, но его CI по действующему
|
||||
контракту выполняет только commitlint. Поэтому orchestration принадлежит root,
|
||||
а сборка и публикация каждого image — репозиторию компонента.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- запускать весь application runtime локально через Docker с Linux, общей
|
||||
container network, единым browser origin и быстрым frontend/backend watch;
|
||||
- поставлять отдельные immutable frontend и backend images;
|
||||
- публиковать наружу только frontend port, через который доступны SPA и API;
|
||||
- хранить SQLite и backend secrets вне images и сохранять их при recreation;
|
||||
- применять Prisma migrations до готовности новой версии backend;
|
||||
- обновлять frontend или backend отдельно с явной парой установленных версий;
|
||||
- дать оператору воспроизводимые backup, rollback и restore boundaries.
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- zero-downtime, blue-green, несколько backend replicas и высокая доступность;
|
||||
- PostgreSQL, Kubernetes, container orchestration вне одного сервера;
|
||||
- управление Caddy, DNS, TLS, host firewall или provisioning сервера;
|
||||
- изменение HTTP API, session semantics или пользовательского интерфейса;
|
||||
- общий release номер для независимых репозиториев.
|
||||
|
||||
## Decisions
|
||||
|
||||
Уточнение Change Owner от 2026-09-16: обязательная настройка digests отменена.
|
||||
Production принимает `FRONTEND_IMAGE`/`BACKEND_IMAGE` с release version tags.
|
||||
Публикация сохраняет запрет перезаписи release tags; `latest` не используется.
|
||||
|
||||
### 1. Docker Compose владеет application topology
|
||||
|
||||
Root workspace получает production Compose и development override. Production
|
||||
Compose использует опубликованные image references; development override
|
||||
заменяет их local development targets, подключает исходники и отдельное local
|
||||
data storage. Новые custom orchestration scripts не создаются: lifecycle
|
||||
выражается штатными Compose commands и документированной последовательностью.
|
||||
|
||||
Production содержит два long-running services:
|
||||
|
||||
- `frontend`: nginx со статической SPA и proxy `/api/` в `backend:3000`;
|
||||
- `backend`: один NestJS process с доступом к persistent SQLite storage.
|
||||
|
||||
Одноразовый migration service использует тот же backend image и data storage,
|
||||
завершается до старта новой версии backend. Наружу публикуется только nginx на
|
||||
настраиваемый loopback host port. Caddy проксирует весь домен на этот port и не
|
||||
маршрутизирует `/api/` отдельно.
|
||||
|
||||
Development сохраняет те же component и network boundaries, но frontend target
|
||||
запускает Vite с proxy `/api/` в `backend:3000`, а backend target запускает Nest
|
||||
watch. Browser видит только frontend port. Source mounts не включают host
|
||||
`node_modules`; Linux dependencies принадлежат images/volumes. Изменение
|
||||
manifest или lockfile требует rebuild соответствующего development image.
|
||||
|
||||
Отдельный nginx gateway в development не добавляется: он создал бы третий
|
||||
постоянный service, но всё равно использовал бы отличающуюся proxy-конфигурацию
|
||||
для Vite HMR. Production image и его nginx routing проверяются отдельным
|
||||
production Compose smoke scenario.
|
||||
|
||||
### 2. Frontend и backend имеют собственные multi-stage images
|
||||
|
||||
Frontend image собирает SPA точной project Node version и переносит только
|
||||
build output и nginx configuration в version-pinned nginx runtime. Production
|
||||
SPA использует same-origin API base. nginx поддерживает SPA history fallback,
|
||||
передаёт `/api/` без переписывания prefix и повторно разрешает Docker DNS имя
|
||||
backend после recreation.
|
||||
|
||||
Backend image собирается под Linux точной project Node version. Runtime содержит
|
||||
compiled application, production dependencies, generated Prisma client,
|
||||
migrations и T-Bank `.proto` contracts по пути, который использует production
|
||||
process. Prisma CLI становится явным runtime tool backend image; test, lint и
|
||||
compiler tooling в runtime не переносится. Process работает не от root и пишет
|
||||
только в выделенный data path.
|
||||
|
||||
Оба images получают OCI metadata с repository revision и version. Base images
|
||||
и package installs закрепляются воспроизводимыми версиями; новая platform или
|
||||
architecture не обещается без отдельной проверки.
|
||||
|
||||
### 3. Gitea Container Registry хранит независимые release images
|
||||
|
||||
Frontend и backend workflows публикуют собственный image после push защищённого
|
||||
release tag `vX.Y.Z`. Publish job повторяет канонический repository gate,
|
||||
проверяет совпадение tag с package version и только затем отправляет semver tags в Gitea Container Registry. `latest` не используется.
|
||||
|
||||
Server deployment фиксирует полные frontend/backend image references с
|
||||
semver tags; оператор выбирает опубликованную версию каждого компонента. CI использует отдельный secret с
|
||||
package write permission, сервер — отдельный credential только для pull. Ни один
|
||||
credential не хранится в repository или image. Возможность встроенного Gitea
|
||||
workflow token публиковать packages не предполагается без проверки фактической
|
||||
server version.
|
||||
|
||||
Root не получает image workflow: каждый repository самостоятельно доказывает и
|
||||
публикует свой artifact, а Compose только фиксирует установленную пару image references.
|
||||
|
||||
### 4. Same-origin routing сохраняет действующую auth boundary
|
||||
|
||||
Production frontend nginx и development Vite направляют исходный `/api/...` в
|
||||
backend без изменения path. Frontend client использует relative API base.
|
||||
Backend получает `FRONTEND_ORIGIN`, равный browser-visible origin; production
|
||||
работает с `NODE_ENV=production`, поэтому refresh-cookie остаётся Secure.
|
||||
|
||||
nginx передаёт host, forwarding headers и request ID context, не журналирует
|
||||
Authorization, Cookie или request body. Backend port доступен только Compose
|
||||
network. Server host публикует frontend на loopback, чтобы Caddy оставался
|
||||
единственным внешним listener.
|
||||
|
||||
### 5. Readiness опирается на существующий runtime contract
|
||||
|
||||
Migration service должен завершиться успешно до запуска backend. Backend
|
||||
healthcheck подтверждает завершённый HTTP-ответ от существующего auth route;
|
||||
статус `401` без cookie является допустимым доказательством готового HTTP/auth
|
||||
boundary. Новый публичный health endpoint не добавляется. Frontend healthcheck
|
||||
получает статический root и зависит от healthy backend при полном старте.
|
||||
|
||||
Compose `--wait` используется как bounded readiness gate. Он не является
|
||||
автоматическим rollback и не обещает отсутствие краткого `502` во время
|
||||
отдельного backend update или недоступность всей точки входа во время frontend
|
||||
recreation.
|
||||
|
||||
### 6. SQLite остаётся single-server storage в явно ограниченной роли
|
||||
|
||||
Production использует один backend process и один persistent host data
|
||||
directory. Это расширяет прежнее локальное решение ADR 001: docs получают новый
|
||||
ADR, который разрешает SQLite только для текущего single-server deployment и
|
||||
фиксирует условия пересмотра — несколько replicas, иной availability target,
|
||||
рост write contention или потребность в отдельном database service.
|
||||
|
||||
Перед migration backend останавливается и создаётся согласованная копия всего
|
||||
data directory. Остановка исключает конкурентные writes и позволяет сохранить
|
||||
database вместе с возможными WAL companion files без нового backup service.
|
||||
Encryption key хранится отдельно от data backup; восстановление требует оба
|
||||
артефакта.
|
||||
|
||||
Local development использует другой named volume/data directory и другие
|
||||
secrets. Production data никогда не монтируется в development environment.
|
||||
|
||||
### 7. Обновления меняют только выбранный service
|
||||
|
||||
Frontend update меняет только frontend image reference, загружает image и
|
||||
recreates frontend без зависимостей. Backend и data остаются запущенными, но
|
||||
единая внешняя точка входа кратко недоступна во время recreation.
|
||||
|
||||
Backend update сначала сохраняет backup при остановленном backend, затем меняет
|
||||
backend image reference. Migration service и backend используют один reference; backend
|
||||
стартует только после успешной migration и становится доступен после healthcheck.
|
||||
Frontend не пересоздаётся. nginx повторно разрешает service DNS после смены
|
||||
backend container address.
|
||||
|
||||
Release compatibility остаётся обязанностью API evolution: новая сторона
|
||||
ставится первой только когда прежняя сторона совместима с ней. Compose-файл
|
||||
фиксирует пару image references, но не вводит второй version negotiation mechanism.
|
||||
|
||||
## UI/UX Applicability and Package
|
||||
|
||||
**Applicability and scope:** `N/A` — change меняет development, packaging и
|
||||
server operations, но не экраны, состояния, interactions или responsive
|
||||
поведение WealthLedger. Новый визуальный пакет не требуется.
|
||||
|
||||
## Delivery Map
|
||||
|
||||
| Area | Status | Architectural outcome or N/A reason |
|
||||
| --- | --- | --- |
|
||||
| frontend | `affected` | Multi-stage development/production image, same-origin client configuration, Vite API proxy, nginx SPA/API routing и image publication workflow. |
|
||||
| backend | `affected` | Multi-stage development/production image, runtime Prisma migration assets, container readiness и image publication workflow. |
|
||||
| specs | `affected` | Новая capability `application-delivery` и утверждаемый SDD package. |
|
||||
| docs | `affected` | Deployment/runbook, обновлённая container topology и ADR ограниченного single-server SQLite deployment. |
|
||||
|
||||
Root workspace дополнительно владеет Compose orchestration и кратким entrypoint
|
||||
README как cross-area coordination; это не переносит component build ownership
|
||||
из frontend/backend и не добавляет root CI помимо commitlint.
|
||||
|
||||
## Solution Assessment
|
||||
|
||||
| Вариант | Fit и зрелость | Security / operations | Ограничения и migration cost | Решение |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Docker Compose + два component images | Нативно покрывает один server, service DNS, healthchecks, volumes и targeted recreation; широко поддерживается | Малый operating surface; registry credentials и host Docker требуют обычной защиты | Краткий простой, один host, нет automatic rollback | Выбран как минимальное полное решение |
|
||||
| Один объединённый application image | Простая установка одного artifact | Один lifecycle и один process boundary проще оператору | Связывает независимые релизы, пересобирает неизменённый component, усложняет watch и нарушает repository ownership | Отклонён |
|
||||
| Kubernetes или Swarm | Зрелая orchestration для replicas и rolling updates | Добавляет control plane, политики и постоянную эксплуатацию | Не нужен одному server и не решает текущие SQLite/multi-instance ограничения | Отклонён до появления HA требований |
|
||||
| Caddy маршрутизирует отдельно frontend и backend | Использует существующий server proxy | Убирает internal gateway layer | Server должен знать внутреннюю topology, появляются два application upstream и deployment перестаёт быть self-contained | Отклонён по выбранной внешней границе |
|
||||
| Отдельный постоянный gateway service внутри Compose | Стабильный port при frontend recreation | Может уменьшить внешний простой frontend update | Третий runtime service и конфигурация без требования zero-downtime | Отклонён; пересмотреть при SLO без краткого простоя |
|
||||
| SQLite на persistent directory | Уже реализован, зрел для single-process embedded workload, не требует database service | Минимальная сеть и credentials; backup требует остановки | Один writer/process topology, нет HA; новая ADR boundary обязательна | Выбран в ограниченной single-server роли |
|
||||
| PostgreSQL service | Зрел для concurrency, replicas и независимого DB lifecycle | Требует отдельные credentials, backup, upgrades и monitoring | Миграция Prisma provider и существующих данных вне scope; текущая нагрузка не требует | Отклонён до появления multi-instance/availability требования |
|
||||
| Собственная packaging/orchestration layer | Может точно повторить частные команды | Создаёт собственный security и maintenance surface | Дублирует Compose, registry и standard image lifecycle | Отклонён |
|
||||
|
||||
Gitea Container Registry и Actions используются как уже доступные mature
|
||||
platform capabilities. Предварительное условие Apply — runner с Docker build/push
|
||||
capability и package permissions; при отсутствии этого условия Design не
|
||||
заменяется самописным registry uploader, а publish task остаётся blocked.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- Frontend recreation кратко отключает и SPA, и API ingress; это принято
|
||||
текущим non-goal zero-downtime.
|
||||
- Backend update может кратко возвращать `502`; healthcheck ограничивает окно,
|
||||
но не устраняет его.
|
||||
- Старые browser tabs могут запрашивать chunks прежнего frontend. nginx задаёт
|
||||
revalidation для HTML и immutable cache для hashed assets, но прежние assets
|
||||
после recreation не сохраняются. Пользователю может потребоваться reload;
|
||||
автоматическое восстановление старых вкладок остаётся вне текущего scope.
|
||||
- SQLite на server расширяет прежний local-only baseline. Новый ADR делает это
|
||||
осознанным ограничением, а не молчаливым изменением production guarantee.
|
||||
- Воспроизводимость version tags зависит от запрета их перезаписи: workflow
|
||||
отклоняет существующий tag. Переназначать опубликованные tags нельзя.
|
||||
- Development работает через Vite, production — через nginx. Production Compose
|
||||
smoke проверяет различающийся web-server boundary до поставки.
|
||||
- Полная runtime image воспроизводимость зависит от base-image availability;
|
||||
digests и сохранённые release images уменьшают, но не устраняют registry risk.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. Утвердить SDD package и новый ADR о границе SQLite на одном сервере.
|
||||
2. Подготовить component images и проверить их отдельно с каноническими gates.
|
||||
3. Добавить root Compose topology и development override; подтвердить watch,
|
||||
same-origin API, отсутствие внешнего backend port и изоляцию local data.
|
||||
4. Добавить release-tag publication в component repositories и получить version tags
|
||||
проверенных images из Gitea Registry.
|
||||
5. На server создать restricted environment/secrets и data directories,
|
||||
сохранить исходную базу и encryption key, затем выполнить первый migration
|
||||
service и production smoke через loopback port.
|
||||
6. Настроить Caddy на единственный loopback port и проверить login, refresh,
|
||||
чтение существующих данных и один внешний financial request.
|
||||
7. Зафиксировать установленную пару image references и удалить прежний runtime
|
||||
только после успешной проверки нового.
|
||||
|
||||
### Rollback Contract
|
||||
|
||||
| Field | Decision |
|
||||
| --- | --- |
|
||||
| Status | `required` |
|
||||
| Reason | Change вводит server persistence, migrations, secrets и новую delivery boundary. |
|
||||
| Trigger | Migration failure, unhealthy component, невозможность login/refresh, нечитаемое encrypted connection, повреждение данных или критическая регрессия smoke scenario. |
|
||||
| Actions | Не направлять Caddy на первый deployment либо вернуть предыдущий component image reference. Старую версию backend запускать только после проверки совместимости с текущей schema. Если schema несовместима, остановить приложение и отдельно предложить восстановление согласованного backup; не выполнять restore автоматически. |
|
||||
| Data safety | Backup создаётся при остановленном backend из всего data directory; encryption key сохраняется отдельно. Данные, созданные после backup, считаются более новыми и не заменяются без явного решения оператора о потере этого интервала. |
|
||||
| Verification | Проверить component health, schema migration status, login/refresh, чтение существующих user/card data, decrypt/use сохранённого T-Bank connection и отсутствие повторной migration ошибки; затем записать фактически установленную пару image references. |
|
||||
@@ -0,0 +1,46 @@
|
||||
## Why
|
||||
|
||||
WealthLedger сейчас запускается как набор локальных процессов, а поставка на
|
||||
сервер не определена. Разработка не воспроизводит границы runtime-среды, а
|
||||
оператор не имеет согласованного способа установить, обновить, сохранить или
|
||||
восстановить приложение.
|
||||
|
||||
Нужен единый поддерживаемый путь запуска для локальной разработки и одного
|
||||
сервера, чтобы поставка каждой версии была воспроизводимой и не требовала
|
||||
ручного пересоздания окружения.
|
||||
|
||||
## What Changes
|
||||
|
||||
Будет определён поддерживаемый способ запускать WealthLedger локально и на
|
||||
одном сервере. Внешняя серверная маршрутизация передаёт весь трафик
|
||||
приложения на одну точку входа WealthLedger; приложение само обслуживает
|
||||
интерфейс и API.
|
||||
|
||||
Оператор сможет независимо обновлять интерфейс или API согласованными
|
||||
версиями поставки. Пользовательские данные, сессии и секреты сохраняются
|
||||
между штатными перезапусками и обновлениями. Для обновления и восстановления
|
||||
будут определены необходимые безопасные действия и их границы.
|
||||
|
||||
Не входят непрерывное обновление без краткого простоя, несколько экземпляров
|
||||
API, высокая доступность, смена хранилища данных, изменение внешнего reverse
|
||||
proxy и управление серверной инфраструктурой вне WealthLedger.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `application-delivery`: поддерживаемый локальный и серверный запуск,
|
||||
обновление компонентов и сохранность состояния WealthLedger.
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
Нет.
|
||||
|
||||
## Impact
|
||||
|
||||
Пользователь получает одинаково работающую среду разработки и поставленное
|
||||
приложение. Оператор получает воспроизводимую установку, независимое
|
||||
обновление частей приложения и понятные границы восстановления данных.
|
||||
Изменение затронет frontend, backend, specs, docs и общую orchestration
|
||||
workspace; детали решений и delivery будут определены в последующих
|
||||
утверждаемых артефактах.
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
## Purpose
|
||||
|
||||
Определяет поддерживаемые эксплуатационные свойства локального и серверного
|
||||
запуска WealthLedger, включая поставку компонентов и сохранность состояния.
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Локальная среда воспроизводит границы поставленного приложения
|
||||
|
||||
Поддерживаемый локальный запуск SHALL предоставлять один browser origin для
|
||||
интерфейса и API WealthLedger. Разработка интерфейса MUST сохранять быстрый
|
||||
цикл обратной связи при изменении исходного кода, а разработка API MUST
|
||||
перезапускать затронутый runtime без ручной пересборки всей среды. Локальные
|
||||
данные MUST быть изолированы от server data.
|
||||
|
||||
#### Scenario: Разработчик открывает локальное приложение
|
||||
|
||||
- **WHEN** поддерживаемая локальная среда успешно запущена
|
||||
- **THEN** браузер получает интерфейс и обращается к API через тот же origin,
|
||||
не зная внутреннего адреса API
|
||||
|
||||
#### Scenario: Разработчик меняет интерфейс
|
||||
|
||||
- **WHEN** разработчик изменяет исходный код интерфейса в запущенной локальной
|
||||
среде
|
||||
- **THEN** браузер получает изменение без ручной полной пересборки среды
|
||||
|
||||
### Requirement: Серверное приложение имеет одну внешнюю точку входа
|
||||
|
||||
Поддерживаемый server deployment SHALL принимать HTTP-трафик WealthLedger на
|
||||
одной внешней точке входа. Через неё MUST быть доступны интерфейс и API с
|
||||
сохранением их действующих путей и session semantics. API и хранилище данных
|
||||
MUST NOT требовать отдельного внешнего сетевого доступа.
|
||||
|
||||
#### Scenario: Внешний reverse proxy направляет запрос приложению
|
||||
|
||||
- **WHEN** server reverse proxy передаёт запрос на единственную точку входа
|
||||
WealthLedger
|
||||
- **THEN** пользователь получает интерфейс, а запросы к действующему API
|
||||
обрабатываются приложением без отдельного маршрута reverse proxy к API
|
||||
|
||||
### Requirement: Поставка допускает независимое обновление компонентов
|
||||
|
||||
Система SHALL предоставлять versioned delivery artifacts для интерфейса и API
|
||||
как независимых компонентов. Оператор MUST иметь возможность установить
|
||||
выбранную версию только одного компонента, сохранив другой компонент и
|
||||
постоянное пользовательское состояние работающими. Поддерживаемая поставка
|
||||
MUST явно фиксировать выбранные версии обоих компонентов.
|
||||
|
||||
#### Scenario: Обновляется только интерфейс
|
||||
|
||||
- **WHEN** оператор устанавливает новую версию интерфейса при неизменной
|
||||
совместимой версии API
|
||||
- **THEN** API и его постоянное состояние не пересоздаются, а приложение
|
||||
начинает отдавать новую версию интерфейса
|
||||
|
||||
#### Scenario: Обновляется только API
|
||||
|
||||
- **WHEN** оператор устанавливает новую версию API при неизменной совместимой
|
||||
версии интерфейса
|
||||
- **THEN** интерфейс не пересоздаётся, а приложение начинает обрабатывать
|
||||
запросы новой версией API после её готовности
|
||||
|
||||
### Requirement: Постоянное состояние и секреты переживают штатный lifecycle
|
||||
|
||||
Пользовательские данные, session state и ключи, необходимые для чтения
|
||||
зашифрованных подключений, MUST сохраняться при штатных перезапусках и
|
||||
обновлениях компонентов. Секреты MUST задаваться отдельно от versioned delivery
|
||||
artifacts и MUST NOT попадать в интерфейс, журналы или публичный HTTP-ответ.
|
||||
|
||||
#### Scenario: Приложение штатно перезапускается
|
||||
|
||||
- **WHEN** оператор штатно перезапускает приложение без восстановления данных
|
||||
- **THEN** после запуска доступны прежние пользовательские данные и действующие
|
||||
session semantics, а сохранённые зашифрованные подключения остаются читаемыми
|
||||
тем же ключом
|
||||
|
||||
### Requirement: Обновление API сохраняет целостность данных
|
||||
|
||||
Перед тем как новая версия API начинает принимать запросы, необходимые
|
||||
изменения схемы постоянных данных MUST быть применены успешно. При ошибке
|
||||
изменения данных новая версия API MUST NOT объявляться готовой. Краткий простой
|
||||
обновляемого компонента допустим; непрерывность обслуживания и несколько
|
||||
одновременных экземпляров API не являются обещанием этой capability.
|
||||
|
||||
#### Scenario: Подготовка данных новой версии не прошла
|
||||
|
||||
- **WHEN** обязательное изменение постоянных данных завершается ошибкой
|
||||
- **THEN** новая версия API не начинает обслуживать запросы, а оператор получает
|
||||
диагностируемый неуспешный результат обновления
|
||||
|
||||
### Requirement: Восстановление не выдаёт откат приложения за откат данных
|
||||
|
||||
Поддерживаемая процедура обновления и восстановления MUST различать возврат
|
||||
версии компонентов и восстановление пользовательских данных. Она MUST требовать
|
||||
согласованную резервную копию перед изменением постоянных данных и MUST NOT
|
||||
заменять более новые пользовательские данные прежней копией как побочный эффект
|
||||
возврата версии приложения.
|
||||
|
||||
#### Scenario: Оператор возвращает предыдущую версию API
|
||||
|
||||
- **WHEN** оператор возвращает прежнюю версию API после неуспешного обновления
|
||||
- **THEN** процедура явно проверяет совместимость этой версии с текущими
|
||||
данными и не выполняет восстановление старой копии данных без отдельного
|
||||
решения оператора
|
||||
@@ -0,0 +1,219 @@
|
||||
# Контейнерная разработка и поставка 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.
|
||||
@@ -2,8 +2,8 @@ schema: wealth-ledger-sdd
|
||||
|
||||
context: |
|
||||
WealthLedger состоит из независимых frontend, backend, specs и docs Git-репозиториев.
|
||||
Canonical OpenSpec authority — зарегистрированный store wealth-ledger-specs в specs/openspec.
|
||||
Docs описывает только фактическое as-built состояние; устойчивые process policies находятся в docs/development.
|
||||
Локальная разработка и verification выполняются под Node 24 без CI.
|
||||
Canonical OpenSpec authority — store wealth-ledger-specs в локальном openspec/.
|
||||
Инструкции и validation specs находятся в этом репозитории; соседние checkout не требуются.
|
||||
Локальная разработка и CI используют Node из собственной .nvmrc; порядок работы задаёт AGENTS.md.
|
||||
Project artifacts объясняют решения по-русски; exact OpenSpec headings, tokens,
|
||||
commands и normative keywords SHALL/MUST сохраняются на английском.
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "wealth-ledger-specs",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "wealth-ledger-specs",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "21.2.2",
|
||||
"@commitlint/config-conventional": "21.2.2",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wealth-ledger-specs",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": "24.21.0"
|
||||
|
||||
Reference in New Issue
Block a user