From e364e434804a33a44fbd56e8d8a04798bf4d849d Mon Sep 17 00:00:00 2001 From: rene Date: Sun, 12 Apr 2026 16:43:16 +0200 Subject: [PATCH] Deploy-Skripte: Makefile, setup-ds.sh, new-feature.sh --- Makefile | 147 +++++++++++++++++++++++++++++++++++++++++ scripts/new-feature.sh | 136 ++++++++++++++++++++++++++++++++++++++ scripts/setup-ds.sh | 87 ++++++++++++++++++++++++ 3 files changed, 370 insertions(+) create mode 100644 Makefile create mode 100755 scripts/new-feature.sh create mode 100755 scripts/setup-ds.sh diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..68bc09a --- /dev/null +++ b/Makefile @@ -0,0 +1,147 @@ +# ============================================================== +# BAN YARO — Makefile +# Alle häufigen Operationen mit kurzen Befehlen. +# Verwendung: make +# ============================================================== + +# Konfiguration +DS_HOST := ds +DS_PATH := /volume1/docker/ban-yaro +CONTAINER := ban-yaro +GIT_REMOTE := origin + +.PHONY: help deploy push pull logs logs-f shell db restart stop status build \ + clean-cache dev lint + +# ---------------------------------------------------------- +# Standard: Hilfe anzeigen +# ---------------------------------------------------------- +help: + @echo "" + @echo " Ban Yaro — verfügbare Befehle:" + @echo "" + @echo " make deploy Push zu Git + Rebuild auf DS (häufigster Befehl)" + @echo " make push Nur Git push (ohne DS-Deploy)" + @echo " make pull Nur auf DS pullen + neustarten (ohne Git push)" + @echo " make restart Container neustarten (ohne Rebuild)" + @echo " make build Nur Docker-Image neu bauen (ohne Start)" + @echo " make stop Container stoppen" + @echo " make status Container-Status auf DS anzeigen" + @echo "" + @echo " make logs Letzte 100 Log-Zeilen" + @echo " make logs-f Log-Stream (live)" + @echo " make shell Bash-Shell im Container" + @echo " make db SQLite-Shell auf DS" + @echo "" + @echo " make dev Lokaler Entwicklungsserver (ohne Docker)" + @echo " make clean-cache Service Worker + Browser-Cache leeren (Push)" + @echo "" + +# ---------------------------------------------------------- +# DEPLOY: Git push → DS pull → Rebuild → Neustart +# Das ist der Befehl den du am meisten nutzen wirst. +# ---------------------------------------------------------- +deploy: + @echo "→ Git push..." + @git push $(GIT_REMOTE) main + @echo "→ DS: pull + rebuild + restart..." + @ssh $(DS_HOST) "cd $(DS_PATH) && \ + git pull && \ + sudo docker compose down && \ + sudo docker compose build --no-cache && \ + sudo docker compose up -d && \ + echo '✓ Deploy fertig.' && \ + sudo docker compose logs --tail=20" + +# ---------------------------------------------------------- +# NUR Git push (z.B. um nur Code zu sichern) +# ---------------------------------------------------------- +push: + git push $(GIT_REMOTE) main + +# ---------------------------------------------------------- +# NUR auf DS deployen (ohne neuen Git push) +# z.B. wenn jemand anderes gepusht hat +# ---------------------------------------------------------- +pull: + @ssh $(DS_HOST) "cd $(DS_PATH) && \ + git pull && \ + sudo docker compose down && \ + sudo docker compose up -d --build && \ + echo '✓ Pull + Restart fertig.'" + +# ---------------------------------------------------------- +# Nur neustarten (kein Rebuild, kein Git) +# z.B. nach .env-Änderung +# ---------------------------------------------------------- +restart: + @ssh $(DS_HOST) "cd $(DS_PATH) && \ + sudo docker compose restart $(CONTAINER) && \ + echo '✓ Container neugestartet.'" + +# ---------------------------------------------------------- +# Nur bauen (kein Start) +# ---------------------------------------------------------- +build: + @ssh $(DS_HOST) "cd $(DS_PATH) && \ + sudo docker compose build --no-cache" + +# ---------------------------------------------------------- +# Stoppen +# ---------------------------------------------------------- +stop: + @ssh $(DS_HOST) "cd $(DS_PATH) && sudo docker compose down" + +# ---------------------------------------------------------- +# Status +# ---------------------------------------------------------- +status: + @ssh $(DS_HOST) "sudo docker ps --filter name=$(CONTAINER) --format \ + 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'" + +# ---------------------------------------------------------- +# LOGS +# ---------------------------------------------------------- +logs: + @ssh $(DS_HOST) "sudo docker logs $(CONTAINER) --tail=100" + +logs-f: + @ssh $(DS_HOST) "sudo docker logs $(CONTAINER) -f" + +# ---------------------------------------------------------- +# SHELL im Container +# ---------------------------------------------------------- +shell: + @ssh -t $(DS_HOST) "sudo docker exec -it $(CONTAINER) bash" + +# ---------------------------------------------------------- +# SQLite direkt öffnen +# ---------------------------------------------------------- +db: + @ssh -t $(DS_HOST) "sudo docker exec -it $(CONTAINER) \ + sqlite3 /data/banyaro.db" + +# ---------------------------------------------------------- +# Lokale Entwicklung (ohne Docker, direkt auf Mac) +# Voraussetzung: Python-Venv in backend/venv/ +# ---------------------------------------------------------- +dev: + @cd backend && \ + test -d venv || python3 -m venv venv && \ + . venv/bin/activate && \ + pip install -q -r requirements.txt && \ + KI_MODE=off ENV=development \ + JWT_SECRET=dev-secret \ + DB_PATH=./dev.db \ + uvicorn main:app --reload --port 8001 + +# ---------------------------------------------------------- +# Service-Worker-Cache auf DS forciert leeren +# (nach größeren CSS/JS-Änderungen sinnvoll) +# ---------------------------------------------------------- +clean-cache: + @ssh $(DS_HOST) "cd $(DS_PATH) && \ + sudo docker exec $(CONTAINER) \ + sed -i 's/by-v[0-9]*/by-v'$$(date +%s)'/g' /app/static/sw.js && \ + echo '✓ Cache-Version aktualisiert.'" + @$(MAKE) restart diff --git a/scripts/new-feature.sh b/scripts/new-feature.sh new file mode 100755 index 0000000..5f4b6c5 --- /dev/null +++ b/scripts/new-feature.sh @@ -0,0 +1,136 @@ +#!/bin/bash +# ============================================================== +# BAN YARO — Neues Feature anlegen +# Erstellt alle nötigen Dateien für eine neue Seite/Feature. +# Verwendung: bash scripts/new-feature.sh +# Beispiel: bash scripts/new-feature.sh poison +# ============================================================== + +set -e + +FEATURE="$1" + +if [ -z "$FEATURE" ]; then + echo "Verwendung: bash scripts/new-feature.sh " + echo "Beispiel: bash scripts/new-feature.sh poison" + exit 1 +fi + +# Snake_case für JS-Modul-Name (bindestriche → unterstriche) +JS_NAME=$(echo "$FEATURE" | tr '-' '_') +# Titel (erstes Buchstabe groß) +TITLE=$(echo "$FEATURE" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) substr($i,2); print}') + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" + +echo "=== Neues Feature: $FEATURE ===" + +# ---------------------------------------------------------- +# 1. Frontend: JS-Seiten-Modul +# ---------------------------------------------------------- +JS_FILE="$ROOT/backend/static/js/pages/${FEATURE}.js" +if [ -f "$JS_FILE" ]; then + echo " ⚠️ $JS_FILE existiert bereits, übersprungen." +else + cat > "$JS_FILE" << EOF +/* ============================================================ + BAN YARO — ${TITLE} + Seiten-Modul. Wird von App.js lazy geladen. + ============================================================ */ + +window.Page_${JS_NAME} = (() => { + + let _container = null; + let _state = null; + + // ---------------------------------------------------------- + async function init(container, appState) { + _container = container; + _state = appState; + await render(); + } + + // ---------------------------------------------------------- + async function render() { + _container.innerHTML = UI.skeleton(3); + try { + // TODO: Daten laden + // const data = await API.${JS_NAME}.list(...); + _container.innerHTML = \` +
+

${TITLE}

+

Noch in Entwicklung.

+
+ \`; + } catch (err) { + _container.innerHTML = UI.emptyState({ + icon: '⚠️', + title: 'Fehler beim Laden', + text: err.message, + }); + } + } + + // Vom + Button aufgerufen + function openNew() { + // TODO: Neuer Eintrag Modal + } + + // Wenn User Hund wechselt + function onDogChange(dog) { + if (_container) render(); + } + + // Bei erneutem Seitenaufruf + function refresh() { + if (_container) render(); + } + + return { init, refresh, openNew, onDogChange }; + +})(); +EOF + echo " ✓ Frontend: backend/static/js/pages/${FEATURE}.js" +fi + +# ---------------------------------------------------------- +# 2. Backend: Route +# ---------------------------------------------------------- +ROUTE_FILE="$ROOT/backend/routes/${FEATURE}.py" +if [ -f "$ROUTE_FILE" ]; then + echo " ⚠️ $ROUTE_FILE existiert bereits, übersprungen." +else + cat > "$ROUTE_FILE" << EOF +"""BAN YARO — ${TITLE} Routes""" + +from fastapi import APIRouter, Depends, HTTPException +from pydantic import BaseModel +from typing import Optional +from database import db +from auth import get_current_user + +router = APIRouter() + + +# TODO: Pydantic-Modelle definieren +# class ${TITLE}Create(BaseModel): +# ... + + +# TODO: Endpoints implementieren +# @router.get("") +# async def list_${JS_NAME}(user=Depends(get_current_user)): +# ... +EOF + echo " ✓ Backend: backend/routes/${FEATURE}.py" +fi + +# ---------------------------------------------------------- +# 3. Hinweis: Router in main.py registrieren +# ---------------------------------------------------------- +echo "" +echo " Noch manuell in backend/main.py eintragen:" +echo " from routes.${FEATURE} import router as ${JS_NAME}_router" +echo " app.include_router(${JS_NAME}_router, prefix='/api/${FEATURE}', tags=['${TITLE}'])" +echo "" +echo "=== Fertig. Viel Spaß beim Bauen! ===" diff --git a/scripts/setup-ds.sh b/scripts/setup-ds.sh new file mode 100755 index 0000000..6dc6600 --- /dev/null +++ b/scripts/setup-ds.sh @@ -0,0 +1,87 @@ +#!/bin/bash +# ============================================================== +# BAN YARO — Ersteinrichtung auf der DiskStation +# Einmalig ausführen: bash scripts/setup-ds.sh +# ============================================================== + +set -e + +DS_HOST="ds" +DS_PATH="/volume1/docker/ban-yaro" +REPO_URL="ssh://git@dsm.motocamp.de:2222/rene/banyaro.git" + +echo "=== Ban Yaro Setup auf DS1621 ===" +echo "" + +# ---------------------------------------------------------- +# 1. Verzeichnis anlegen und Repo klonen +# ---------------------------------------------------------- +echo "→ Repo klonen..." +ssh "$DS_HOST" " + mkdir -p $(dirname $DS_PATH) && + if [ -d '$DS_PATH' ]; then + echo ' Verzeichnis existiert bereits, pull statt clone.' + cd '$DS_PATH' && git pull + else + git clone '$REPO_URL' '$DS_PATH' + echo ' Geklont nach $DS_PATH' + fi +" + +# ---------------------------------------------------------- +# 2. .env anlegen falls nicht vorhanden +# ---------------------------------------------------------- +echo "→ .env prüfen..." +ssh "$DS_HOST" " + if [ ! -f '$DS_PATH/.env' ]; then + cp '$DS_PATH/.env.example' '$DS_PATH/.env' + echo '' + echo ' ⚠️ .env wurde angelegt. Bitte jetzt anpassen:' + echo ' ssh ds && nano $DS_PATH/.env' + echo '' + echo ' Mindestens setzen:' + echo ' JWT_SECRET=' + echo ' KI_MODE=local' + echo ' KI_LOCAL_URL=http://10.47.11.10:1234/v1' + echo '' + else + echo ' .env existiert bereits.' + fi +" + +# ---------------------------------------------------------- +# 3. Data-Verzeichnis mit korrekten Rechten +# ---------------------------------------------------------- +echo "→ Data-Verzeichnis..." +ssh "$DS_HOST" " + mkdir -p '$DS_PATH/data/media/dogs' + mkdir -p '$DS_PATH/data/media/diary' + mkdir -p '$DS_PATH/data/media/poison' + echo ' Verzeichnisse angelegt.' +" + +# ---------------------------------------------------------- +# 4. Docker-Image bauen und starten +# ---------------------------------------------------------- +echo "→ Docker build + start..." +ssh "$DS_HOST" " + cd '$DS_PATH' && + sudo docker compose build && + sudo docker compose up -d +" + +# ---------------------------------------------------------- +# 5. Status prüfen +# ---------------------------------------------------------- +echo "" +echo "→ Status:" +ssh "$DS_HOST" "sudo docker ps --filter name=ban-yaro --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'" + +echo "" +echo "=== Setup abgeschlossen ===" +echo "" +echo "Nächste Schritte:" +echo " 1. NPM-Eintrag für banyaro.app → Port 3010" +echo " 2. Logs prüfen: make logs" +echo " 3. App aufrufen: https://banyaro.app" +echo ""