feat: add containerized application delivery #11 #12

Merged
ksv741 merged 1 commits from codex/containerized-deployment into develop 2026-09-16 10:23:15 +03:00
6 changed files with 160 additions and 1 deletions
+12
View File
@@ -0,0 +1,12 @@
# Copy to a restricted, untracked file. Never commit filled values.
# Full release image references; use published version tags, not latest.
FRONTEND_IMAGE=git.personal.ksv741.ru/wealthledger/frontend:0.1.0
BACKEND_IMAGE=git.personal.ksv741.ru/wealthledger/backend:0.1.0
FRONTEND_PORT=8080
FRONTEND_ORIGIN=https://wealthledger.example.com
# Absolute directory, pre-created with owner UID/GID 1000:1000 and mode 0700.
DATA_DIRECTORY=/srv/wealthledger/data
# Generate once and keep across updates. Store an independent key backup.
JWT_SECRET=
TOKEN_ENCRYPTION_KEY=
LOG_LEVEL=info
+10
View File
@@ -0,0 +1,10 @@
# Local-only fixture values. Never use this file for a server deployment.
# Base-file interpolation happens before overrides; these references are replaced.
FRONTEND_IMAGE=wealthledger-frontend:development
BACKEND_IMAGE=wealthledger-backend:development
DATA_DIRECTORY=/unused-development-volume
FRONTEND_PORT=5173
FRONTEND_ORIGIN=http://localhost:5173
JWT_SECRET=local-development-only-not-a-server-secret
TOKEN_ENCRYPTION_KEY=MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY=
LOG_LEVEL=info
+4
View File
@@ -3,6 +3,10 @@
!/.gitignore !/.gitignore
!/AGENTS.md !/AGENTS.md
!/README.md !/README.md
!/compose.yaml
!/compose.development.yaml
!/.env.compose.example
!/.env.development.example
!/.ai/ !/.ai/
/.ai/* /.ai/*
!/.ai/conventions/ !/.ai/conventions/
+30 -1
View File
@@ -41,7 +41,7 @@ git clone ssh://git@git.personal.ksv741.ru:2222/WealthLedger/specs.git specs
Root отслеживает входные документы, собственные engineering conventions и исторический migration Root отслеживает входные документы, собственные engineering conventions и исторический migration
inventory в `.ai/`, npm/release-конфигурацию, changelog, inventory в `.ai/`, npm/release-конфигурацию, changelog,
один CI workflow с commitlint. Точный allowlist — в `.gitignore`. Compose configuration, безопасные env examples и один CI workflow с commitlint. Точный allowlist — в `.gitignore`.
Остальные root-пути игнорируются по умолчанию: Остальные root-пути игнорируются по умолчанию:
вложенные repos, `.env`, базы и WAL, импорты выписок, PDF, `references/`, вложенные repos, `.env`, базы и WAL, импорты выписок, PDF, `references/`,
`design/`, `todo/` и локальные настройки инструментов. `design/`, `todo/` и локальные настройки инструментов.
@@ -53,6 +53,35 @@ inventory в `.ai/`, npm/release-конфигурацию, changelog,
Не запускайте очистку workspace через `git clean -fdx`: ignored-пути содержат Не запускайте очистку workspace через `git clean -fdx`: ignored-пути содержат
локальные данные. Правила tracking не удаляют файлы и вложенные `.git`. локальные данные. Правила tracking не удаляют файлы и вложенные `.git`.
## Запуск через Docker Compose
Нужны Docker Engine и Compose >= 2.24.4, а для development — checkout
`frontend/` и `backend/` рядом с root. Компоненты собираются независимо:
```bash
docker compose --env-file .env.development.example \
-f compose.yaml -f compose.development.yaml up -d --build --wait --wait-timeout 180
```
Откройте `http://localhost:5173`: Vite HMR и `/api/` используют один origin,
Nest работает в watch mode. Host `node_modules` и `.env` не монтируются.
Данные development хранятся отдельно в named volume `development-data` проекта `wealthledger-dev`;
обычные restart/down их сохраняют. Изменение dependencies/config требует rebuild.
Production использует `compose.yaml` и restricted env по `.env.compose.example`:
две ссылки на опубликованные версии images, persistent absolute host data path,
постоянные JWT/encryption secrets и публичный HTTPS origin. Каталог данных
должен существовать и принадлежать UID/GID 1000:1000. Только frontend публикует
`127.0.0.1:8080`; серверный Caddy направляет туда весь домен. Backend port
остаётся внутренним, migration service использует тот же backend image.
Полная процедура установки, независимых обновлений, stopped-backend backup
и explicit restore — [документация](https://git.personal.ksv741.ru/WealthLedger/docs),
страница `architecture/deployment.md`.
Перед backend update обязательны остановка, backup и успешная migration.
Image rollback не восстанавливает старую базу. Публикация component images
принадлежит их Gitea workflows; root CI остаётся только commitlint.
## Подготовка и запуск ## Подготовка и запуск
Нужны nvm и Node из `.nvmrc` каждого npm-repo (сейчас 24.21.0, npm 11.19). Нужны nvm и Node из `.nvmrc` каждого npm-repo (сейчас 24.21.0, npm 11.19).
+53
View File
@@ -0,0 +1,53 @@
# Requires Compose >= 2.24.4 for !override. Always use a separate project name.
name: wealthledger-dev
x-development-backend: &development-backend
image: wealthledger-backend:development
pull_policy: build
build:
context: ./backend
target: development
read_only: false
environment:
NODE_ENV: development
volumes: !override
- development-data:/data
services:
migration:
<<: *development-backend
backend:
<<: *development-backend
healthcheck:
test: [CMD, node, -e, 'fetch("http://127.0.0.1:3000/api/v1/auth/me").then(async r=>{await r.arrayBuffer();process.exit(r.status===401?0:1)}).catch(()=>process.exit(1))']
interval: 10s
timeout: 3s
start_period: 20s
retries: 6
volumes: !override
- development-data:/data
- ./backend/src:/app/src:ro
frontend:
image: wealthledger-frontend:development
pull_policy: build
build:
context: ./frontend
target: development
read_only: false
volumes:
- ./frontend/src:/app/src:ro
- ./frontend/public:/app/public:ro
environment:
VITE_API_BASE_URL: ''
API_PROXY_TARGET: http://backend:3000
healthcheck:
test: [CMD, node, -e, 'fetch("http://127.0.0.1:8080/").then(async r=>{await r.arrayBuffer();process.exit(r.ok?0:1)}).catch(()=>process.exit(1))']
interval: 10s
timeout: 3s
start_period: 10s
retries: 6
volumes:
development-data:
+51
View File
@@ -0,0 +1,51 @@
name: wealthledger
x-backend: &backend
image: ${BACKEND_IMAGE:?Set versioned backend image}
environment:
NODE_ENV: production
PORT: '3000'
DATABASE_URL: file:/data/wealthledger.db
FRONTEND_ORIGIN: ${FRONTEND_ORIGIN:?Set browser-visible origin}
JWT_SECRET: ${JWT_SECRET:?Set persistent JWT secret}
TOKEN_ENCRYPTION_KEY: ${TOKEN_ENCRYPTION_KEY:?Set persistent encryption key}
LOG_LEVEL: ${LOG_LEVEL:-info}
volumes:
- type: bind
source: ${DATA_DIRECTORY:?Set persistent absolute host data directory}
target: /data
bind:
create_host_path: false
read_only: true
init: true
security_opt: [no-new-privileges:true]
cap_drop: [ALL]
services:
migration:
<<: *backend
command: [node, node_modules/prisma/build/index.js, migrate, deploy]
restart: 'no'
healthcheck:
disable: true
backend:
<<: *backend
scale: 1
restart: unless-stopped
depends_on:
migration:
condition: service_completed_successfully
frontend:
image: ${FRONTEND_IMAGE:?Set versioned frontend image}
ports:
- '127.0.0.1:${FRONTEND_PORT:-8080}:8080'
read_only: true
tmpfs: [/tmp]
security_opt: [no-new-privileges:true]
cap_drop: [ALL]
restart: unless-stopped
depends_on:
backend:
condition: service_healthy