commit 4fbcb99743aeba0e551a37430c730d1d754cb973 Author: Oliver Hofmann Date: Mon Apr 27 08:33:43 2026 +0200 Init diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..0c43f31 --- /dev/null +++ b/.env.example @@ -0,0 +1,8 @@ +APP_ENV=development +APP_PREFIX= +DATABASE_URL=sqlite:///./app.db + +# Produktion (MariaDB): +# APP_ENV=production +# APP_PREFIX=/uph +# DATABASE_URL=mysql+pymysql://user:password@db:3306/efihub \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dad53d6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# Environments (Virtualenvs) +.env +.venv +env/ +venv/ +ENV/ + +# Database (Wichtig: Verhindert, dass die lokale SQLite-DB committet wird) +*.sqlite3 +*.db + +# macOS System Files +.DS_Store +.AppleDouble +.LSOverride + +# PyCharm / JetBrains IDE +.idea/ +!.idea/runConfigurations/ +*.iws +*.iml +*.ipr + +# Project specific +docker-compose.override.yml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/efihub.iml b/.idea/efihub.iml new file mode 100644 index 0000000..e4e9378 --- /dev/null +++ b/.idea/efihub.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..3967ea3 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,28 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..9cb91fc --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..7697a7e --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,68 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project + +**University Process Hub (UPH)** — modulares FastAPI-Backend für Fakultätsprozesse (TH Nürnberg). Einstieg ist ein RSS-Server, erweiterbar durch Module in `app/modules/`. Dient als Basis für studentische Arbeiten. + +## Commands + +```bash +# Abhängigkeiten installieren +pip install -r requirements.txt + +# Entwicklungsserver starten +uvicorn app.main:app --reload + +# Mit APP_PREFIX (Traefik-Simulation) +APP_PREFIX=/uph uvicorn app.main:app --reload + +# Tests ausführen +pytest + +# Einzelnen Test ausführen +pytest tests/test_foo.py::test_bar -v + +# Formatting & Linting +black app/ +flake8 app/ +``` + +## Architektur + +### Konfiguration (`app/core/config.py`) + +Zentrale `Settings`-Klasse via `pydantic-settings`. Werte kommen aus `.env` oder Umgebungsvariablen: + +- `APP_PREFIX` — Traefik-Pfadpräfix (z. B. `/uph`). Wird als `root_path` an FastAPI übergeben, damit alle Routen inkl. WebSockets und Swagger UI automatisch korrekt geroutet werden. +- `DATABASE_URL` — `sqlite:///./app.db` lokal, `mysql+pymysql://...` in Produktion. Kein separates Flag nötig — SQLAlchemy erkennt den Dialekt aus der URL. +- Singleton via `@lru_cache` → `get_settings()` als FastAPI-Dependency injizierbar. + +### App-Entrypoint (`app/main.py`) + +`FastAPI(root_path=settings.APP_PREFIX)` — das ist der einzige Ort, an dem `APP_PREFIX` angewendet wird. Kein Prefix-Middleware-Hack nötig. + +### Modulstruktur + +Jedes Feature liegt in `app/modules//` mit: +- `router.py` — `APIRouter`, wird in `main.py` per `app.include_router()` eingebunden +- `service.py` — Businesslogik (keine direkten FastAPI-Abhängigkeiten) +- `models.py` — SQLAlchemy-Models + +Module müssen ohne tiefgreifende Core-Abhängigkeiten exportierbar sein (für studentische Arbeiten). + +### Datenbank (`app/core/database.py`, noch zu erstellen) + +Zentrales `database.py` mit SQLAlchemy 2.0 Engine und Session-Factory. Sessions werden als FastAPI-Dependency (`Depends(get_db)`) injiziert. + +### Authentifizierung (`app/core/auth.py`, noch zu erstellen) + +OAuth2/JWT als FastAPI-Dependencies. Referenzimplementierung liegt in `/Users/oliver/Development/Operations/django-app/authstuff` (Django-Logik, muss auf FastAPI portiert werden). + +## Deployment + +- Traefik-basiertes pfadbasiertes Routing via `APP_PREFIX` +- Docker & Docker Compose (Configs in `docker/`) +- Celery + Redis als Task-Queue (`app/worker/`) +- Admin-UI via `sqladmin` diff --git a/README.md b/README.md new file mode 100644 index 0000000..1cbed78 --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ +# University Process Hub (UPH) + +## 1. Vision & Goals +Modulares Backend für Fakultätsprozesse. Startpunkt ist ein RSS-Server, erweiterbar um REST-APIs und Websockets für Echtzeit-Kommunikation. Das System dient als Basis für studentische Arbeiten. + +## 2. Tech-Stack +* **Framework:** FastAPI (Python 3.11+) +* **Kommunikation:** REST & Websockets (native FastAPI Implementation) +* **Datenbank:** SQLAlchemy 2.0 (Support für SQLite lokal & MariaDB produktiv) +* **Task-Queue:** Celery mit Redis als Broker +* **Deployment:** Docker & Docker Compose +* **Proxy:** Traefik-ready mit pfadbasiertem Routing (`APP_PREFIX`) + +## 3. Architektur-Richtlinien für Claude Code +* **Modularität:** Jedes Modul (z.B. `rss_feed`) liegt in `app/modules/`. Es muss ohne tiefgreifende Core-Abhängigkeiten exportierbar sein. +* **Routing:** Nutze `APIRouter`. Implementiere eine globale Middleware oder eine Prefix-Logik, die die `APP_PREFIX` Umgebungsvariable nutzt, damit alle Routen (inkl. Websockets) unter Traefik funktionieren. +* **Database:** Zentrale `database.py`. Studierende nutzen SQLite, der Server nutzt MariaDB via `DATABASE_URL`. +* **Authentifizierung:** Übernimm das Logik-Konzept aus `/Users/oliver/Development/Operations/django-app/authstuff`, implementiere es aber als FastAPI-Dependencies (OAuth2/JWT). +* **Admin-UI:** Nutze `sqladmin` oder `fastapi-users`, um eine einfache Weboberfläche zur Datenpflege bereitzustellen. +* **Testing:** Schreibe Unit-Tests mit `pytest` für alle Module. Teste auch die Websocket-Kommunikation mit `websockets` oder `httpx`. +* **Documentation:** Nutze FastAPI's automatische Dokumentation (Swagger UI) und ergänze sie mit ausführlichen Docstrings. Erstelle zusätzlich ein `docs/` Verzeichnis für weiterführende Spezifikationen und Anleitungen. +* **Code-Style:** Halte dich an PEP 8. Nutze `black` für automatisches Formatting und `flake8` für Linting. Vermeide komplexe Funktionen (>20 Zeilen) und setze auf klare, sprechende Namen. +* **UX:** Orientiere Dich bei der Visualisierung am Vorläufer, zu erreichen unter `https://medinf.efi.th-nuernberg.de/app/`. Ersetze aber Bootstrap durch Tailwind CSS für eine modernere und flexiblere Gestaltung. Alle UI-Komponenten sollten responsive sein und auf verschiedenen Bildschirmgrößen gut funktionieren. + +## 4. Struktur +. +├── app/ +│ ├── __init__.py +│ ├── main.py # App-Entrypoint & FastAPI Initialisierung +│ ├── core/ # Übergreifende Logik +│ │ ├── config.py # APP_PREFIX, DB_URL, Secrets +│ │ ├── database.py # SQLAlchemy Engine & Session +│ │ └── auth.py # JWT & Berechtigungen (ex-Django Logik) +│ ├── modules/ # Abgeschlossene Module (für Studierende) +│ │ └── rss_feed/ # Das erste Modul +│ │ ├── router.py +│ │ ├── service.py +│ │ └── models.py +│ ├── schemas/ # Pydantic Models (REST/WS Validierung) +│ └── worker/ # Celery Tasks & Scheduler +├── legacy_django/ # Referenzcode (nicht aktiv) +├── docker/ +│ ├── Dockerfile +│ └── docker-compose.yml +├── requirements.txt +└── .env.example \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/main.py b/app/main.py new file mode 100644 index 0000000..61f7173 --- /dev/null +++ b/app/main.py @@ -0,0 +1,22 @@ +from fastapi import FastAPI, WebSocket + +from app.core.config import get_settings + +settings = get_settings() + +app = FastAPI( + title="University Process Hub", + root_path=settings.APP_PREFIX, +) + + +@app.get("/") +async def root(): + return {"status": "ok", "env": settings.APP_ENV} + + +@app.websocket("/ws/hello/{name}") +async def websocket_hello(websocket: WebSocket, name: str): + await websocket.accept() + await websocket.send_text(f"Hello, {name}!") + await websocket.close() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..873c94b --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +fastapi +uvicorn[standard] +pydantic-settings +sqlalchemy \ No newline at end of file diff --git a/test_main.http b/test_main.http new file mode 100644 index 0000000..a2d81a9 --- /dev/null +++ b/test_main.http @@ -0,0 +1,11 @@ +# Test your FastAPI endpoints + +GET http://127.0.0.1:8000/ +Accept: application/json + +### + +GET http://127.0.0.1:8000/hello/User +Accept: application/json + +###