Initial: Rust-Backend mit Clean Architecture (domain/application/infrastructure/api)
Vier-Crate-Workspace mit:
- Domain: Account, Car, Tour, Delivery, DeliveryItem, DeliveryNote, Customer,
Article, Warehouse, ScanState, AuditAction — alle mit serde + feature-gated
utoipa::ToSchema.
- Application: Ports (TourRepository, DeliveryRepository, ScanRepository,
DeliveryNoteRepository, CarRepository, AuthService) und Use Cases.
- Infrastructure: Postgres-Adapter via sqlx (PgTourRepository etc.) +
Keycloak-AuthService mit JWKS-Cache + OIDC-Discovery.
- API: Axum 0.8, utoipa-OpenAPI + Swagger-UI, JWT-Bearer-Middleware,
AuthenticatedUser-Extractor.
Endpoints:
- GET /me/tours/today, /tours/{id}, /accounts/{pn}, /me/cars, /health
- POST /sync/tour, /scans (bulk + idempotent via clientScanId),
/deliveries/{id}/{hold,resume,cancel,complete,notes}, /me/cars
- PUT /tours/{id}/delivery-order, /deliveries/{id}/assigned-car, /me/cars/{id}
- PATCH /me/cars/{id}
Datenmodell:
- 6 Migrationen (accounts, tours/deliveries/items + Stammdaten,
scan_audit mit clientScanId-UNIQUE, state_reason refactor,
delivery_notes, cars + FKs nachziehen).
- Business-stabile Beleg-Keys (belegart_id, belegnummer) für ERP-Sync.
- Append-only scan_audit + embedded scan_state als doppelte Wahrheit.
Dev-Setup:
- docker-compose mit Postgres 17 + Keycloak 26
- Keycloak-Realm 'holzleitner' mit Public-Client (PKCE), Testfahrer
(PN 1001) + Audience-/Personalnummer-Mapper
This commit is contained in:
99
README.md
Normal file
99
README.md
Normal file
@ -0,0 +1,99 @@
|
||||
# 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) Env-Datei vorbereiten
|
||||
cp .env.example .env
|
||||
|
||||
# 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 Umgebungsvariablen gelesen (siehe `.env.example`),
|
||||
gruppiert nach Prefix:
|
||||
|
||||
| Prefix | Bereich |
|
||||
|---|---|
|
||||
| `SERVER_*` | Bind-Host/Port |
|
||||
| `DATABASE_*` | Postgres-URL, Pool-Größe |
|
||||
| `KEYCLOAK_*` | OIDC-Issuer, Audience, JWKS-Cache (greift erst in der Keycloak-Phase) |
|
||||
|
||||
## 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`. Default:
|
||||
`holzleitner_api=info,tower_http=info`. Override via `RUST_LOG`.
|
||||
Reference in New Issue
Block a user