diff --git a/.gitignore b/.gitignore index f768044..5300ec1 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,10 @@ __pycache__/ *.sqlite3 # IDE -.idea/ +.idea/* +!.idea/runConfigurations/ +.idea/runConfigurations/* +!.idea/runConfigurations/Dev.xml .vscode/ # Frontend build diff --git a/.idea/runConfigurations/Dev.xml b/.idea/runConfigurations/Dev.xml new file mode 100644 index 0000000..2b872f6 --- /dev/null +++ b/.idea/runConfigurations/Dev.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/run_dev.py b/run_dev.py new file mode 100644 index 0000000..f636a2b --- /dev/null +++ b/run_dev.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +"""Dev runner: startet Proxy, Admin-API und Frontend gemeinsam.""" +import os +import sys +import signal +import subprocess +import threading +from pathlib import Path + + +def load_env(path: Path): + if not path.exists(): + return + for line in path.read_text(encoding='utf-8').splitlines(): + line = line.strip() + if line and not line.startswith('#') and '=' in line: + key, _, val = line.partition('=') + os.environ.setdefault(key.strip(), val.strip().strip('"\'')) + + +def pipe_output(proc: subprocess.Popen, label: str, color: str): + reset = '\033[0m' + prefix = f'\033[{color}m[{label}]{reset} ' + for raw in iter(proc.stdout.readline, b''): + sys.stdout.write(prefix + raw.decode(errors='replace')) + sys.stdout.flush() + + +def main(): + root = Path(__file__).parent + load_env(root / '.env') + + if not os.environ.get('ADMIN_PASSWORD'): + print('Fehler: ADMIN_PASSWORD nicht gesetzt (siehe .env)') + sys.exit(1) + + python = root / '.venv' / 'bin' / 'python' + backend = root / 'backend' + frontend = root / 'frontend' + + proxy_host = os.environ.get('PROXY_HOST', '0.0.0.0') + proxy_port = os.environ.get('PROXY_PORT', '8000') + admin_port = os.environ.get('ADMIN_PORT', '8001') + + print('Initialisiere Datenbank...') + subprocess.run([str(python), 'init_db.py'], cwd=backend, check=True) + + print(f'Starte Proxy → http://{proxy_host}:{proxy_port}') + print(f'Starte Admin-API → http://127.0.0.1:{admin_port}') + print('Starte Frontend → http://localhost:5173') + + env = {**os.environ, 'PYTHONUNBUFFERED': '1'} + + procs = [ + (subprocess.Popen( + [str(python), '-m', 'uvicorn', 'main:app', '--reload', + '--host', proxy_host, '--port', proxy_port], + cwd=backend, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env, + ), 'Proxy ', '34'), # blau + (subprocess.Popen( + [str(python), '-m', 'uvicorn', 'admin:app', '--reload', + '--host', '127.0.0.1', '--port', admin_port], + cwd=backend, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env, + ), 'Admin ', '33'), # gelb + (subprocess.Popen( + ['npm', 'run', 'dev'], + cwd=frontend, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + ), 'Frontend', '32'), # grün + ] + + for proc, label, color in procs: + threading.Thread(target=pipe_output, args=(proc, label, color), daemon=True).start() + + def stop(*_): + for p, _, _ in procs: + p.terminate() + + signal.signal(signal.SIGINT, stop) + signal.signal(signal.SIGTERM, stop) + + for p, _, _ in procs: + p.wait() + + +if __name__ == '__main__': + main()