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:
118
crates/api/src/openapi.rs
Normal file
118
crates/api/src/openapi.rs
Normal file
@ -0,0 +1,118 @@
|
||||
//! OpenAPI-Aggregation: zieht alle annotierten Handler und Schemata in
|
||||
//! ein einziges Dokument zusammen, das der `/openapi.json`-Endpoint
|
||||
//! serviert und Swagger-UI darstellt.
|
||||
//!
|
||||
//! Neue Endpoints werden hier in `paths(...)` registriert, neue Schemata
|
||||
//! in `components(schemas(...))`. Die Annotation am Handler (via
|
||||
//! `#[utoipa::path(...)]`) liefert die eigentliche Beschreibung.
|
||||
|
||||
use utoipa::Modify;
|
||||
use utoipa::OpenApi;
|
||||
use utoipa::openapi::security::{HttpAuthScheme, HttpBuilder, SecurityScheme};
|
||||
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
info(
|
||||
title = "Holzleitner Backend API",
|
||||
version = "0.1.0",
|
||||
description = "Backend für die Holzleitner-Lieferservice-App — Tour, Beladung, Ausführung."
|
||||
),
|
||||
paths(
|
||||
crate::routes::health::health,
|
||||
crate::routes::accounts::get_account,
|
||||
crate::routes::tours::list_my_tours_today,
|
||||
crate::routes::tours::get_tour,
|
||||
crate::routes::tours::set_delivery_order,
|
||||
crate::routes::tours::sync_tour,
|
||||
crate::routes::scans::apply_scans,
|
||||
crate::routes::deliveries::hold,
|
||||
crate::routes::deliveries::resume,
|
||||
crate::routes::deliveries::cancel,
|
||||
crate::routes::deliveries::complete,
|
||||
crate::routes::deliveries::create_note,
|
||||
crate::routes::deliveries::assign_car,
|
||||
crate::routes::cars::list_my_cars,
|
||||
crate::routes::cars::create_my_car,
|
||||
crate::routes::cars::update_my_car,
|
||||
),
|
||||
components(
|
||||
schemas(
|
||||
holzleitner_domain::Account,
|
||||
holzleitner_domain::Address,
|
||||
holzleitner_domain::Article,
|
||||
holzleitner_domain::AuditAction,
|
||||
holzleitner_domain::Car,
|
||||
holzleitner_domain::Customer,
|
||||
holzleitner_domain::CustomerContact,
|
||||
holzleitner_domain::Delivery,
|
||||
holzleitner_domain::DeliveryItem,
|
||||
holzleitner_domain::DeliveryNote,
|
||||
holzleitner_domain::DeliveryState,
|
||||
holzleitner_domain::ScanState,
|
||||
holzleitner_domain::ScanStatus,
|
||||
holzleitner_domain::Tour,
|
||||
holzleitner_domain::Warehouse,
|
||||
holzleitner_application::dto::TourDetails,
|
||||
holzleitner_application::dto::DeliveryWithItems,
|
||||
holzleitner_application::dto::TourSummary,
|
||||
holzleitner_application::dto::SyncTourRequest,
|
||||
holzleitner_application::dto::SyncDelivery,
|
||||
holzleitner_application::dto::SyncDeliveryItem,
|
||||
holzleitner_application::dto::SetDeliveryOrderRequest,
|
||||
holzleitner_application::dto::SetDeliveryOrderResponse,
|
||||
holzleitner_application::dto::DeliveryOrderEntry,
|
||||
holzleitner_application::dto::ApplyScansRequest,
|
||||
holzleitner_application::dto::ApplyScansResponse,
|
||||
holzleitner_application::dto::ScanEvent,
|
||||
holzleitner_application::dto::ScanResult,
|
||||
holzleitner_application::dto::ScanResultStatus,
|
||||
holzleitner_application::dto::HoldDeliveryRequest,
|
||||
holzleitner_application::dto::CancelDeliveryRequest,
|
||||
holzleitner_application::dto::DeliveryResponse,
|
||||
holzleitner_application::dto::CreateDeliveryNoteRequest,
|
||||
holzleitner_application::dto::DeliveryNoteResponse,
|
||||
holzleitner_application::dto::CreateCarRequest,
|
||||
holzleitner_application::dto::UpdateCarRequest,
|
||||
holzleitner_application::dto::CarResponse,
|
||||
holzleitner_application::dto::CarsList,
|
||||
holzleitner_application::dto::AssignCarRequest,
|
||||
crate::routes::tours::TourSummaryList,
|
||||
crate::routes::tours::SyncTourResponse,
|
||||
)
|
||||
),
|
||||
modifiers(&SecurityAddon),
|
||||
tags(
|
||||
(name = "health", description = "Health- und Status-Endpoints"),
|
||||
(name = "accounts", description = "Account-Stammdaten"),
|
||||
(name = "tours", description = "Touren der Fahrer"),
|
||||
(name = "sync", description = "ERP-Sync-Endpunkte"),
|
||||
(name = "scans", description = "Scan-Events (Beladung & Auslieferung)"),
|
||||
(name = "deliveries", description = "Delivery-Lifecycle (hold / resume / cancel / complete)"),
|
||||
(name = "cars", description = "Fahrzeug-Stammdaten pro Fahrer"),
|
||||
),
|
||||
security(
|
||||
("bearer_auth" = [])
|
||||
)
|
||||
)]
|
||||
pub struct ApiDoc;
|
||||
|
||||
/// Hängt das `bearer_auth`-Security-Scheme nachträglich in die Spec ein —
|
||||
/// das geht nur über einen `Modify`-Hook, weil derive-Macros das nicht
|
||||
/// direkt erlauben.
|
||||
struct SecurityAddon;
|
||||
|
||||
impl Modify for SecurityAddon {
|
||||
fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
|
||||
if let Some(components) = openapi.components.as_mut() {
|
||||
components.add_security_scheme(
|
||||
"bearer_auth",
|
||||
SecurityScheme::Http(
|
||||
HttpBuilder::new()
|
||||
.scheme(HttpAuthScheme::Bearer)
|
||||
.bearer_format("JWT")
|
||||
.build(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user