Initial commit: Konzept v2 + Etappe 1 (Blueprints + Login + Profile)
Schwester-Projekt zu arduino.lehrstun.de fuer die 3D-Druck-AG am Lessing-Gymnasium. Offene jahrelange Nachmittags-AG (kein Trimester), 8-10 Einzel-SuS mit optionalen 2er-Paarungen, 4 Bambu-Lab-Drucker (3 geschlossen + 1 A1 mini). Konzept v2 (Reality-Check-Iteration 2026-05-24): - Onboarding-Pfad statt Pflicht-Lektionen (L1-L3 selbst-zertifiziert) - Selbstlern-Loop als Kern: SuS-Projekte wachsen die interne Bibliothek - Drill-Down-Lehrer-Dashboard (Wer ist hier / Wartet Review / Haengt fest) - Cockpit progressiv: zeigt nur was zum Status passt - Bambu-Cloud-API fuer Drucker-Live-Status (fragil + Fallback manuell) - Three.js-Vorschau fuer Cover-aus-3D-Ansicht (Etappe 6) - Vollstaendige Doku als Obsidian-Vault (24 Markdown-Dateien) - Entscheidungen E-001 bis E-022 in docs/decisions.md Etappe 1 lauffaehig (~1800 Zeilen Code): - Blueprint-Struktur (V8): routes/oeffentlich+profil+admin+api, services/auth+bambu+datei - Komplettes Schema in database.py (14 Tabellen, idempotent) - Login mit bcrypt + persistentem Lockout in DB (V7, verbessert ggue Arduino-Kurs der In-Memory-Dict nutzt) - Admin-Login + Profile-CRUD + PIN-Reset + PIN-Karten-Druckbogen - Inline-Edit-Endpunkt mit Whitelist + Audit-Log - Seeds: AG lessing-3d-ag + 4 Drucker + Default-Einstellungen - Smoke-Test bestanden (Login, Profil-Anlage, Lockout-Logging) Nicht im Repo (.gitignore): .env, *.db, venv/, .obsidian/workspace.json
This commit is contained in:
126
docs/routen.md
Normal file
126
docs/routen.md
Normal file
@@ -0,0 +1,126 @@
|
||||
---
|
||||
type: konzept-modul
|
||||
projekt: 3d.lehrstun.de
|
||||
stand: 2026-05-24
|
||||
tags: [konzept, routen, api]
|
||||
---
|
||||
|
||||
# Routen
|
||||
|
||||
> Vollständige Routen-Liste. Live im Code: `app.py` + `routes/*.py` (V8: Blueprint-Struktur, siehe [[../decisions#E-020]]).
|
||||
> Welche Etappe was baut: [[etappen]]. Selbstlern-Loop-Details: [[selbstlern-loop]]. Lehrer-Dashboard: [[lehrer-dashboard]].
|
||||
|
||||
## Blueprint-Aufteilung (V8)
|
||||
|
||||
| Blueprint-Datei | URL-Präfix | Inhalt |
|
||||
|---|---|---|
|
||||
| `routes/oeffentlich.py` | `/` (kein Präfix) | Startseite, Lektionen, Software, Projekt-Katalog, Drucker, Troubleshooting |
|
||||
| `routes/profil.py` | `/cockpit`, `/login` | Login, Cockpit, Projekt-Workflow, Slots, Druckaufträge |
|
||||
| `routes/admin.py` | `/admin` | Dashboard, Profile, Lektionen, Projekt-Freigabe, Inline-Edit |
|
||||
| `routes/api.py` | `/api` | JSON-Endpunkte für Frontend-Polling |
|
||||
| `services/bambu.py` | (kein HTTP) | Bambu-Cloud-API-Wrapper, isoliert für späteren Austausch |
|
||||
| `services/datei.py` | (kein HTTP) | File-BLOB-Handling, abstrahiert für spätere Object-Storage-Migration |
|
||||
|
||||
## Öffentlich (`routes/oeffentlich.py`)
|
||||
|
||||
| Methode | Pfad | Zweck | Etappe |
|
||||
|---|---|---|---|
|
||||
| GET | `/` | Startseite | ✓ skelett |
|
||||
| GET | `/lektionen` | Onboarding-Pfad + freie Module | 3 |
|
||||
| GET | `/lektion/<nr>` | Einzelne Lektion | 3 |
|
||||
| GET | `/software` | Software-Tools | 3 |
|
||||
| GET | `/software/<slug>` | Software-Detail | 3 |
|
||||
| GET | `/projekte` | **Projekt-Katalog** (mit Filter: tag, level, erfolg, macher) | 6 |
|
||||
| GET | `/projekte/<id>` | Projekt-Detail (Cover, Beschreibung, Files, Bewertung, Macher) | 6 |
|
||||
| GET | `/projekte/datei/<id>` | Datei-Download (mit Auth-Check, sichtbar_in_ag prüfen) | 6 |
|
||||
| GET | `/troubleshooting` | Entscheidungsbaum + Suchliste | 3 |
|
||||
| GET | `/drucker` | 4 Drucker live | 5 |
|
||||
|
||||
## Profil (`routes/profil.py` — eingeloggt)
|
||||
|
||||
| Methode | Pfad | Zweck | Etappe |
|
||||
|---|---|---|---|
|
||||
| GET | `/login` | Profil-Kacheln (Vorname + Tier) | 1 |
|
||||
| POST | `/login/<profil_id>` | PIN-Eingabe (Rate-Limit + persistenter Lockout) | 1 |
|
||||
| GET | `/logout` | Abmelden | 1 |
|
||||
| GET | `/cockpit` | **Progressiv** (V1): zeigt nur was zum Status passt | 2 |
|
||||
| POST | `/cockpit/check-in` | Stunden-Beginn-Abfrage (V3: 1 Radio, 1 optionaler Freitext, "weiter wie bisher" als Default) | 2 |
|
||||
| POST | `/cockpit/lektion/<nr>/status` | Onboarding-Lektion als fertig/läuft markieren (V2-relevant) | 3 |
|
||||
| GET | `/cockpit/projekt/neu` | Projekt anlegen (mit Vorlage-Auswahl aus Katalog) | 6 |
|
||||
| POST | `/cockpit/projekt/neu` | Speichern | 6 |
|
||||
| POST | `/cockpit/projekt/<id>/edit` | Projekt-Details anpassen (während `in_arbeit`) | 6 |
|
||||
| GET | `/cockpit/projekt/<id>/abschluss` | **Abschluss-Checkliste** (V4: 3 Pflicht-Felder) | 6 |
|
||||
| POST | `/cockpit/projekt/<id>/abschluss` | Abschluss absenden → Status `wartet_auf_freigabe` | 6 |
|
||||
| POST | `/cockpit/projekt/<id>/datei` | Datei hochladen (30 MB Limit) | 6 |
|
||||
| POST | `/cockpit/projekt/<id>/datei/<dateiid>/loeschen` | Eigene Datei entfernen | 6 |
|
||||
| POST | `/cockpit/projekt/<id>/rueckfrage/<rid>/erledigt` | Rückfrage als erledigt markieren (V6) | 6 |
|
||||
| GET | `/cockpit/druckauftraege` | Eigene Auftragsliste | 7 |
|
||||
| POST | `/cockpit/druckauftrag/neu` | Auftrag eintragen | 7 |
|
||||
| GET | `/cockpit/slots` | Slot-Kalender (eigene + freie) — **gesperrt bis L1 fertig** (V2) | 6 |
|
||||
| POST | `/cockpit/slot/reservieren` | Neuen Slot buchen — gesperrt bis L1 fertig | 6 |
|
||||
| POST | `/cockpit/slot/<id>/stornieren` | Slot zurückgeben | 6 |
|
||||
| POST | `/cockpit/paarung/anfragen/<andere_id>` | Paar-Anfrage | 2 |
|
||||
| POST | `/cockpit/paarung/aufloesen` | Paar trennen | 2 |
|
||||
|
||||
## Admin (`routes/admin.py` — Herb + Markus)
|
||||
|
||||
| Methode | Pfad | Zweck | Etappe |
|
||||
|---|---|---|---|
|
||||
| GET | `/admin/login` | Passwort-Eingabe | 1 |
|
||||
| GET | `/admin/dashboard` | **Drill-Down** (V5): „Wer ist heute hier / Wartet auf Review / Wer hängt fest" | 2 |
|
||||
| GET | `/admin/profile` | Liste + Edit | 1 |
|
||||
| POST | `/admin/profil/neu` | Neues SuS-Profil + PIN-Generation | 1 |
|
||||
| GET | `/admin/profile/karten` | Druckbogen PIN-Karten (CSS-Print) | 1 |
|
||||
| GET | `/admin/projekt-freigabe` | **Review-Queue** mit Badge im Dashboard | 6 |
|
||||
| GET | `/admin/projekt-freigabe/<id>` | Detail-Review mit Three.js-Vorschau + Edit-Möglichkeit | 6 |
|
||||
| POST | `/admin/projekt/<id>/freigeben` | Projekt freigeben (mit optionaler Eigenbearbeitung) | 6 |
|
||||
| POST | `/admin/projekt/<id>/rueckfrage` | Rückfrage stellen → Status `rueckfrage` + Notiz im Cockpit | 6 |
|
||||
| POST | `/admin/projekt/<id>/loeschen` | **Hartes Löschen** mit Bestätigung (Audit-Log behält Datum + Lehrer + SuS-Name) | 6 |
|
||||
| POST | `/admin/projekt/<id>/datei-aus-3d` | Three.js-Screenshot als Cover speichern (von Detail-Review aus) | 6 |
|
||||
| GET | `/admin/druckauftraege` | Queue + Freigabe-UI | 7 |
|
||||
| POST | `/admin/druckauftrag/<id>/freigeben` | Lange Drucke explizit freigeben | 7 |
|
||||
| POST | `/admin/slot/<id>/prioritaet` | Slot-Priorität setzen | 6 |
|
||||
| POST | `/admin/slot/<id>/verschieben` | Slot bei Drucker-Ausfall auf anderen Drucker | 6 |
|
||||
| GET | `/admin/drucker` | Drucker-Stammdaten + manueller Status | 5 |
|
||||
| POST | `/admin/drucker/<id>/manueller_status` | Override bei API-Ausfall | 5 |
|
||||
| GET/POST | `/admin/lektionen` | Lektionen-CRUD | 3 |
|
||||
| GET | `/admin/einstellungen` | Konfig-Werte (auch Tag-Vorschläge) | 1 |
|
||||
| POST | `/admin/inline-edit` | Universal-Endpoint für Inline-Edit (Whitelist!) | 1 |
|
||||
|
||||
## API (`routes/api.py` — JSON für Frontend-Polling)
|
||||
|
||||
| Methode | Pfad | Liefert | Frequenz |
|
||||
|---|---|---|---|
|
||||
| GET | `/api/drucker/status` | JSON aller 4 Drucker mit Status/Restzeit | alle 30 s im Frontend |
|
||||
| GET | `/api/slots/heute` | JSON aller aktiven/anstehenden Slots heute | alle 60 s |
|
||||
| GET | `/api/projekte/suche?q=...&tag=...&erfolg=...` | Projekt-Filter-Ergebnis als JSON (für Live-Suche im Katalog) | on-demand |
|
||||
| GET | `/api/admin/dashboard-zahlen` | Badge-Zahlen für Admin-Dashboard | beim Page-Load |
|
||||
|
||||
## Inline-Edit-Whitelist (`ERLAUBTE_INLINE_TABELLEN`)
|
||||
|
||||
Pattern aus Arduino-Kurs (`app.py:~1530-1550`). Pro Tabelle und Feld definiert, was editiert werden darf.
|
||||
|
||||
```python
|
||||
ERLAUBTE_INLINE_TABELLEN = {
|
||||
"lektion": {"titel", "aufgabe_md", "tipp_md", "extern_link"},
|
||||
"projekt": {"titel", "beschreibung_md", "tags"}, # bei Lehrer-Review zusätzlich
|
||||
"einstellung": {"wert"},
|
||||
"software_seite": {"titel", "inhalt_md", "url", "quickstart_md"},
|
||||
"drucker": {"name", "notiz"},
|
||||
}
|
||||
|
||||
# Zeitliche Begrenzung beim Projekt: Lehrer darf alle Felder editieren,
|
||||
# aber nur wenn projekt.freigabe_status IN ('wartet_auf_freigabe', 'rueckfrage')
|
||||
```
|
||||
|
||||
Jede Änderung loggt in `aenderung_log` (Tabelle, Datensatz-ID, Feld, alter Wert, neuer Wert, Lehrer-Profil-ID).
|
||||
|
||||
## Sicherheit
|
||||
|
||||
- Admin-Routen via `@admin_required`-Decorator (Passwort aus `.env`).
|
||||
- Profil-Routen via `@login_required` (Session-basiert).
|
||||
- Slot-Buchung zusätzlich via `@onboarding_l1_fertig` (V2).
|
||||
- Inline-Edit-POST mit CSRF-Token.
|
||||
- Login: persistenter Lockout über `login_lockout`-Tabelle (V7). Fenster: 5 Versuche / 5 Min, danach 15 Min Sperre.
|
||||
- Datei-Download nur wenn `sichtbar_in_ag=1` und SuS eingeloggt; Lehrer sieht immer alles.
|
||||
- Hartes Löschen (V3-Aktion) mit Audit-Log (Datum, Lehrer, SuS, Grund optional) — Dateien sind danach weg.
|
||||
Reference in New Issue
Block a user