Files
Vorrania/ios/README.md
T
ScarriffleandClaude Opus 5 3d0ff54bf5 Anmeldung wahlweise ueber OpenID Connect (Authentik)
Neben dem Passwort-Login gibt es jetzt einen zweiten, gleichberechtigten Weg:
OpenID Connect gegen einen selbst gehosteten Anmeldedienst. Ohne Konfiguration
aendert sich nichts - keine SSO-Knoepfe, Passwort-Login wie bisher.

Der Anmeldedienst ist NUR fuer die Anmeldung zustaendig. Danach stellt Vorrania
sein eigenes Token aus wie beim Passwort-Login, deshalb bleiben deps.py, die
Rollenpruefung und die langlebigen API-Tokens unveraendert.

Backend
- Anbieter kommen aus der Umgebung (OIDC_PROVIDERS + OIDC_<KUERZEL>_*). Ein
  zweiter Anbieter ist damit reine Konfiguration, ohne Codeaenderung.
- Browser-Weg (vertraulicher Client) und App-Weg (oeffentlicher Client, PKCE)
  enden beide im selben Token-Schema.
- state/nonce/PKCE-Verifier liegen in einer kurzlebigen Tabelle statt in einem
  Cookie: Starlettes CORS-Schicht spiegelt bei allow_origins=["*"] zusammen mit
  allow_credentials die Herkunft zurueck, sobald ein Request ein Cookie traegt.
  Ohne Cookie entsteht diese Wechselwirkung erst gar nicht - und der Ablauf
  bleibt mit der db-Fixture pruefbar.
- Zuordnung ueber die sub des Anbieters; die Erstverknuepfung laeuft ueber die
  BESTAETIGTE E-Mail-Adresse. Rollen kommen nie aus dem Anbieter, und ein
  gleichlautender preferred_username uebernimmt nie ein bestehendes Konto.
- users.password_hash darf jetzt leer sein (reine SSO-Konten). verify_password
  faengt das ab, sonst antwortete der Login mit 500 statt 401.

Verknuepfen bestehender Konten
- Neue Seite "Mein Konto" (fuer alle Benutzer, nicht nur Admins): verknuepfen
  und wieder loesen. Die Berechtigung stammt aus der laufenden Sitzung, es
  braucht also weder eine hinterlegte Adresse noch Admin-Rechte.
- Der Start laeuft ueber POST, weil eine Seitennavigation das Bearer-Token
  nicht mitschicken kann.
- Die letzte Anmeldemoeglichkeit eines Kontos laesst sich nicht loesen.

iOS
- AppAuth (erste Paketabhaengigkeit) mit PKCE im System-Browser, nie in einem
  eingebetteten WebView, und ohne Client-Secret.
- offline_access nur im App-Weg: der Browser-Weg braucht kein Refresh-Token und
  bekaeme sonst einen ueberfluessigen Zustimmungsdialog.
- Anmeldezustand je Serverprofil im Keychain; abgelaufene Token erneuert die App
  still im Hintergrund. Gleichzeitige 401er teilen sich eine Erneuerung.

Deployment
- docker-compose reicht die ganze .env durch. Einzeln aufzuzaehlen ginge nur mit
  fest verdrahteten Kuerzeln - genau das soll ein weiterer Anbieter nicht
  erfordern.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 21:55:38 +02:00

106 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Vorrania – iOS-App
Native SwiftUI-App für Lebensmittel **und** Gegenstände. Sie spricht dieselbe
REST-API wie die Web-Oberfläche.
> **Stand:** Voll nutzbar. Login; Scannen von Barcode, MHD/Datum (per
> Texterkennung, auch nur Tag+Monat ohne Jahr), Lagerort-QR und Name/Marke;
> Ein-/Auslagern mit mehreren Chargen bzw. Menge je Lagerort; Einzelstücke mit
> UID/QR, Kaufdatum, Garantie und Beleg; Verbrauchsgegenstände als Charge;
> Artikel anlegen (Open Food/Products Facts oder manuell, mit Foto); getrennte
> Listen für Lebensmittel/Gegenstände/Einzelstücke, Kategoriefilter, Sortierung;
> Einkaufsliste, Ablaufliste, Mindestbestände; Verlauf mit Sprung zum Produkt;
> lokale Dashboards und Push-Benachrichtigungen bei ablaufenden Produkten.
## Projekt in Xcode öffnen
### Variante A – mit XcodeGen (empfohlen)
```bash
brew install xcodegen
cd ios
xcodegen generate
open Vorrania.xcodeproj
```
`project.yml` beschreibt das Projekt vollständig (Bundle-ID, Info.plist,
Shortcuts, URL-Schema).
### Variante B – ohne XcodeGen
1. Xcode → *File ▸ New ▸ Project…* → **App**, Interface **SwiftUI**, Sprache **Swift**
2. Produktname `Vorrania`, Bundle-ID z. B. `com.scarriffle.vorrania`
3. Die von Xcode erzeugte `ContentView.swift` und `…App.swift` löschen
4. Den Ordner `Sources/` per Drag & Drop ins Projekt ziehen („Copy items if needed")
5. In den Target-Einstellungen die mitgelieferte `Sources/Info.plist` als Info.plist setzen
(*Build Settings ▸ Info.plist File*) und *Generate Info.plist File* auf **No** stellen
## Auf dem iPhone installieren
1. iPhone per Kabel verbinden, in Xcode als Ziel auswählen
2. *Signing & Capabilities* → dein Apple-Developer-Team wählen
3. ▶︎ Run. Beim ersten Start auf dem iPhone unter
*Einstellungen ▸ Allgemein ▸ VPN & Geräteverwaltung* dem Entwickler vertrauen
## Erste Schritte in der App
Beim Start nach der Server-Adresse fragen lassen, z. B. `http://192.168.1.50:8080`
(dieselbe Adresse wie im Browser), dann mit deinem Benutzer anmelden. Adresse und
Token bleiben gespeichert – das Token liegt im Keychain.
Hat der Server einen Anmeldedienst eingerichtet (Single Sign-on, siehe
[../README.md](../README.md#single-sign-on-optional)), erscheint darunter ein
Knopf „Mit … anmelden". Die Anmeldung läuft dann im System-Browser (AppAuth mit
PKCE, kein eingebettetes WebView); der Anmeldezustand samt Refresh-Token liegt
je Serverprofil getrennt im Keychain, und die App erneuert ein abgelaufenes
Token still im Hintergrund.
## Home-Screen-Shortcuts
Es gibt zwei Wege direkt in den Scan-Bildschirm:
**Schnellaktionen** – langer Druck auf das App-Symbol zeigt „Einlagern" und
„Auslagern" (funktioniert ohne weitere Einrichtung).
**Eigene Symbole auf dem Home-Bildschirm** – über die Apple-App *Kurzbefehle*:
1. Kurzbefehle ▸ **+** ▸ Aktion *URL öffnen*
2. URL `vorrania://checkin` (bzw. `vorrania://checkout`) eintragen
3. Kurzbefehl benennen, dann ▸ *Zum Home-Bildschirm hinzufügen*
Beide Wege öffnen die App **direkt in der Kamera**.
## Aufbau der Quellen
| Datei | Inhalt |
|---|---|
| `VorraniaApp.swift` | App-Einstieg, Schnellaktionen, URL-Schema |
| `Session.swift` | Server-Adresse (UserDefaults) und Token (Keychain) |
| `APIClient.swift` | REST-Aufrufe gegen `/api/...` |
| `Models.swift` | Codable-Typen passend zu `backend/app/schemas.py` |
| `ScannerView.swift` | Kamera + Barcode-Erkennung (EAN-8/13, UPC-E, Code128, QR) |
| `RootView.swift` | Startbildschirm und Routing |
| `LoginView.swift` | Server + Anmeldung |
| `CheckInView.swift` / `CheckInFormView.swift` | Scan → Charge (MHD), Menge je Lagerort oder Einzelstück |
| `CheckOutView.swift` | Scan → Menge, Chargenauswahl oder FEFO |
| `ProductViews.swift` | Artikelsuche und Anlegen (mit OFF-Vorbefüllung, Foto, Text-Scan) |
| `ProductDetailView.swift` | Produkt bearbeiten, Verwaltungsart ändern, Chargen korrigieren |
| `ObjectStockView.swift` | Gegenstände: Menge je Lagerort (hinzufügen/umlagern/entfernen) |
| `ItemViews.swift` / `ItemListView.swift` | Einzelstücke anlegen, bearbeiten und auflisten |
| `AssignScanView.swift` | Einzelstück (Scan oder Liste) einem Lagerort-QR zuordnen |
| `ListViews.swift` | Produktlisten, Einkaufsliste, „bald ablaufend", Mindestbestände |
| `DashboardView.swift` / `DashboardCards.swift` / `ChartCards.swift` | Übersicht mit Karten und Diagrammen |
| `NotificationScheduler.swift` / `NotificationSettings*.swift` | Push-Benachrichtigungen bei Ablauf |
| `DateScanView.swift` / `BestBeforeText.swift` | MHD/Text per Texterkennung ablesen |
| `DisplaySettings.swift` | Datumsformat und Einheiten-Beschriftungen vom Server |
| `CategoryPicker.swift` | Kategorie-Auswahl und Gruppe anlegen |
## Gruppe und Kategorie – zwei verschiedene Dinge
**Gruppe** dient der *Bestandsrechnung*: Mehl von Rewe, Aldi und Migros zählen
zusammen, wichtig ist „ich habe 5 kg Mehl“. Eine Gruppe hat deshalb einen
gemeinsamen Mindestbestand mit Einheit und EAN-Codes. Ordnest du einen Artikel
einer Gruppe zu, erscheint sein EAN-Code automatisch dort; wechselt er die
Gruppe, wandert der Code mit.
**Kategorie** dient *allein dem Überblick* („Süßwaren“, „Molkereiprodukte“) und
ist verschachtelbar wie ein Lagerort (Süßwaren → Schokolade). Sie hat keinen
Bestand, keinen Mindestbestand und keine EAN-Codes. Filterst du auf eine
Oberkategorie, erscheinen die Artikel ihrer Unterkategorien mit. Beim Anlegen
schlägt der Server eine Kategorie aus der Open-Food-Facts-Einordnung vor.
## Weiteres
Push-Benachrichtigungen bei Ablauf und Lagerort je Charge beim Einlagern sind
umgesetzt. Weitere Ideen stehen in [../docs/ROADMAP.md](../docs/ROADMAP.md).