Bringt das Backend vom initialen Skeleton auf den aktuellen Arbeitsstand (Clean Architecture: domain → application → infrastructure → api). Wesentliche Bereiche: - ERP-Anbindung (MSSQL-Pull der Touren, Import-Scheduler, Rückschreiben) - Lieferlebenszyklus: Scan/Hold/Cancel/Complete, Gutschriften, Notizen, Bild-Anhänge, Unterschriften, PDF-Lieferreport → DOCUframe - Stammdaten: Kunden, Artikel, Lager, Zahlungsarten, Services - Keycloak-JWT-Gate + Fahrer-Provisionierung via Admin-API - Admin-API-Key-Gate (X-Admin-Api-Key) für Maschinen-Endpunkte Jüngste Änderungen dieser Session: - Belegspezifische Kontaktdaten: alle ERP-Adressen (Beleg-/Liefer-/ Rechnungsadresse, Ansprechpartner, Kundenstamm) mit Telefon/Mobil/ E-Mail werden gesynct (Migration 0029, MSSQL-Query, TourDetails) - Konfiguration von .env (envy/dotenvy) auf config.toml (toml/serde) umgestellt; Vorlage config.example.toml, Pfad via HOLZLEITNER_CONFIG Nicht im Repo (per .gitignore): config.toml (Secrets), data/ (Laufzeit-/ Kundendaten), demo.mp4, .claude/, variocontrol-ai/. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
115 lines
3.9 KiB
Markdown
115 lines
3.9 KiB
Markdown
# Holzleitner-Backend
|
|
|
|
Rust-Backend für die Holzleitner-Lieferservice-App. Workspace mit Clean
|
|
Architecture: `domain` → `application` → `infrastructure` → `api`.
|
|
|
|
## Schnellstart (lokale Entwicklung)
|
|
|
|
```bash
|
|
# 1) Postgres + Keycloak hochfahren
|
|
docker compose up -d
|
|
# Keycloak braucht ~30s bis "Listening on http://0.0.0.0:8080" im Log steht.
|
|
|
|
# 2) Konfiguration vorbereiten
|
|
cp config.example.toml config.toml
|
|
# Werte in config.toml anpassen (DB-URL, Keycloak-Issuer, ERP-Zugang, …).
|
|
|
|
# 3) Backend starten
|
|
cargo run -p holzleitner-api
|
|
```
|
|
|
|
Migrations laufen beim Start automatisch über `sqlx::migrate!`.
|
|
Smoke-Test danach:
|
|
|
|
```bash
|
|
curl http://127.0.0.1:3000/health
|
|
# → ok
|
|
|
|
curl http://127.0.0.1:3000/accounts/1001
|
|
# → {"personalnummer":1001,"name":"Müller Logistik GmbH","active":true}
|
|
```
|
|
|
|
## Keycloak (Dev)
|
|
|
|
| Wo | URL / Credentials |
|
|
|---|---|
|
|
| Admin-Console | http://localhost:8080/admin/ (admin / admin) |
|
|
| Realm | `holzleitner` |
|
|
| Client | `holzleitner-app` (public, PKCE) |
|
|
| Test-User | `testfahrer` / `test` · Personalnummer 1001 · Rolle `driver` |
|
|
| Audience im Access-Token | `holzleitner-api` |
|
|
|
|
Der Realm wird bei jedem `docker compose up` aus
|
|
`keycloak/import/realm-holzleitner.json` frisch importiert. Wer in der
|
|
Admin-UI Änderungen macht, sollte sie **in die JSON zurückspielen**,
|
|
sonst sind sie beim nächsten `docker compose down` weg.
|
|
|
|
### Token für Dev-Tests holen
|
|
|
|
```bash
|
|
curl -s -X POST \
|
|
http://localhost:8080/realms/holzleitner/protocol/openid-connect/token \
|
|
-d 'grant_type=password' \
|
|
-d 'client_id=holzleitner-app' \
|
|
-d 'username=testfahrer' \
|
|
-d 'password=test' | jq -r .access_token
|
|
```
|
|
|
|
Den Token in den `Authorization`-Header packen, sobald die JWT-Middleware
|
|
in der API-Schicht aktiv ist:
|
|
|
|
```bash
|
|
TOKEN=$(curl -s -X POST .../token -d ... | jq -r .access_token)
|
|
curl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:3000/accounts/1001
|
|
```
|
|
|
|
## Crate-Layout
|
|
|
|
| Crate | Inhalt | Abhängigkeiten |
|
|
|---|---|---|
|
|
| `holzleitner-domain` | Reines Domänenmodell (serde + UUID + chrono) | — |
|
|
| `holzleitner-application` | Use Cases und Ports (Trait-Definitionen für Repository, AuthService) | `domain` |
|
|
| `holzleitner-infrastructure` | Konkrete Adapter (sqlx-Postgres, später Keycloak) | `domain`, `application` |
|
|
| `holzleitner-api` | Axum HTTP-Layer + Composition Root | alle |
|
|
|
|
## Konfiguration
|
|
|
|
Werte werden aus `config.toml` gelesen (Vorlage: `config.example.toml`),
|
|
gruppiert in TOML-Sections. Der Dateipfad ist über die Env-Variable
|
|
`HOLZLEITNER_CONFIG` überschreibbar (z. B. im Deployment); Default ist
|
|
`config.toml` im Arbeitsverzeichnis. Die echte `config.toml` enthält
|
|
Secrets und ist `.gitignore`-t.
|
|
|
|
| Section | Bereich | Pflicht? |
|
|
|---|---|---|
|
|
| `[server]` | Bind-Host/Port | ja |
|
|
| `[database]` | Postgres-URL, Pool-Größe | ja |
|
|
| `[keycloak]` | OIDC-Issuer, Audience, JWKS-Cache, Provisioning | ja |
|
|
| `[gsd]` | DOCUframe-REST (Datei-Upload) | ja |
|
|
| `[erp]` | ERPframe-MSSQL (Touren-Pull) | optional |
|
|
| `[import]` | Import-Scheduler (Cron, Offset) | optional |
|
|
| `[report]` / `[signature]` / `[attachment]` | Lokale Speicher-Pfade | optional |
|
|
| `[dev]` | `today_override`, `sync_enabled` (DEV-ONLY) | optional |
|
|
| `[admin]` | `api_key` für das `/admin`-Gate | optional |
|
|
| `[logging]` | Log-Filter (Default; `RUST_LOG`-Env hat Vorrang) | optional |
|
|
|
|
Unbekannte Schlüssel werden beim Laden abgewiesen (`deny_unknown_fields`),
|
|
sodass Tippfehler sofort als Startfehler auffallen.
|
|
|
|
## Migrations
|
|
|
|
Migrations liegen im Workspace-Root `migrations/`. Eingebettet via
|
|
`sqlx::migrate!()` — kein zusätzlicher Laufzeit-Dateizugriff nötig.
|
|
Neue Migration anlegen:
|
|
|
|
```bash
|
|
# Format: <epoch>_<beschreibung>.sql, z.B.:
|
|
touch migrations/0002_tour.sql
|
|
```
|
|
|
|
## Logging
|
|
|
|
`tracing` + `tracing-subscriber` mit `EnvFilter`. Der Default-Filter steht
|
|
in `config.toml` unter `[logging] filter`; die Env-Variable `RUST_LOG` hat
|
|
Vorrang (Ad-hoc-Debugging ohne Datei-Edit, z. B. `RUST_LOG=debug cargo run`).
|