Deine Apps wachsen, wo du sie pflanzt.
🔒 Bitte mit dem Admin-Passwort anmelden.
🌾 Noch keine Apps gepflanzt.
Fuer ausgewaehlte Apps kuerzer pollen (z.B. waehrend aktiver Entwicklung), statt auf den normalen Sync-Intervall zu warten. Schaltet sich automatisch nach Ablauf der Dauer wieder ab.
Appgarden-App-Vorgaben (Repo-Struktur + Konventionen):
requirements.txt optional, Python-Pakete fuers Backend (Repo-ROOT, wird
automatisch installiert)
frontend/index.html Pflicht, ausgeliefert unter /<name>/
frontend/... weitere statische Assets (css/js/...)
backend/cgi-bin/*.py optional, Python3-CGI unter /<name>/cgi-bin/
CGI-Skripte:
- Shebang #!/usr/bin/env python3
- chmod +x setzen UND im Git-Commit erhalten (sonst liefert Apache die Datei
nur als Text statt sie auszufuehren)
- Antwortprotokoll: erst "Status: ..." und "Content-Type: ..." Header-Zeilen,
dann eine Leerzeile, danach der Body
Persistenz:
- Der Repo-Checkout ist READ-ONLY (git reset --hard bei jedem Sync) - niemals
Daten dorthin schreiben
- Env-Var APP_DATA_DIR zeigt auf einen leeren, garantiert beschreibbaren Ordner:
import os
data_dir = os.environ.get("APP_DATA_DIR", ".")
db_path = os.path.join(data_dir, "meine.db")
- Eigene Env-Vars (z.B. fuer eine DB-Datei) lassen sich im Manager pro App unter
"Env-Variablen" setzen (KEY=WERT)
Logging-Konvention (fuers Manager-Log einheitlich):
- Format: [YYYY-MM-DD HH:MM:SS] [app-name] [LEVEL] message
- App-Name: fest in den Code schreiben, z.B. APP_NAME = "meine-app"
- Level: INFO, WARN, ERROR, DEBUG (Großbuchstaben)
- stderr immer mit [ERROR]-Level, nutze file=sys.stderr
- Beispiel:
ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"[{ts}] [meine-app] [INFO] Start", flush=True)
print(f"[{ts}] [meine-app] [ERROR] Fehler!", file=sys.stderr, flush=True)
Deploy-Stand im Frontend anzeigen (optional):
- Manager stellt Endpunkt bereit: /_manager/cgi-bin/app_status.py?name=<name>
- Liefert JSON mit commit_date, commit_message, ok, error
- Beispiel im Footer:
fetch("/_manager/cgi-bin/app_status.py?name=meine-app")
.then(r => r.json())
.then(s => {
if (s.commit_date) {
const d = new Date(s.commit_date).toLocaleString();
document.getElementById("footer").textContent = `${d} – "${s.commit_message}"`;
}
});
Sonstiges:
- Kein eigener Serverprozess/Port - rein pfadbasiertes Routing (/<name>/)
- App-Name: nur Kleinbuchstaben, Ziffern, Bindestriche, 2-32 Zeichen, danach
nicht mehr aenderbar
- Alle Logs landen im Manager-Log (oben sichtbar), auch stderr