Add multitenant scripts and documentation to release bundle; remove outdated build script
This commit is contained in:
@@ -230,7 +230,15 @@ jobs:
|
|||||||
cp update.sh release-bundle/update.sh
|
cp update.sh release-bundle/update.sh
|
||||||
cp init-admin.sh release-bundle/init-admin.sh
|
cp init-admin.sh release-bundle/init-admin.sh
|
||||||
|
|
||||||
chmod +x release-bundle/start.sh release-bundle/stop.sh release-bundle/restart.sh release-bundle/backup.sh release-bundle/update.sh release-bundle/init-admin.sh
|
# Multitenant scripts & docs
|
||||||
|
cp docker-compose-multitenant.yml release-bundle/docker-compose-multitenant.yml
|
||||||
|
cp docker/nginx/multitenant.conf release-bundle/docker/nginx/multitenant.conf
|
||||||
|
cp manage-tenant.sh release-bundle/manage-tenant.sh
|
||||||
|
cp run-tenant-cmd.sh release-bundle/run-tenant-cmd.sh
|
||||||
|
cp MULTITENANT_DEPLOYMENT.md release-bundle/MULTITENANT_DEPLOYMENT.md
|
||||||
|
cp MULTITENANT_PYTHON_API.md release-bundle/MULTITENANT_PYTHON_API.md
|
||||||
|
|
||||||
|
chmod +x release-bundle/start.sh release-bundle/stop.sh release-bundle/restart.sh release-bundle/backup.sh release-bundle/update.sh release-bundle/init-admin.sh release-bundle/manage-tenant.sh release-bundle/run-tenant-cmd.sh
|
||||||
tar -czf inventarsystem-docker-bundle.tar.gz -C release-bundle .
|
tar -czf inventarsystem-docker-bundle.tar.gz -C release-bundle .
|
||||||
|
|
||||||
- name: Create or update GitHub Release
|
- name: Create or update GitHub Release
|
||||||
|
|||||||
@@ -1,177 +0,0 @@
|
|||||||
# Fehlersuche: Geplante Ausleihen werden nicht automatisch aktiviert
|
|
||||||
|
|
||||||
## 🔍 Mögliche Ursachen
|
|
||||||
|
|
||||||
### 1. **Termin wurde für falsches Datum erstellt**
|
|
||||||
Die meisten Probleme entstehen, weil der Termin für ein **falsches Datum** (z.B. morgen statt heute) erstellt wurde.
|
|
||||||
|
|
||||||
### 2. **Scheduler läuft nicht**
|
|
||||||
Der automatische Scheduler kann deaktiviert sein oder nicht starten.
|
|
||||||
|
|
||||||
### 3. **Zeitzonen-Problem**
|
|
||||||
Die Startzeit kann in einer anderen Zeitzone gespeichert sein als erwartet.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ SOFORT-FIX: Manuell aktivieren
|
|
||||||
|
|
||||||
Falls du eine geplante Ausleihe sofort aktivieren möchtest, nutze diesen Befehl auf dem Server:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker exec inventarsystem-mongodb mongosh --eval "
|
|
||||||
db.ausleihungen.updateOne(
|
|
||||||
{_id: ObjectId('BOOKING_ID_HIER')},
|
|
||||||
{\$set: {Status: 'active', LastUpdated: new Date()}}
|
|
||||||
)" Inventarsystem
|
|
||||||
```
|
|
||||||
|
|
||||||
Ersetze `BOOKING_ID_HIER` mit der ID deiner Ausleihe.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔧 DEBUG: Alle geplanten Ausleihen anschauen
|
|
||||||
|
|
||||||
Führe auf deinem Server aus:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker exec inventarsystem-mongodb mongosh --eval "
|
|
||||||
db.ausleihungen.find({Status: 'planned'}).pretty()
|
|
||||||
" Inventarsystem
|
|
||||||
```
|
|
||||||
|
|
||||||
Das zeigt dir:
|
|
||||||
- **Start**: Das gespeicherte Startdatum/Uhrzeit
|
|
||||||
- **Periode**: Die Schulstunde (falls verwendet)
|
|
||||||
- **Erstellungs-Zeit vs. aktuelle Zeit**: Vergleich
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 PROBLEM 1: Falsches Datum beim Erstellen
|
|
||||||
|
|
||||||
**Symptom**: Start-Zeit ist in der Zukunft (z.B. morgen statt heute)
|
|
||||||
|
|
||||||
**Lösung**:
|
|
||||||
1. In der Kalender-Ansicht das **richtige Datum** auswählen
|
|
||||||
2. Die **aktuelle Uhrzeit** für den Beginn nutzen (nicht eine zukünftige Zeit)
|
|
||||||
3. Für Schulstunden: Stelle sicher die **heutige Schulstunde** zu wählen
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 PROBLEM 2: Scheduler läuft nicht
|
|
||||||
|
|
||||||
**Symptom**: Keine Logs über Termin-Aktivierungen
|
|
||||||
|
|
||||||
**Überprüfung**:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Container-Logs anschauen
|
|
||||||
docker logs inventarsystem-app | grep -i "scheduler\|appointment\|status update"
|
|
||||||
|
|
||||||
# 2. Scheduler ist aktiviert?
|
|
||||||
docker exec inventarsystem-app python3 -c "
|
|
||||||
import sys
|
|
||||||
sys.path.insert(0, '/app/Web')
|
|
||||||
import settings as cfg
|
|
||||||
print(f'Scheduler aktiviert: {cfg.SCHEDULER_ENABLED}')
|
|
||||||
print(f'Scheduler Intervall: {cfg.SCHEDULER_INTERVAL_MIN} Minuten')
|
|
||||||
"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Lösung wenn deaktiviert**:
|
|
||||||
- In `config.json` ändern:
|
|
||||||
```json
|
|
||||||
"scheduler": {
|
|
||||||
"enabled": true,
|
|
||||||
"interval_minutes": 1
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- Container neu starten: `docker-compose restart app`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 PROBLEM 3: Startzeit als nur-Zeit (kein Datum)
|
|
||||||
|
|
||||||
**Symptom**: Start-Zeit zeigt nur "13:30" ohne Datum
|
|
||||||
|
|
||||||
**Überprüfung**: In der Datenbank nach `{Start: {$type: "string"}}` suchen statt datetime
|
|
||||||
|
|
||||||
**Lösung**: Die Ausleihe muss mit einem vollständigen Datum+Uhrzeit erstellt werden.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 AUTOMATISCHE AKTIVIERUNG TESTEN
|
|
||||||
|
|
||||||
Nach dem Fix: Erstelle eine Ausleihe für:
|
|
||||||
- **Heute** (das aktuelle Datum)
|
|
||||||
- **Schulstunde 7** (13:30-14:15)
|
|
||||||
- Startzeitpunkt sollte **jetzt oder in 1 Minute** sein
|
|
||||||
|
|
||||||
Warte 2 Minuten. Der Status sollte von `planned` zu `active` wechseln.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 SCHEDULER STATUS ÜBERPRÜFEN
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Zeige die letzten 50 Log-Zeilen
|
|
||||||
docker logs --tail 50 inventarsystem-app | tail -20
|
|
||||||
|
|
||||||
# Suche nach "Appointment status update"
|
|
||||||
docker logs inventarsystem-app 2>/dev/null | grep -i "Appointment status" | tail -5
|
|
||||||
```
|
|
||||||
|
|
||||||
Erwartete Log-Ausgabe:
|
|
||||||
```
|
|
||||||
Appointment status update finished: X changed (Y active, Z completed)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔍 DETAILLIERTE DEBUG-INFOS
|
|
||||||
|
|
||||||
Wenn obiges nicht funktioniert, führe dies aus:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker exec inventarsystem-app python3 -c "
|
|
||||||
from pymongo import MongoClient
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
client = MongoClient('mongodb', 27017)
|
|
||||||
db = client['Inventarsystem']
|
|
||||||
aus = db['ausleihungen']
|
|
||||||
|
|
||||||
print('=== GEPLANTE AUSLEIHEN ===')
|
|
||||||
for b in aus.find({'Status': 'planned'}).limit(3):
|
|
||||||
print(f\"Start: {b.get('Start')} | Typ: {type(b.get('Start')).__name__}\")
|
|
||||||
print(f\"Periode: {b.get('Period')} | User: {b.get('User')}\")
|
|
||||||
print(f\"Jetzt > Start? {datetime.datetime.now() > b.get('Start', datetime.datetime.max)}\")
|
|
||||||
print()
|
|
||||||
"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 💡 EMPFOHLENE EINSTELLUNG FÜR SCHULEN
|
|
||||||
|
|
||||||
In `config.json` verwende diese Werte:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"scheduler": {
|
|
||||||
"enabled": true,
|
|
||||||
"interval_minutes": 1,
|
|
||||||
"backup_interval_hours": 24
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Dies checkt **jede Minute** ob Termine aktiviert werden sollen - perfekt für Schulstunden.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Weitere Hilfe?
|
|
||||||
|
|
||||||
Falls das nicht funktioniert:
|
|
||||||
1. Schreib mir die **exakte Uhrzeit** wann du die Ausleihe erstellt hast
|
|
||||||
2. Und wann sie hätte aktiviert werden sollen
|
|
||||||
3. Zeige mir ein Beispiel aus der DB mit `docker exec inventarsystem-mongodb mongosh...`
|
|
||||||
@@ -125,3 +125,4 @@ def get_items():
|
|||||||
The `get_tenant_db` function queries `g.tenant_context` inside Flask, calculates the database name from the subdomain, and returns a live `pymongo.database.Database` object.
|
The `get_tenant_db` function queries `g.tenant_context` inside Flask, calculates the database name from the subdomain, and returns a live `pymongo.database.Database` object.
|
||||||
|
|
||||||
This ensures that scaling is extremely cheap on resources because 1 Application Container connects to 100 separate Tenant Databases using just 1 shared `MongoClient` pool.
|
This ensures that scaling is extremely cheap on resources because 1 Application Container connects to 100 separate Tenant Databases using just 1 shared `MongoClient` pool.
|
||||||
|
|
||||||
|
|||||||
-107
@@ -1,107 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
cd "$SCRIPT_DIR"
|
|
||||||
|
|
||||||
SUDO=""
|
|
||||||
if [ "$(id -u)" -ne 0 ] && command -v sudo >/dev/null 2>&1; then
|
|
||||||
SUDO="sudo"
|
|
||||||
fi
|
|
||||||
|
|
||||||
VENV_PYTHON="$SCRIPT_DIR/.venv/bin/python"
|
|
||||||
if [ ! -x "$VENV_PYTHON" ]; then
|
|
||||||
echo "Error: .venv python not found at $VENV_PYTHON"
|
|
||||||
echo "Create it first, e.g.: python3 -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$(id -u)" -ne 0 ] && [ ! -w "$SCRIPT_DIR/.venv" ]; then
|
|
||||||
echo "Fixing ownership of .venv for current user..."
|
|
||||||
if [ -n "$SUDO" ]; then
|
|
||||||
$SUDO chown -R "$(id -un):$(id -gn)" "$SCRIPT_DIR/.venv"
|
|
||||||
else
|
|
||||||
echo "Error: .venv is not writable and sudo is unavailable."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
for path in "$SCRIPT_DIR/dist" "$SCRIPT_DIR/build"; do
|
|
||||||
if [ -e "$path" ] && [ "$(id -u)" -ne 0 ]; then
|
|
||||||
echo "Ensuring ownership of $(basename "$path") for current user..."
|
|
||||||
if [ -n "$SUDO" ]; then
|
|
||||||
$SUDO chown -R "$(id -un):$(id -gn)" "$path"
|
|
||||||
else
|
|
||||||
if [ ! -w "$path" ]; then
|
|
||||||
echo "Error: $path is not writable and sudo is unavailable."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "Installing Nuitka build dependencies in .venv..."
|
|
||||||
"$VENV_PYTHON" -m pip install --upgrade pip setuptools wheel
|
|
||||||
"$VENV_PYTHON" -m pip install --upgrade "nuitka==2.8.10" ordered-set zstandard
|
|
||||||
|
|
||||||
DIST_DIR="$SCRIPT_DIR/dist"
|
|
||||||
BUILD_DIR="$SCRIPT_DIR/build"
|
|
||||||
OUTPUT_NAME="inventarsystem"
|
|
||||||
|
|
||||||
mkdir -p "$DIST_DIR" "$BUILD_DIR"
|
|
||||||
|
|
||||||
NUITKA_DATA_ARGS=()
|
|
||||||
|
|
||||||
if [ -d "$SCRIPT_DIR/Web/templates" ]; then
|
|
||||||
NUITKA_DATA_ARGS+=("--include-data-dir=$SCRIPT_DIR/Web/templates=templates")
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d "$SCRIPT_DIR/Web/static" ]; then
|
|
||||||
NUITKA_DATA_ARGS+=("--include-data-dir=$SCRIPT_DIR/Web/static=static")
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d "$SCRIPT_DIR/uploads" ]; then
|
|
||||||
NUITKA_DATA_ARGS+=("--include-data-dir=$SCRIPT_DIR/uploads=uploads")
|
|
||||||
fi
|
|
||||||
|
|
||||||
ORIGINAL_PERF_PARANOID=""
|
|
||||||
if [ -r /proc/sys/kernel/perf_event_paranoid ]; then
|
|
||||||
ORIGINAL_PERF_PARANOID="$(cat /proc/sys/kernel/perf_event_paranoid)"
|
|
||||||
if [ "$ORIGINAL_PERF_PARANOID" -gt 1 ]; then
|
|
||||||
echo "Temporarily setting kernel.perf_event_paranoid=1 for Nuitka build compatibility..."
|
|
||||||
if ! $SUDO sh -c 'echo 1 > /proc/sys/kernel/perf_event_paranoid'; then
|
|
||||||
echo "Warning: Could not adjust kernel.perf_event_paranoid automatically."
|
|
||||||
echo "Run: sudo sh -c 'echo 1 > /proc/sys/kernel/perf_event_paranoid' and retry."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
restore_perf_setting() {
|
|
||||||
if [ -n "$ORIGINAL_PERF_PARANOID" ] && [ "$ORIGINAL_PERF_PARANOID" -gt 1 ]; then
|
|
||||||
$SUDO sh -c "echo $ORIGINAL_PERF_PARANOID > /proc/sys/kernel/perf_event_paranoid" >/dev/null 2>&1 || true
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
trap restore_perf_setting EXIT
|
|
||||||
|
|
||||||
echo "Building standalone binary with Nuitka..."
|
|
||||||
"$VENV_PYTHON" -m nuitka \
|
|
||||||
--standalone \
|
|
||||||
--assume-yes-for-downloads \
|
|
||||||
--follow-imports \
|
|
||||||
--output-dir="$DIST_DIR" \
|
|
||||||
--output-filename="$OUTPUT_NAME" \
|
|
||||||
"${NUITKA_DATA_ARGS[@]}" \
|
|
||||||
--remove-output \
|
|
||||||
"$SCRIPT_DIR/Web/app.py"
|
|
||||||
|
|
||||||
APP_DIST_DIR="$DIST_DIR/app.dist"
|
|
||||||
if [ -d "$APP_DIST_DIR" ]; then
|
|
||||||
echo "Nuitka build complete."
|
|
||||||
echo "Run with: $APP_DIST_DIR/$OUTPUT_NAME"
|
|
||||||
else
|
|
||||||
echo "Build finished, but expected output directory not found: $APP_DIST_DIR"
|
|
||||||
echo "Check Nuitka output above."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
Reference in New Issue
Block a user