update
This commit is contained in:
297
AzA march 2026 - Kopie (18)/workforce_planner/ARCHITECTURE.md
Normal file
297
AzA march 2026 - Kopie (18)/workforce_planner/ARCHITECTURE.md
Normal file
@@ -0,0 +1,297 @@
|
||||
# Workforce Planner – Zielarchitektur
|
||||
|
||||
## 1. Architekturdiagramm
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ CLIENTS │
|
||||
│ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
|
||||
│ │ Desktop App │ │ Web App │ │ MedWork Plugin │ │
|
||||
│ │ (tkinter) │ │(React/Vue/…) │ │ (Integration) │ │
|
||||
│ └──────┬───────┘ └──────┬───────┘ └────────┬─────────┘ │
|
||||
│ │ │ │ │
|
||||
│ └──────────────────┼─────────────────────┘ │
|
||||
│ │ │
|
||||
│ HTTPS / REST API │
|
||||
└────────────────────────────┼────────────────────────────────────┘
|
||||
│
|
||||
┌────────────────────────────┼────────────────────────────────────┐
|
||||
│ API GATEWAY │
|
||||
│ │
|
||||
│ ┌─────────────────────────┴────────────────────────────────┐ │
|
||||
│ │ FastAPI Server │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────┐ ┌────────────┐ ┌──────────┐ ┌────────┐ │ │
|
||||
│ │ │ Auth │ │ CORS │ │ Audit │ │ Rate │ │ │
|
||||
│ │ │Middleware│ │ Middleware │ │Middleware │ │Limiter │ │ │
|
||||
│ │ └─────────┘ └────────────┘ └──────────┘ └────────┘ │ │
|
||||
│ │ │ │
|
||||
│ │ ┌────────────────────────────────────────────────────┐ │ │
|
||||
│ │ │ API Routes │ │ │
|
||||
│ │ │ /employees /absences /balance /practices │ │ │
|
||||
│ │ │ /auth /reports /health /audit │ │ │
|
||||
│ │ └────────────────────────┬───────────────────────────┘ │ │
|
||||
│ └───────────────────────────┼───────────────────────────────┘ │
|
||||
└──────────────────────────────┼──────────────────────────────────┘
|
||||
│
|
||||
┌──────────────────────────────┼──────────────────────────────────┐
|
||||
│ SERVICE LAYER │
|
||||
│ (Businesslogik) │
|
||||
│ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
|
||||
│ │ Employee │ │ Absence │ │ Approval │ │
|
||||
│ │ Service │ │ Service │ │ Workflow │ │
|
||||
│ └──────┬───────┘ └──────┬───────┘ └──────────┬───────────┘ │
|
||||
│ │ │ │ │
|
||||
│ │ ┌────────────┴──────────┐ │ │
|
||||
│ │ │ Business Rules │ │ │
|
||||
│ │ │ • Überschneidung │ │ │
|
||||
│ │ │ • Kontingentprüfung │ │ │
|
||||
│ │ │ • Mindestbesetzung │ │ │
|
||||
│ │ └───────────────────────┘ │ │
|
||||
│ │ │ │
|
||||
└─────────┼────────────────────────────────────────┼──────────────┘
|
||||
│ │
|
||||
┌─────────┼────────────────────────────────────────┼──────────────┐
|
||||
│ │ REPOSITORY LAYER │ │
|
||||
│ │ (Datenzugriff) │ │
|
||||
│ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
|
||||
│ │ Employee │ │ Absence │ │ Balance │ │
|
||||
│ │ Repository │ │ Repository │ │ Repository │ │
|
||||
│ └──────┬───────┘ └──────┬───────┘ └──────────┬───────────┘ │
|
||||
└─────────┼─────────────────┼─────────────────────┼──────────────┘
|
||||
│ │ │
|
||||
└─────────────────┼──────────────────────┘
|
||||
│
|
||||
┌──────┴──────┐
|
||||
│ SQLAlchemy │
|
||||
│ ORM │
|
||||
└──────┬──────┘
|
||||
│
|
||||
┌────────────┴────────────┐
|
||||
│ │
|
||||
┌──────┴──────┐ ┌───────┴──────┐
|
||||
│ SQLite │ │ PostgreSQL │
|
||||
│ (Dev) │ │ (Produktion)│
|
||||
└─────────────┘ └──────────────┘
|
||||
```
|
||||
|
||||
## 2. Komponentenbeschreibung
|
||||
|
||||
### Client Layer
|
||||
| Komponente | Beschreibung |
|
||||
|---|---|
|
||||
| **Desktop App** | Bestehende tkinter-App. Wird umgebaut: statt lokaler JSON-Dateien ruft sie die REST API auf. Gleiche Benutzeranmeldung wie Web. |
|
||||
| **Web App** | Modernes Web-Frontend (React/Vue/Svelte). Nutzt dieselbe API. Responsive für Tablet/Desktop. |
|
||||
| **MedWork Plugin** | Adapter der MedWork-Daten (Patienten, Termine) mit dem Arbeitsplan verknüpft. Eigener API-Endpunkt. |
|
||||
|
||||
### API Layer
|
||||
| Komponente | Beschreibung |
|
||||
|---|---|
|
||||
| **FastAPI Server** | Zentraler Einstiegspunkt. Stellt REST-Endpunkte bereit. Auto-generierte OpenAPI-Doku. |
|
||||
| **Auth Middleware** | JWT-basierte Authentifizierung. Gleiche Tokens für Desktop + Web. |
|
||||
| **Audit Middleware** | Protokolliert jede schreibende Aktion (wer, was, wann, alte/neue Werte). |
|
||||
| **CORS Middleware** | Erlaubt Cross-Origin-Zugriffe für Web-Client. |
|
||||
|
||||
### Service Layer (Businesslogik)
|
||||
| Komponente | Beschreibung |
|
||||
|---|---|
|
||||
| **EmployeeService** | Mitarbeiter anlegen/bearbeiten/deaktivieren. E-Mail-Duplikat-Check. |
|
||||
| **AbsenceService** | Abwesenheiten erstellen mit Regelprüfung. Kontingent berechnen. |
|
||||
| **Business Rules** | `check_no_overlap` – keine überlappenden Einträge. `check_balance` – genug Ferientage? `check_min_staffing` – Mindestbesetzung gewährleistet? |
|
||||
| **Approval Workflow** | Pending → Approved/Rejected Workflow mit Genehmiger-Zuweisung. |
|
||||
|
||||
### Repository Layer
|
||||
| Komponente | Beschreibung |
|
||||
|---|---|
|
||||
| **EmployeeRepository** | CRUD für Mitarbeiter. Einziger Code der direkt SQL ausführt. |
|
||||
| **AbsenceRepository** | CRUD + Spezialabfragen (Überschneidungen, Abwesende pro Tag). |
|
||||
| **BalanceRepository** | Ferientage-Kontingent pro Mitarbeiter/Jahr. |
|
||||
|
||||
### Data Layer
|
||||
| Komponente | Beschreibung |
|
||||
|---|---|
|
||||
| **SQLAlchemy ORM** | Abstrahiert Datenbank. Identischer Code für SQLite und PostgreSQL. |
|
||||
| **Practice (Mandant)** | Multi-Tenant: jede Praxis hat eigene Mitarbeiter/Abwesenheiten. |
|
||||
| **AuditLog** | Unveränderliches Änderungsprotokoll mit JSON-Diff. |
|
||||
|
||||
## 3. Technologie-Stack
|
||||
|
||||
| Schicht | Technologie | Begründung |
|
||||
|---|---|---|
|
||||
| **Backend** | Python 3.11+ | Bestehende Codebasis, grosses Ökosystem |
|
||||
| **API Framework** | FastAPI | Async, Auto-Docs, Pydantic-Integration, modern |
|
||||
| **ORM** | SQLAlchemy 2.0 | Industriestandard, DB-agnostisch |
|
||||
| **Validierung** | Pydantic v2 | Schemas für API + Clients, schnell |
|
||||
| **Auth** | JWT (python-jose) | Stateless, Desktop + Web kompatibel |
|
||||
| **Passwörter** | passlib + bcrypt | Industriestandard |
|
||||
| **DB (Dev)** | SQLite | Kein Setup nötig, lokales Testen |
|
||||
| **DB (Prod)** | PostgreSQL 16 | ACID, JSON-Support, skalierbar |
|
||||
| **Desktop** | tkinter (→ später Qt) | Bestehend, HTTP-Client wird ergänzt |
|
||||
| **Web** | React oder Vue.js | SPA, nutzt dieselbe API |
|
||||
| **Deployment** | Docker + Docker Compose | Einfach, reproduzierbar |
|
||||
| **Reverse Proxy** | nginx / Caddy | HTTPS, Load Balancing |
|
||||
|
||||
## 4. Datenfluss
|
||||
|
||||
### Abwesenheit eintragen (von jedem Client)
|
||||
|
||||
```
|
||||
Client (Desktop/Web)
|
||||
│
|
||||
▼
|
||||
POST /api/v1/absences
|
||||
{ employee_id, category, start_date, end_date, reason }
|
||||
│
|
||||
▼
|
||||
Auth Middleware ──── JWT prüfen ──── 401 wenn ungültig
|
||||
│
|
||||
▼
|
||||
AbsenceService.create_absence()
|
||||
│
|
||||
├─→ EmployeeRepository.get_by_id() → Mitarbeiter existiert?
|
||||
├─→ rules.check_no_overlap() → Überschneidung?
|
||||
├─→ rules.check_balance() → Genug Ferientage?
|
||||
├─→ rules.check_min_staffing() → Mindestbesetzung OK?
|
||||
│
|
||||
├─→ AbsenceRepository.create() → DB INSERT
|
||||
├─→ AuditLog.log_action() → Protokollierung
|
||||
├─→ db.commit()
|
||||
│
|
||||
▼
|
||||
Response: 201 Created
|
||||
{ id, employee_id, category, status, business_days, ... }
|
||||
│
|
||||
▼
|
||||
Client aktualisiert Kalenderansicht
|
||||
```
|
||||
|
||||
### Login-Flow (Desktop + Web identisch)
|
||||
|
||||
```
|
||||
Client
|
||||
│
|
||||
▼
|
||||
POST /api/v1/auth/login
|
||||
{ email, password }
|
||||
│
|
||||
▼
|
||||
verify_password(plain, hashed)
|
||||
│
|
||||
├─→ Falsch: 401 Unauthorized
|
||||
├─→ Richtig: create_access_token(employee_id, role)
|
||||
│
|
||||
▼
|
||||
Response: { access_token, token_type, employee }
|
||||
│
|
||||
▼
|
||||
Client speichert Token → sendet bei jedem Request als
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
### Multi-Tenant Datenfluss
|
||||
|
||||
```
|
||||
Praxis A (ID: praxis_a) Praxis B (ID: praxis_b)
|
||||
│ │
|
||||
▼ ▼
|
||||
Mitarbeiter mit Mitarbeiter mit
|
||||
practice_id = praxis_a practice_id = praxis_b
|
||||
│ │
|
||||
▼ ▼
|
||||
Abwesenheiten nur Abwesenheiten nur
|
||||
für Praxis A sichtbar für Praxis B sichtbar
|
||||
|
||||
Admin-Benutzer mit role=ADMIN kann praxisübergreifend zugreifen.
|
||||
```
|
||||
|
||||
## 5. Deployment-Konzept
|
||||
|
||||
### Entwicklung (lokal)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Entwickler-PC │
|
||||
│ │
|
||||
│ uvicorn workforce_planner.api.app:app │
|
||||
│ │ │
|
||||
│ └──→ SQLite (workforce_planner.db)│
|
||||
│ │
|
||||
│ Desktop App (tkinter) → localhost:8000 │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Produktion (Docker)
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────┐
|
||||
│ Server / VPS / Cloud │
|
||||
│ │
|
||||
│ ┌────────────┐ │
|
||||
│ │ nginx │ ◄── HTTPS (Let's Encrypt) │
|
||||
│ │ :443/:80 │ │
|
||||
│ └─────┬──────┘ │
|
||||
│ │ │
|
||||
│ ┌─────┴──────┐ ┌──────────────────────────────┐ │
|
||||
│ │ FastAPI │ │ PostgreSQL │ │
|
||||
│ │ :8000 ├──►│ :5432 │ │
|
||||
│ │ (2 Worker) │ │ Volume: /data/postgres │ │
|
||||
│ └────────────┘ └──────────────────────────────┘ │
|
||||
│ │
|
||||
│ docker-compose.yml orchestriert alles │
|
||||
└──────────────────────────────────────────────────────┘
|
||||
|
||||
Desktop Clients ──────► server.praxis.ch:443/api/v1/
|
||||
Web Clients ──────► server.praxis.ch:443/
|
||||
```
|
||||
|
||||
### docker-compose.yml (Ziel)
|
||||
|
||||
```yaml
|
||||
services:
|
||||
api:
|
||||
build: .
|
||||
ports: ["8000:8000"]
|
||||
environment:
|
||||
WP_DATABASE_URL: postgresql://wp:secret@db:5432/workforce
|
||||
WP_SECRET_KEY: ${SECRET_KEY}
|
||||
depends_on: [db]
|
||||
|
||||
db:
|
||||
image: postgres:16-alpine
|
||||
volumes: [pgdata:/var/lib/postgresql/data]
|
||||
environment:
|
||||
POSTGRES_DB: workforce
|
||||
POSTGRES_USER: wp
|
||||
POSTGRES_PASSWORD: secret
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
ports: ["443:443", "80:80"]
|
||||
volumes: [./nginx.conf:/etc/nginx/conf.d/default.conf]
|
||||
depends_on: [api]
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
```
|
||||
|
||||
## Aktueller Stand
|
||||
|
||||
| Komponente | Status |
|
||||
|---|---|
|
||||
| Datenmodelle (Employee, Absence, BalanceAccount, Practice, AuditLog) | ✅ Fertig |
|
||||
| Enums (AbsenceCategory, EmployeeRole, AbsenceStatus) | ✅ Fertig |
|
||||
| Pydantic Schemas (Create/Update/Read) | ✅ Fertig |
|
||||
| Database Setup (SQLite/PostgreSQL) | ✅ Fertig |
|
||||
| Repository Layer (Employee, Absence, Balance) | ✅ Fertig |
|
||||
| Service Layer + Business Rules | ✅ Fertig |
|
||||
| FastAPI Routen (Employees, Absences, Balance) | ✅ Fertig |
|
||||
| JWT Auth + Rollen | ✅ Fertig |
|
||||
| Audit Logging | ✅ Fertig |
|
||||
| Multi-Tenant (Practice) | ✅ Modell fertig |
|
||||
| Desktop-Client Umstellung auf API | ⬜ Nächster Schritt |
|
||||
| Web-Frontend | ⬜ Geplant |
|
||||
| MedWork-Integration | ⬜ Geplant |
|
||||
| Docker Deployment | ⬜ Geplant |
|
||||
Reference in New Issue
Block a user