Kansho/docs/DEPLOYMENT.md
Lars af6fe55577
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Test Suite / pytest-backend (push) Successful in 2m35s
Test Suite / smoke-dev (push) Successful in 1s
Test Suite / frontend-build (push) Successful in 15s
Allow remote detect in production until local Ollama is connected.
Keep KANSHO_ENV=production and require an explicit operator flag instead of treating Prod as Development. Promote to Prod only via merge commit on main.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-08 10:02:28 +02:00

5.2 KiB
Raw Blame History

Deployment Kanshō

Stand: 2026-09-07
Server: Raspberry Pi 5 (192.168.2.49) — gleicher Host wie Mitai/Shinkan/Kairo, eigene Compose-Projekte
Runner: Gitea Actions (/home/lars/gitea-runner/)
Repo: http://192.168.2.144:3000/Lars/Kansho.git

Kanonische Runtime-Entscheidungen: docs/architecture/technical/runtime_and_deploy.md.
Datenübernahme SQLite → Postgres: backend/sqlite_to_postgres.py (Probe auf Kopie, --confirm).


Port- und Pfad-Übersicht

Production Development
Git-Branch main develop
Server-Verzeichnis /home/lars/docker/kansho /home/lars/docker/kansho-dev
Frontend-Port 3006 3096
Backend-Port 8005 8096
PostgreSQL nur Compose-Netz, DB kansho nur Compose-Netz, DB kansho_dev
Domain kansho.jinkendo.de dev.kansho.jinkendo.de
Öffentliche URL https://kansho.jinkendo.de https://dev.kansho.jinkendo.de
Compose docker-compose.yml docker-compose.dev-env.yml

Prod-Frontend ist 3006, nicht 3005: auf dem Pi lauscht Bookstack bereits auf 0.0.0.0:3005. Dev 3096/8096 und Prod-API 8005 waren frei.

Lokal ohne Docker bleibt Windows: Frontend 5188, Backend 8018, SQLite unter backend/data/.


Einmalige Server-Einrichtung

mkdir -p /home/lars/docker/kansho /home/lars/docker/kansho-dev

cd /home/lars/docker/kansho-dev
git clone http://192.168.2.144:3000/Lars/Kansho.git .
git checkout develop
cp .env.example .env
# DB_PASSWORD und Provider-Keys setzen

cd /home/lars/docker/kansho
git clone http://192.168.2.144:3000/Lars/Kansho.git .
git checkout main
cp .env.example .env
# Prod-DB_PASSWORD und Provider-Keys setzen

Host-nginx: nginx/kansho.conf und nginx/kansho-dev.conf nach /etc/nginx/sites-available/, dann nginx/certbot-setup.sh. DNS A/AAAA für dev.kansho.jinkendo.de und kansho.jinkendo.de auf den Reverse-Proxy. Bis TLS steht, bleibt der LAN-Zugriff über die Publish-Ports.

Gitea: Actions aktivieren. Derselbe Pi-Runner wie die Schwesterprodukte (ubuntu-latest).

Watchtower bleibt aus.


Gitea Actions

Workflow Trigger Zweck
deploy-dev.yml Push develop Deploy nach /home/lars/docker/kansho-dev, Health localhost:8096
deploy-prod.yml Push main Deploy nach /home/lars/docker/kansho, Health localhost:8005
test.yml nach erfolgreichem Deploy Development pytest auf kansho_test, nicht-schreibender Smoke gegen die laufende Dev-API, Frontend-Build. Keine Live-Provider-Keys.

Prod nur über Merge-Commit developmain (git merge --no-ff develop auf main), danach Push von main. Kein Fast-Forward, kein direkter Commit auf main, kein manuelles git pull auf dem Prod-Checkout. Gitea (deploy-prod.yml) ist der einzige Prod-Schreibpfad für Code.


Datenübernahme (persönlich, Klasse A/B)

  1. Phase-A-SQLite auf dem Heimrechner ist führend, bis der Dev-Import grün ist.
  2. Schema auf der Zielinstanz durch normalen Container-Start anlegen (leeres Postgres).
  3. Import auf Dev zuerst:
# Zip oder laufende SQLite + Medien in den Dev-Container legen, dann:
docker compose -f docker-compose.dev-env.yml exec -T backend \
  python sqlite_to_postgres.py --confirm \
  --sqlite /tmp/kansho.sqlite \
  --media-src /tmp/media \
  --media-dest /app/data/media

Windows-Vorbereitung (Kopie, nicht das einzige Backup):

.\scripts\backup-local.ps1 create
# Archiv prüfen, dann SQLite+Medien auf den Pi kopieren — nicht nach Gitea.
  1. Abnahme Dev: Profilanzahl, Journal-Days/Entries, Messages, ein Medien-GET, Gateway fail-closed. Production ohne KANSHO_ALLOW_REMOTE_DETECT blockiert Klartext-Detect; der Operator-Übergang bis Ollama ist explizit und dokumentiert (guardrails.md §22.3).
  2. Erst dann derselbe Import nach Prod (--confirm, leeres Volume). --replace nur auf einer bewussten Kopie.

debug.persist_traces nach dem Import prüfen.


Postgres-Backup (Server)

Kein Ersatz durch backup-local.ps1 (das bleibt der SQLite-Weg).

# Dump
cd /home/lars/docker/kansho
docker compose exec -T postgres pg_dump -U kansho kansho > "/home/lars/backups/kansho-$(date -u +%Y%m%d).sql"

# Medienvolume
docker run --rm -v kansho_kansho-media:/src -v /home/lars/backups:/dst alpine \
  tar -C /src -czf /dst/kansho-media-$(date -u +%Y%m%d).tgz .

Restore-Übung vor dem ersten Prod-Dialogbestand nach dem Cutover wiederholen. Dump und Medien nicht an Provider und nicht in öffentliche Remotes.


Manuelles Deploy

# Development
cd /home/lars/docker/kansho-dev
git fetch origin develop && git reset --hard origin/develop
docker compose -f docker-compose.dev-env.yml build --no-cache backend frontend
docker compose -f docker-compose.dev-env.yml up -d --wait
curl -sf http://localhost:8096/api/health

# Production
cd /home/lars/docker/kansho
git fetch origin main && git reset --hard origin/main
docker compose build --no-cache backend frontend
docker compose up -d --wait
curl -sf http://localhost:8005/api/health

Laptop-Checkout nach erfolgreichem Heim-Restore und Dev-Import nur noch Archiv. Keine parallelen Schreibzugriffe auf denselben persönlichen Bestand.