From 95d05ea8be6f337ff163e931610e38349d6bb0cf Mon Sep 17 00:00:00 2001 From: Maxim Strzebkowski Date: Tue, 30 Jun 2026 21:11:24 +0200 Subject: [PATCH 1/7] fix: align dapr subscription route with axum handler --- src/event/http_event_service.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/event/http_event_service.rs b/src/event/http_event_service.rs index 099a1b9..856d250 100644 --- a/src/event/http_event_service.rs +++ b/src/event/http_event_service.rs @@ -199,7 +199,7 @@ pub async fn list_topic_subscriptions() -> Result>, StatusCode> let pubsub_user = Pubsub { pubsubname: "pubsub".to_string(), topic: "user/user/created".to_string(), - route: "/on-id-creation-event".to_string(), + route: "/on-user-creation-event".to_string(), }; let pubsub_user_address = Pubsub { pubsubname: "pubsub".to_string(), From 766fd6fd001b8a8a936817122ca81211c1bc58e2 Mon Sep 17 00:00:00 2001 From: Maxim Strzebkowski Date: Wed, 1 Jul 2026 10:10:31 +0200 Subject: [PATCH 2/7] fix: missing camelCase conversion on UserEventData & VendorAddressEventData --- src/event/http_event_service.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/event/http_event_service.rs b/src/event/http_event_service.rs index 856d250..c01568f 100644 --- a/src/event/http_event_service.rs +++ b/src/event/http_event_service.rs @@ -42,6 +42,7 @@ pub struct Event { } #[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] /// Relevant part of vendor address creation event. pub struct VendorAddressEventData { /// Vendor address UUID. @@ -61,6 +62,7 @@ pub struct VendorAddressEventData { } #[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] /// Relevant part of user creation event data. pub struct UserEventData { /// User UUID. From ada3907b68746c69efb1addc96fff7218f29144d Mon Sep 17 00:00:00 2001 From: Maxim Strzebkowski Date: Fri, 3 Jul 2026 10:28:47 +0200 Subject: [PATCH 3/7] fix: use SCREAMING_SNAKE_CASE for OrderStatus and RejectionReason enums --- src/graphql/model/order.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/graphql/model/order.rs b/src/graphql/model/order.rs index 67f32d5..8007625 100644 --- a/src/graphql/model/order.rs +++ b/src/graphql/model/order.rs @@ -15,6 +15,7 @@ pub struct Order { /// Describes if order is placed, or yet pending. An order can be rejected during its lifetime. #[derive(Debug, Enum, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum OrderStatus { Pending, Placed, @@ -23,6 +24,7 @@ pub enum OrderStatus { /// Describes the reason why an order was rejected, in case of rejection: `OrderStatus::Rejected`. #[derive(Debug, Enum, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum RejectionReason { InvalidOrderData, InventoryReservationFailed, From 044c05c7dab540c01a0a73ae69f60113cee67414 Mon Sep 17 00:00:00 2001 From: Maxim Strzebkowski Date: Fri, 3 Jul 2026 13:17:01 +0200 Subject: [PATCH 4/7] fix: use correct MongoDB field name addresses for user address operations --- src/event/http_event_service.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/event/http_event_service.rs b/src/event/http_event_service.rs index c01568f..a887ef8 100644 --- a/src/event/http_event_service.rs +++ b/src/event/http_event_service.rs @@ -397,7 +397,7 @@ pub async fn insert_user_address_in_mongodb( match collection .update_one( doc! {"_id": user_address.user_id }, - doc! {"$push": {"user_addresses": user_address }}, + doc! {"$push": {"addresses": user_address }}, None, ) .await @@ -418,7 +418,7 @@ pub async fn remove_user_address_in_mongodb( match collection .update_one( doc! {"_id": user_address_event_data.user_id }, - doc! {"$pull": {"user_addresses._id": user_address_event_data.id }}, + doc! {"$pull": {"addresses._id": user_address_event_data.id }}, None, ) .await From 14d35203d202df4a5fc703079c6bb7adea00df6f Mon Sep 17 00:00:00 2001 From: Maxim Strzebkowski Date: Fri, 3 Jul 2026 13:25:05 +0200 Subject: [PATCH 5/7] add GHA cache for Docker layers in publish workflow --- .github/workflows/publish-image.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/publish-image.yaml b/.github/workflows/publish-image.yaml index ce977e0..b26bec1 100644 --- a/.github/workflows/publish-image.yaml +++ b/.github/workflows/publish-image.yaml @@ -56,3 +56,5 @@ jobs: push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max From 1243e593a3b73e881769b064bd4a517264d150b7 Mon Sep 17 00:00:00 2001 From: Maxim Strzebkowski Date: Fri, 3 Jul 2026 21:52:06 +0200 Subject: [PATCH 6/7] Added configurable logging & error logging --- Cargo.toml | 6 +++--- src/event/http_event_service.rs | 7 +++++-- src/main.rs | 5 +++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0c16b64..243d93f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,8 +6,8 @@ edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -async-graphql = { version = "7.0.16", features = ["bson", "chrono", "uuid", "log"] } -async-graphql-axum = "7.0.16" +async-graphql = { version = "7.0.17", features = ["bson", "chrono", "uuid", "log"] } +async-graphql-axum = "7.0.17" tokio = { version = "1.44.2", features = ["macros", "rt-multi-thread"] } hyper = "1.0.1" axum = { version = "0.8.3", features = ["macros"] } @@ -19,7 +19,7 @@ clap = { version = "4.5.37", features = ["derive"] } uuid = { version = "1.16.0", features = ["v4", "serde"] } json = "0.12.4" log = "0.4.27" -simple_logger = "5.0.0" +env_logger = "0.11" serde_json = "1.0.140" reqwest = { version = "0.12.15", features = ["json"] } chrono = { version = "0.4.40", features = ["serde"] } diff --git a/src/event/http_event_service.rs b/src/event/http_event_service.rs index a887ef8..0ee2837 100644 --- a/src/event/http_event_service.rs +++ b/src/event/http_event_service.rs @@ -1,7 +1,7 @@ use async_graphql::Result; use axum::{debug_handler, extract::State, http::StatusCode, Json}; use bson::{doc, Uuid}; -use log::info; +use log::{error, info}; use mongodb::{options::UpdateOptions, Collection}; use serde::{Deserialize, Serialize}; @@ -237,7 +237,10 @@ pub async fn on_discount_order_validation_succeeded_event( "discount/order/validation-succeeded" => { let invoice = Invoice::new(event.data.order.clone(), &state) .await - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + .map_err(|e| { + error!("Failed to create invoice: {:?}", e); + StatusCode::INTERNAL_SERVER_ERROR + })?; let invoice_dto = InvoiceDTO::from(invoice.clone()); let invoice_created_dto = InvoiceCreatedDTO::from((event.data.order, invoice_dto)); insert_invoice_in_mongodb(&state.invoice_collection, invoice).await?; diff --git a/src/main.rs b/src/main.rs index e7c3a04..fbac8cf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,7 +15,7 @@ use axum::{ }; use clap::{arg, command, Parser}; -use log::{info, Level}; +use log::info; use mongodb::{options::ClientOptions, Client, Database}; use once_cell::sync::Lazy; @@ -113,7 +113,8 @@ struct Args { /// Activates logger and parses argument for optional schema generation. Otherwise starts gRPC and GraphQL server. #[tokio::main] async fn main() -> std::io::Result<()> { - simple_logger::init_with_level(Level::Warn).unwrap(); + env_logger::init(); + info!("Invoice service starting"); let args = Args::parse(); if args.generate_schema { From 0159b8250b939df95d1c6beaabb73f931348f11a Mon Sep 17 00:00:00 2001 From: Maxim Strzebkowski Date: Sat, 4 Jul 2026 00:01:10 +0200 Subject: [PATCH 7/7] fix: log invoice creation failures per step and persist full vendor address on upsert --- src/event/http_event_service.rs | 10 +++++++++- src/graphql/model/invoice.rs | 19 ++++++++++++++----- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/event/http_event_service.rs b/src/event/http_event_service.rs index 0ee2837..240f978 100644 --- a/src/event/http_event_service.rs +++ b/src/event/http_event_service.rs @@ -379,7 +379,15 @@ pub async fn create_or_update_vendor_address_in_mongodb( match collection .update_one( doc! {"_id": vendor_address._id }, - doc! {"$set": {"_id": vendor_address._id}}, + doc! {"$set": { + "_id": vendor_address._id, + "street1": vendor_address.street1, + "street2": vendor_address.street2, + "city": vendor_address.city, + "postal_code": vendor_address.postal_code, + "country": vendor_address.country, + "company_name": vendor_address.company_name, + }}, update_options, ) .await diff --git a/src/graphql/model/invoice.rs b/src/graphql/model/invoice.rs index 064600a..3f0fcdc 100644 --- a/src/graphql/model/invoice.rs +++ b/src/graphql/model/invoice.rs @@ -1,5 +1,6 @@ use async_graphql::{Error, Result, SimpleObject}; use bson::{doc, DateTime, Uuid}; +use log::error; use mongodb::{options::FindOneOptions, Collection}; use serde::{Deserialize, Serialize}; @@ -122,10 +123,16 @@ async fn invoice_attribute_setup( let order_item_invoice_overview = build_order_item_invoice_content(order_event_data); let user_address_user = query_user_address_user(&state.user_collection, order_event_data.invoice_address_id) - .await?; - let user_address = project_user_to_user_address(user_address_user)?; - let vendor_address = query_vendor_address(&state.vendor_address_collection).await?; - let user = query_object(&state.user_collection, order_event_data.user_id).await?; + .await + .map_err(|e| { error!("step 1 query_user_address_user: {:?}", e); e })?; + let user_address = project_user_to_user_address(user_address_user) + .map_err(|e| { error!("step 2 project_user_to_user_address: {:?}", e); e })?; + let vendor_address = query_vendor_address(&state.vendor_address_collection) + .await + .map_err(|e| { error!("step 3 query_vendor_address: {:?}", e); e })?; + let user = query_object(&state.user_collection, order_event_data.user_id) + .await + .map_err(|e| { error!("step 4 query_object user: {:?}", e); e })?; Ok(( issued_at, issued_at_string, @@ -159,7 +166,9 @@ pub async fn query_user_address_user( let find_options = FindOneOptions::builder() .projection(Some(doc! { "addresses.$": 1, - "_id": 1 + "_id": 1, + "first_name": 1, + "last_name": 1, })) .build(); let message = format!("Address of UUID: `{}` not found.", address_id);