init
This commit is contained in:
commit
5126decf36
4 files changed
+341
No files matched your search
@@ -0,0 +1,31 @@
|
|||||||
|
# kbcrm
|
||||||
|
|
||||||
|
[Kurzbeschreibung folgt – Zweck und Ziel der Applikation]
|
||||||
|
|
||||||
|
**Authentifizierung** vollständig an Zitadel delegiert. Lokale Datenhaltung,
|
||||||
|
Benutzer- und Rollenverwaltung über SQLite.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Technologie-Stack
|
||||||
|
|
||||||
|
| Komponente | Technologie |
|
||||||
|
|---|---|
|
||||||
|
| Backend | Python Flask 2.x |
|
||||||
|
| OIDC-Client | Authlib |
|
||||||
|
| Datenbank | SQLite via SQLAlchemy |
|
||||||
|
| IdP | Zitadel |
|
||||||
|
| Produktion | Docker / gunicorn |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Lokale Entwicklung
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 -m venv venv
|
||||||
|
source venv/bin/activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
cp .env.example .env # Zitadel-Credentials eintragen
|
||||||
|
flask db-init # Schema initialisieren
|
||||||
|
flask seed-db # Testdaten einspielen
|
||||||
|
flask run # App startet auf http://localhost:5000
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
# Zitadel-Einrichtung – Schritt-für-Schritt
|
||||||
|
|
||||||
|
Zitadel-Instanz: **https://id.vmlx.de**
|
||||||
|
|
||||||
|
Ziel dieser Anleitung: Das OIDC-Projekt **kbcrm** anlegen, drei Testrollen definieren,
|
||||||
|
drei Testnutzer erstellen, ihnen Rollen zuweisen und die Zitadel-User-IDs
|
||||||
|
(`sub`-Werte) für das DB-Seeding ermitteln.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Schritt 1 – Zitadel-Projekt anlegen
|
||||||
|
|
||||||
|
1. Login unter https://id.vmlx.de
|
||||||
|
2. Linke Navigation → **Projekte** → **Neu anlegen**
|
||||||
|
3. Name: `kbcrm` → Speichern
|
||||||
|
4. Im Projekt-Detail unter **Einstellungen** folgende Optionen aktivieren:
|
||||||
|
- ☑ **Assert Roles on Authentication** (Rollen werden in Token geschrieben)
|
||||||
|
- ☑ **Check Authorization on Authentication** (Zugriff nur für zugewiesene Nutzer)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Schritt 2 – Rollen anlegen
|
||||||
|
|
||||||
|
Im Projekt → Tab **Rollen** → drei Rollen anlegen:
|
||||||
|
|
||||||
|
| Anzeigename | Schlüssel (Key) |
|
||||||
|
|---|---|
|
||||||
|
| Admin | `Admin` |
|
||||||
|
| Mitarbeiter | `Mitarbeiter` |
|
||||||
|
| Kunde | `Kunde` |
|
||||||
|
|
||||||
|
> Der Schlüssel (Key) muss **exakt** so geschrieben sein – er erscheint so im Token-Claim.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Schritt 3 – OIDC-Anwendung anlegen
|
||||||
|
|
||||||
|
Im Projekt → Tab **Anwendungen** → **Neu anlegen**
|
||||||
|
|
||||||
|
| Feld | Wert |
|
||||||
|
|---|---|
|
||||||
|
| Name | `kbcrm-web` |
|
||||||
|
| Typ | **Web** |
|
||||||
|
| Auth-Methode | **Code** (Authorization Code mit Client Secret) |
|
||||||
|
|
||||||
|
Nach dem Erstellen:
|
||||||
|
- **Client-ID** und **Client-Secret** notieren → kommen in die `.env`
|
||||||
|
- Unter **Redirect-URIs** eintragen:
|
||||||
|
- `http://localhost:5000/auth/callback` (Lokal)
|
||||||
|
- `https://<deine-domain>/auth/callback` (Prod, falls zutreffend)
|
||||||
|
- Unter **Post-Logout-Redirect-URIs** eintragen:
|
||||||
|
- `http://localhost:5000/`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Schritt 4 – Testnutzer anlegen
|
||||||
|
|
||||||
|
Navigation: **Nutzer** (oberste Ebene, nicht innerhalb eines Projekts) → **Neu anlegen**
|
||||||
|
|
||||||
|
Drei Nutzer erstellen:
|
||||||
|
|
||||||
|
| Name | E-Mail | Passwort | Zitadel-Rolle |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Admin Test | admin@test.local | (eigenes PW) | Admin |
|
||||||
|
| Mitarbeiter Test | ma@test.local | (eigenes PW) | Mitarbeiter |
|
||||||
|
| Kunde Test | kunde@test.local | (eigenes PW) | Kunde |
|
||||||
|
|
||||||
|
> Bei der Erstellung: **Passwort beim ersten Login ändern** deaktivieren empfohlen, damit Tests flüssig laufen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Schritt 5 – Rollen an Nutzer vergeben
|
||||||
|
|
||||||
|
Für jeden Nutzer:
|
||||||
|
|
||||||
|
1. **Nutzer** → Nutzer auswählen → Tab **Autorisierungen**
|
||||||
|
2. → **Neu** → Projekt `kbcrm` wählen → entsprechende Rolle wählen → Speichern
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Schritt 6 – User-IDs (sub) ermitteln
|
||||||
|
|
||||||
|
Die User-ID (Zitadel-`sub`) ist die interne Zitadel-Nutzer-ID, **nicht** die E-Mail.
|
||||||
|
|
||||||
|
**Methode A – Zitadel-Konsole:**
|
||||||
|
Nutzer auswählen → oben in der Detailansicht steht die **User-ID** (z. B. `236968807784841234`)
|
||||||
|
|
||||||
|
**Methode B – Aus dem App-Log (nach Schritt 7):**
|
||||||
|
Nach dem ersten Login loggt die App in stdout:
|
||||||
|
```
|
||||||
|
OIDC Login – sub: 236968807784841234 | email: admin@test.local | roles: ['Admin']
|
||||||
|
```
|
||||||
|
|
||||||
|
Alle drei Sub-Werte notieren für den nächsten Schritt.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Schritt 7 – .env befüllen und DB seeden
|
||||||
|
|
||||||
|
`.env` aus `.env.example` kopieren und befüllen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
```env
|
||||||
|
ZITADEL_CLIENT_ID=<Client-ID aus Schritt 3>
|
||||||
|
ZITADEL_CLIENT_SECRET=<Client-Secret aus Schritt 3>
|
||||||
|
ZITADEL_DISCOVERY_URL=https://id.vmlx.de/.well-known/openid-configuration
|
||||||
|
SECRET_KEY=<zufälliger langer String>
|
||||||
|
```
|
||||||
|
|
||||||
|
Dann in `app/__init__.py` die Platzhalter in `seed_db()` mit den echten Sub-Werten ersetzen:
|
||||||
|
|
||||||
|
```python
|
||||||
|
ADMIN_ID = "236968807784841234" # <-- echte Zitadel-User-ID
|
||||||
|
MITARBEITER_ID = "..."
|
||||||
|
KUNDE_ID = "..."
|
||||||
|
```
|
||||||
|
|
||||||
|
Anschließend seeden:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
source venv/bin/activate
|
||||||
|
flask seed-db
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Discovery-URL verifizieren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl https://id.vmlx.de/.well-known/openid-configuration | python3 -m json.tool
|
||||||
|
```
|
||||||
|
|
||||||
|
Wenn die Antwort ein JSON mit `issuer`, `authorization_endpoint` usw. ist, ist die URL korrekt.
|
||||||
|
Sollte die URL nicht funktionieren, alternative probieren:
|
||||||
|
`https://id.vmlx.de/oauth/v2/.well-known/openid-configuration`
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# AI.md — Strukturvorgaben für neue Applikation
|
||||||
|
|
||||||
|
**Autoren:** Björn Runden, Gerd Goldberg
|
||||||
|
**Zweck dieses Dokuments:** Verbindliche strukturelle, betriebliche und infrastrukturelle Vorgaben für eine neue Python-Applikation. Applikationslogik, Routing und Frontend sind bewusst nicht Teil dieses Dokuments.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Technologie-Stack
|
||||||
|
|
||||||
|
| Schicht | Technologie |
|
||||||
|
|---|---|
|
||||||
|
| Backend-Framework | Python Flask 2.x |
|
||||||
|
| OIDC-Authentifizierung | Authlib (gegen Zitadel als externen IdP) |
|
||||||
|
| Datenbank / ORM | SQLite + SQLAlchemy |
|
||||||
|
| Konfiguration | 12-Factor-App via `.env`-Datei |
|
||||||
|
| Produktions-Server | Gunicorn |
|
||||||
|
| Container | Docker (`python:3.11-slim`), orchestriert via `docker-compose.yml` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Verzeichnisstruktur
|
||||||
|
|
||||||
|
```text
|
||||||
|
.
|
||||||
|
├── .gitignore
|
||||||
|
├── .env
|
||||||
|
├── .env.example
|
||||||
|
├── requirements.txt
|
||||||
|
├── docker-compose.yml
|
||||||
|
├── Dockerfile
|
||||||
|
├── wsgi.py
|
||||||
|
├── data/ ← Datenbankverzeichnis (persistente SQLite-Datei, nicht im Image)
|
||||||
|
└── app/
|
||||||
|
├── __init__.py
|
||||||
|
├── config.py
|
||||||
|
├── database.py
|
||||||
|
├── models.py
|
||||||
|
├── auth.py
|
||||||
|
├── routes.py
|
||||||
|
├── templates/
|
||||||
|
└── static/
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
# Strukturelle Vorgaben – Quellcode-Konventionen
|
||||||
|
|
||||||
|
Dieses Dokument legt verbindliche Konventionen für alle Quelldateien im Projekt fest.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Datei-Header
|
||||||
|
|
||||||
|
Jede Quelldatei beginnt mit einem standardisierten Header. Der Header dient gleichzeitig als Modul-Docstring und wird von **Sphinx** zur automatischen Dokumentationserzeugung ausgewertet (Python-Äquivalent zu JavaDoc).
|
||||||
|
|
||||||
|
### Python (`.py`)
|
||||||
|
|
||||||
|
Der Header ist ein Modul-Docstring (triple-quoted) direkt am Dateianfang. Sphinx liest ihn automatisch aus:
|
||||||
|
|
||||||
|
```python
|
||||||
|
"""
|
||||||
|
<Einzeiliger Titel des Moduls>
|
||||||
|
|
||||||
|
<Optionale längere Beschreibung, was dieses Modul leistet, welche
|
||||||
|
Klassen/Funktionen es exportiert und welche Abhängigkeiten es hat.>
|
||||||
|
|
||||||
|
:author: Vorname Nachname <email@beispiel.de>
|
||||||
|
:date: YYYY-MM-DD
|
||||||
|
:version: 1.0
|
||||||
|
"""
|
||||||
|
```
|
||||||
|
|
||||||
|
Pflichtfelder: `:author:`, `:date:`
|
||||||
|
Optionale Felder: `:version:`, `:see:`, `:note:`
|
||||||
|
|
||||||
|
### Jinja2 / HTML (`.html`)
|
||||||
|
|
||||||
|
Jinja2-Kommentare (`{# ... #}`) werden vom Browser nicht gerendert und sind deshalb die richtige Wahl für Template-Header:
|
||||||
|
|
||||||
|
```html
|
||||||
|
{#
|
||||||
|
Datei: templates/beispiel.html
|
||||||
|
Autor: Vorname Nachname <email@beispiel.de>
|
||||||
|
Datum: YYYY-MM-DD
|
||||||
|
Zweck: Kurze Beschreibung, welche Seite/Komponente dieses Template rendert
|
||||||
|
und welche Jinja2-Variablen es erwartet.
|
||||||
|
#}
|
||||||
|
```
|
||||||
|
|
||||||
|
Pflichtfelder: `Datei:`, `Autor:`, `Datum:`, `Zweck:`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Dokumentationserzeugung mit Sphinx
|
||||||
|
|
||||||
|
Python bietet mit **Sphinx** ein mächtiges Werkzeug analog zu JavaDoc. Es liest Modul-Docstrings (inkl. `:author:`/`:date:`-Felder) und erzeugt daraus eine vollständige HTML-Dokumentation.
|
||||||
|
|
||||||
|
### Einrichtung (einmalig)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install sphinx
|
||||||
|
cd docs/
|
||||||
|
sphinx-quickstart # Interaktiver Setup-Assistent
|
||||||
|
```
|
||||||
|
|
||||||
|
Im Setup-Assistenten:
|
||||||
|
- `autodoc` aktivieren (liest Docstrings automatisch)
|
||||||
|
- Projektname, Autor und Version eingeben
|
||||||
|
|
||||||
|
Anschließend in `docs/conf.py` sicherstellen:
|
||||||
|
|
||||||
|
```python
|
||||||
|
extensions = [
|
||||||
|
"sphinx.ext.autodoc",
|
||||||
|
"sphinx.ext.viewcode", # Links zum Quellcode
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dokumentation aus dem `app/`-Verzeichnis einlesen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sphinx-apidoc -o docs/source/ app/
|
||||||
|
```
|
||||||
|
|
||||||
|
Dieser Befehl scannt alle `.py`-Dateien unter `app/` und erzeugt `.rst`-Stub-Dateien, die den Modul-Docstring und alle Klassen/Funktionen einbinden.
|
||||||
|
|
||||||
|
### Dokumentation bauen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd docs/
|
||||||
|
make html
|
||||||
|
# Ergebnis liegt unter: docs/_build/html/index.html
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ablauf
|
||||||
|
|
||||||
|
```
|
||||||
|
Modul-Docstrings → sphinx-apidoc → .rst-Dateien → make html → HTML-Doku
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Hinweis:** Für HTML-Templates gibt es kein Python-natives Doku-Tool. Die Header-Kommentare dienen dort als Inline-Dokumentation für Entwickler.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Template-Dateien
|
||||||
|
|
||||||
|
Im Verzeichnis [`_templates/`](_templates/) liegen Vorlagen, von denen sich der Entwickler **jederzeit eine frische Kopie ziehen** kann:
|
||||||
|
|
||||||
|
| Template | Verwendung |
|
||||||
|
|---|---|
|
||||||
|
| [`_templates/_template.py`](_templates/_template.py) | Neue Python-Quelldatei |
|
||||||
|
| [`_templates/_template.html`](_templates/_template.html) | Neues Jinja2/HTML-Template |
|
||||||
|
|
||||||
|
### Workflow: neue Datei aus Template erzeugen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Python-Datei
|
||||||
|
cp _templates/_template.py app/mein_modul.py
|
||||||
|
|
||||||
|
# HTML-Template
|
||||||
|
cp _templates/_template.html app/templates/meine_seite.html
|
||||||
|
```
|
||||||
|
|
||||||
|
Anschließend im kopierten File die Platzhalter (`<...>`) ersetzen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Kurzreferenz – Pflichtfelder auf einen Blick
|
||||||
|
|
||||||
|
| Feldname | Python (Docstring) | HTML (Kommentar) | Pflicht |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Autor | `:author:` | `Autor:` | Ja |
|
||||||
|
| Datum | `:date:` | `Datum:` | Ja |
|
||||||
|
| Zweck/Titel | Erste Docstring-Zeile | `Zweck:` | Ja |
|
||||||
|
| Version | `:version:` | – | Nein |
|
||||||
|
| Dateiname | – | `Datei:` | Ja |
|
||||||
Reference in new issue
Block a user