diff --git a/crates/evops-core/README.md b/crates/evops-core/README.md new file mode 100644 index 0000000..1c7092d --- /dev/null +++ b/crates/evops-core/README.md @@ -0,0 +1,47 @@ +# `evops-core` + +## Overview + +Acts as the application's source of truth, containing all core business logic and service integrations. This crate is reused by both `evops-rest` and `evops-grpc` to ensure consistent behavior across API boundaries. Orchestrates database operations (via `evops_db`), file storage (MinIO via `evops_storage`), and ML services (via `evops_ml_client`) + +### Core Mechanism + +1. **State Initialization** +During `AppState` construction the application is wiring together: + - Database connections + - Storage clients + - ML service integrations + +2. **API Layer Integration** + - REST: All endpoints inject AppState via axum's State mechanism + - gRPC: Service handlers hold shared references to AppState + +3. **Business Logic Execution** +Both REST controllers and gRPC services directly call `AppState` methods like `create_event()` + +### Key Files + +- `lib.rs`: +Initializes application state and dependencies + - Key components: + - Sets up API routes + - `AppState`: Shared application state (thread-safe via `Arc`) + - `State`: Internal struct holding: + - `evops_db::Database` + - `evops_storage::Storage` + - `evops_ml_client::MlClient` + +- `services.rs` +Aggregates service modules (event, language, tag, user) + +### Service Modules + +- `event.rs` +Handles event operations and image management + +- `user.rs` +Manages user accounts + +- `language.rs` +Currently placeholder implementation +Future use: Manage multilingual content diff --git a/crates/evops-grpc/README.md b/crates/evops-grpc/README.md new file mode 100644 index 0000000..806e049 --- /dev/null +++ b/crates/evops-grpc/README.md @@ -0,0 +1,126 @@ +# `evops-grpc` + +## Overview + +Provides gRPC API endpoints using `tonic` framework. Handles protocol buffer serialization, gRPC-web compatibility, and service implementations. Organized into: +- Protocol buffer definitions (`pb`) +- Service implementations (`services`) +- gRPC-specific utilities (`headers`) + +### Service Example + +Event Service (`services/event.rs`) +- Creating an event: +```rust +async fn create( + &self, + request: Request, +) -> Result, Status> { + let request_data = request.into_inner(); + + let form = { + request_data + .form + .ok_or(ApiError::InvalidArgument({ + "EventServiceCreateRequest.form must not be null.".to_owned() + }))? + .try_into()? + }; + let event_id = self.state.create_event(form).await?; + + let response_data = EventServiceCreateResponse { + event_id: event_id.to_string(), + }; + Ok(Response::new(response_data)) +} +``` + +- Streaming image download: +```rust +async fn push_image( + &self, + request: Request>, +) -> Result, Status> { + use crate::pb::event_service_push_image_request::Message; + + let mut request_stream = request.into_inner(); + + let err_msg_not_null = "EventServicePushImageRequest.message must not be null."; + + let event_id = { + let err_msg_1 = "The first message must contain metadata."; + let message = { + request_stream + .next() + .await + .ok_or(ApiError::InvalidArgument(err_msg_1.to_owned()))?? + .message + .ok_or(ApiError::InvalidArgument(err_msg_not_null.to_owned()))? + }; + let metadata = match message { + Message::Metadata(data) => data, + Message::Chunk(_) => { + return Err(ApiError::InvalidArgument(err_msg_1.to_owned()).into()); + } + }; + + evops_models::EventId::new({ + metadata + .event_id + .parse::() + .map_err(|e| ApiError::InvalidArgument(e.to_string()))? + }) + }; + let image = { + let mut buffer = BytesMut::new(); + while let Some(message) = request_stream.message().await? { + let message = { + message + .message + .ok_or(ApiError::InvalidArgument(err_msg_not_null.to_owned()))? + }; + let chunk = match message { + Message::Metadata(_) => { + let err_msg = "Expected chunk, found metadata. Only the first message needs to contain metadata."; + return Err(ApiError::InvalidArgument(err_msg.to_owned()).into()); + } + Message::Chunk(c) => c, + }; + buffer.put(&*chunk); + } + let buffer = buffer.freeze(); + + evops_models::EventImage::try_from(buffer)? + }; + + let image_id = self.state.push_event_image(event_id, image).await?; + let response_data = EventServicePushImageResponse { + image_id: image_id.to_string(), + }; + + Ok(Response::new(response_data)) +} +``` + +### Key Files + +- `lib.rs`: Main entry point + - Creates gRPC router with `axum` + - Registers all services + - Sets up gRPC reflection service for debugging + - Configures CORS with gRPC-specific headers + +- `pb.rs`: PContains auto-generated Protobuf bindings + - Contains all gRPC service and message definitions + - Includes file descriptor set for reflection + - Manual validation implementations + + - `pb/impls.rs`: Protobuf ↔ Domain types + - Handles validation and type conversions + - Key responsibilities + - String to UUID conversion + - Field validation + - Model to gRPC response transformations + +- `services.rs`: Service Registry +Aggregates all service implementations diff --git a/crates/evops-ml-client/README.md b/crates/evops-ml-client/README.md new file mode 100644 index 0000000..88379ba --- /dev/null +++ b/crates/evops-ml-client/README.md @@ -0,0 +1,24 @@ +# `evops-ml-client` + +## Overview + +Provides gRPC client implementation for communicating with Machine Learning services. Handles connection management, request serialization, and response parsing. + +### Key Files + +- `lib.rs`: Core Client Setup + Main entry point that establishes gRPC connection to ML server. + Key Responsibilities: + - Creates `MlClient` struct wrapping gRPC channel + - Implements connection retry logic with 5-second intervals + - Initializes gRPC client stub + +- `logic.rs`: Business Logic + Contains domain-specific operations and data transformations. + 1. Converts `EventDescription` to protobuf format + 2. Executes gRPC call to ML service + +- `pb.rs`: Protobuf Bindings +Auto-generated file (via `tonic-build`) containing: + - gRPC client stubs (`MlServiceClient`) + - Protobuf message definitions \ No newline at end of file diff --git a/crates/evops-rest/README.md b/crates/evops-rest/README.md new file mode 100644 index 0000000..61180f8 --- /dev/null +++ b/crates/evops-rest/README.md @@ -0,0 +1,33 @@ +# `evops-rest` + +## Overview + +Provides REST API endpoints using `axum` crate. Automatically generates OpenAPI documentation using `aide` crate. Organized into logical service groups (events, tags, users, etc.). + +### Key Files + +- `lib.rs`: Main entry point + - Sets up API routes + - Configures OpenAPI generation + +- `routes/`: Endpoint implementations + - Each file handles related operations + - Uses file-system routing (nested routes like `/tags/{tag-id}`) + +- `docs.rs`: OpenAPI configuration + - Defines API tags (e.g., `"TagService"`, `"UserService"`) + - Configures OpenAPI 3 schema generation + +- `types.rs`: Request/response data structures + +- `error.rs`: Error handling + Standardizes API errors: + - `400` Bad Request + - `404` Not Found + - `409` Conflict + - `422` Validation Error + - `500` Server Error + +### Adding New Endpoint + +1. diff --git a/crates/evops-storage/README.md b/crates/evops-storage/README.md new file mode 100644 index 0000000..8dd1a18 --- /dev/null +++ b/crates/evops-storage/README.md @@ -0,0 +1,20 @@ +# `evops-storage` + +## Overview + +Provides object storage operations for event images using MinIO. Handles image uploads, streaming downloads, and deletions. + +### Key Files + +- `lib.rs`: Client Initialization + Sets up the storage client and ensures required buckets exist. + - Creates MinIO/S3 client with authentication + - Checks storage connection + - Auto-creates `event-images` bucket if missing + +- `logic.rs`: Business Logic +Implements CRUD operations for event images. Uses WebP format for storage. +Key methods: + - `upload_event_image` - Encodes image as WebP and uploads to storage + - `stream_event_image` - Streams image bytes chunk-by-chunk + - `delete_event_image` - Removes image from storage diff --git a/crates/evops/README.md b/crates/evops/README.md new file mode 100644 index 0000000..875fd43 --- /dev/null +++ b/crates/evops/README.md @@ -0,0 +1,27 @@ +# `evops` + +## Overview + +The main executable crate serving as the backend entry point. Handles: +- Configuration loading +- Logging initialization +- Server startup (REST + gRPC) +- Graceful shutdown +- Dependency integration + +### Key Files + +- `config.rs` +Loads configuration from environment variables: + - Validates URL formats + - Uses `eyre` for error handling + +- `main.rs` +Entry point with async runtime setup + +### Dependencies + +1. `evops-db`: Database operations (PostgreSQL) +2. `evops-storage`: File storage (MinIO) +3. `evops-ml-client`: Machine learning service integration +4. `evops-models`: Domain data structures \ No newline at end of file