Deploy-Skripte: Makefile, setup-ds.sh, new-feature.sh
This commit is contained in:
parent
00be2bbcd5
commit
e364e43480
3 changed files with 370 additions and 0 deletions
147
Makefile
Normal file
147
Makefile
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
# ==============================================================
|
||||
# BAN YARO — Makefile
|
||||
# Alle häufigen Operationen mit kurzen Befehlen.
|
||||
# Verwendung: make <ziel>
|
||||
# ==============================================================
|
||||
|
||||
# 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
|
||||
136
scripts/new-feature.sh
Executable file
136
scripts/new-feature.sh
Executable file
|
|
@ -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 <feature-name>
|
||||
# Beispiel: bash scripts/new-feature.sh poison
|
||||
# ==============================================================
|
||||
|
||||
set -e
|
||||
|
||||
FEATURE="$1"
|
||||
|
||||
if [ -z "$FEATURE" ]; then
|
||||
echo "Verwendung: bash scripts/new-feature.sh <feature-name>"
|
||||
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 = \`
|
||||
<div class="page-container">
|
||||
<h2 class="text-xl font-bold">${TITLE}</h2>
|
||||
<p class="text-secondary mt-2">Noch in Entwicklung.</p>
|
||||
</div>
|
||||
\`;
|
||||
} 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! ==="
|
||||
87
scripts/setup-ds.sh
Executable file
87
scripts/setup-ds.sh
Executable file
|
|
@ -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=<langer-zufaelliger-string>'
|
||||
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 ""
|
||||
Loading…
Add table
Add a link
Reference in a new issue