Skip to content

Order Service Java πŸš€πŸŒ±πŸ˜

A microservice for managing orders in the Olara Tech platform.


πŸš€ Overview

Order Service is a Spring Boot microservice responsible for handling order creation, management, and retrieval. It integrates with RabbitMQ for event-driven communication and uses PostgreSQL for data persistence. The service is designed for scalability, resilience, and easy integration within a microservices ecosystem.


πŸ“¦ Features

Feature Description
πŸ“ Order Management Create, update, retrieve, and delete orders
πŸ“’ Event Publishing Publishes order events to RabbitMQ
♻️ Resilience Circuit breakers and retries (Resilience4j)
πŸ” Service Discovery Eureka integration for service registration
πŸ“Š Health Monitoring Exposes health and metrics endpoints (Actuator)
πŸ—„οΈ Database Migration Flyway for schema versioning

πŸ—οΈ Architecture

sequenceDiagram
    participant User
    participant App
    participant Backend
    participant Fineract(Wallet)
    participant Broker(Alpaca/DriveWealth)
    participant Market_Data(Polygon/IEX)
    participant Tax_Engine(TaxBit)

    %% ================== ORDER PLACEMENT ==================
    Note over User,App: 1. Order Placement Flow
    User->>App: Selects order type (Market/Limit/Stop)
    App->>Market_Data: Fetch real-time price
    Market_Data-->>App: Return bid/ask
    User->>App: Enter details (Qty, Price, TIF)
    App->>Backend: Submit order

    %% ================== PRE-CHECKS ==================
    Backend->>Fineract: Verify funds/shares
    Backend->>Broker: Check compliance:
    Broker->>Broker: Validate PDT, margin, restrictions
    alt Approved
        Broker-->>Backend: "Approved"
        Backend->>Broker: Route to exchange
    else Rejected
        Broker-->>Backend: "Rejected: Reason"
        Backend->>User: Show rejection notice
    end

    %% ================== ORDER CANCELLATION ==================
    Note over User,App: 2. Cancel/Replace Flow
    User->>App: Requests "Cancel Order"
    App->>Backend: Cancel request
    Backend->>Broker: Check order status
    alt Not Filled
        Broker->>Market_Data: Cancel order
        Market_Data-->>Broker: Confirmation
        Broker->>Fineract: Unlock funds
        Fineract->>User: Update wallet
    else Partially Filled
        Broker-->>Backend: "Partial fill - Cancel remainder"
    end

    %% ================== ORDER REPLACEMENT ==================
    User->>App: Requests "Modify Order"
    App->>Backend: New order params
    Backend->>Broker: Cancel-and-replace
    Broker->>Market_Data: Process replacement
    alt Success
        Market_Data-->>Broker: New order ID
        Broker->>User: Confirmation
    else Failure
        Broker->>Broker: Revert to original order
    end

    %% ================== POST-TRADE PROCESSING ==================
    Note over Broker,Tax_Engine: 3. Post-Trade Flow (T+2)
    Broker->>Fineract: Settlement file
    Fineract->>Broker: Confirm positions
    Broker->>Tax_Engine: Trade details
    Tax_Engine->>Tax_Engine: Calculate wash sales, cost basis
    Tax_Engine->>User: Annual 1099-B report
Hold "Alt" / "Option" to enable pan & zoom
  • Controller: Handles HTTP requests and responses
  • Service: Business logic for order processing
  • Repository: JPA interface to PostgreSQL
  • Event Publisher: Publishes events to RabbitMQ

πŸ› οΈ Technologies Used

  • β˜• Java 17+
  • 🌱 Spring Boot 3.x
  • 🐘 PostgreSQL
  • πŸ‡ RabbitMQ
  • πŸ›‘οΈ Resilience4j
  • 🧭 Eureka
  • πŸƒ Lombok
  • πŸ—„οΈ Flyway

βš™οΈ Setup Instructions

Prerequisites

  • Java 17+
  • Maven or Gradle
  • PostgreSQL
  • RabbitMQ

Quick Start

  1. Clone the repository
    git clone https://github.com/olara-tech/order-service-java.git
    cd order-service-java
    
  2. Configure the database in src/main/resources/application.yml:
    spring:
      datasource:
        url: jdbc:postgresql://localhost:5432/order-service-db
        username: postgres
        password: your_password
    
  3. Start RabbitMQ (Docker):
    docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:management
    
  4. Run the application:
    ./gradlew bootRun
    
  5. Access the application:
  6. Swagger UI: http://localhost:10001/swagger-ui.html
  7. Actuator: http://localhost:10001/actuator

πŸ“ Configuration Example

spring:
  application:
    name: order-service
  datasource:
    url: jdbc:postgresql://localhost:5432/order-service-db
    username: postgres
    password: your_password
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
management:
  endpoints:
    web:
      exposure:
        include: health,info

πŸ“š API Endpoints & Examples

Orders

1. Get Order by Tenant ID, User ID, and Order ID

Request:

GET /orders/{orderId}/users/{userId}
Headers:
  tenantId: <tenant-uuid>

Response:

{
  "requestId": "string",
  "timestamp": "2024-05-10T12:34:56.789Z",
  "success": true,
  "message": "Order fetched successfully.",
  "data": {
    "id": "b1e2c3d4-5678-1234-9abc-1234567890ab",
    "symbol": "AAPL",
    "type": "MARKET",
    "side": "BUY",
    "quantity": 10.0,
    "limitPrice": null,
    "stopPrice": null,
    "timeInForce": "GTC",
    "status": "PENDING",
    "rejectionReason": null,
    "brokerOrderId": "BRK-123456",
    "createdAt": "2024-05-10T12:34:56.789Z",
    "updatedAt": "2024-05-10T12:34:56.789Z",
    "executedAt": null,
    "executedPrice": null,
    "executedQuantity": null,
    "commission": null,
    "isTaxOptimized": false
  },
  "metadata": null
}

2. Get All Orders (Paginated)

Request:

GET /orders?page=0&size=10&sort=createdAt,desc

Response:

{
  "requestId": "string",
  "timestamp": "2024-05-10T12:34:56.789Z",
  "success": true,
  "message": "Orders fetched successfully.",
  "data": [
    {
      "id": "b1e2c3d4-5678-1234-9abc-1234567890ab",
      "symbol": "AAPL",
      "type": "MARKET",
      "side": "BUY",
      "quantity": 10.0,
      "status": "PENDING",
      "createdAt": "2024-05-10T12:34:56.789Z"
    }
    // ...more orders
  ],
  "page": 0,
  "size": 10,
  "totalElements": 1,
  "totalPages": 1,
  "metadata": null
}

3. Get All Orders by Tenant ID and User ID

Request:

GET /orders/{userId}?page=0&size=10&sort=createdAt,desc
Headers:
  tenantId: <tenant-uuid>

Response:

{
  "requestId": "string",
  "timestamp": "2024-05-10T12:34:56.789Z",
  "success": true,
  "message": "Orders fetched successfully.",
  "data": [
    {
      "id": "b1e2c3d4-5678-1234-9abc-1234567890ab",
      "symbol": "AAPL",
      "type": "MARKET",
      "side": "BUY",
      "quantity": 10.0,
      "status": "PENDING",
      "createdAt": "2024-05-10T12:34:56.789Z"
    }
    // ...more orders
  ],
  "page": 0,
  "size": 10,
  "totalElements": 1,
  "totalPages": 1,
  "metadata": null
}

4. Create a New Order

Request:

POST /orders
Content-Type: application/json

{
  "data": {
    "symbol": "AAPL",
    "type": "MARKET",
    "side": "BUY",
    "quantity": 10.0,
    "limitPrice": null,
    "stopPrice": null,
    "timeInForce": "GTC",
    "isTaxOptimized": false,
    "routingInstructions": ""
  }
}

Response:

{
  "requestId": "string",
  "timestamp": "2024-05-10T12:34:56.789Z",
  "success": true,
  "message": "Order created successfully.",
  "data": {
    "id": "b1e2c3d4-5678-1234-9abc-1234567890ab",
    "symbol": "AAPL",
    "type": "MARKET",
    "side": "BUY",
    "quantity": 10.0,
    "status": "PENDING",
    "createdAt": "2024-05-10T12:34:56.789Z"
  },
  "metadata": null
}

Products

1. Get Product by ID

Request:

GET /products/{id}

Response:

{
  "requestId": "string",
  "timestamp": "2025-05-10T12:34:56.789Z",
  "success": true,
  "message": "Product fetched successfully.",
  "data": {
    "id": "c2f3e4d5-6789-2345-abcd-2345678901bc",
    "name": "Apple iPhone 15",
    "description": "Latest Apple smartphone.",
    "imageUrl": "https://example.com/images/iphone15.jpg",
    "category": "Electronics",
    "status": "ACTIVE",
    "created": "2025-05-10T12:34:56.789Z",
    "updated": "2025-05-10T12:34:56.789Z",
    "createdBy": "admin",
    "updatedBy": "admin"
  },
  "metadata": null
}

2. Get All Products (Paginated)

Request:

GET /products?page=0&size=10&sort=created,desc

Response:

{
  "requestId": "string",
  "timestamp": "2025-05-10T12:34:56.789Z",
  "success": true,
  "message": "Products fetched successfully.",
  "data": [
    {
      "id": "c2f3e4d5-6789-2345-abcd-2345678901bc",
      "name": "Apple iPhone 15",
      "description": "Latest Apple smartphone.",
      "imageUrl": "https://example.com/images/iphone15.jpg",
      "category": "Electronics",
      "status": "ACTIVE",
      "created": "2025-05-10T12:34:56.789Z"
    }
    // ...more products
  ],
  "page": 0,
  "size": 10,
  "totalElements": 1,
  "totalPages": 1,
  "metadata": null
}

3. Create a New Product

Request:

POST /products
Content-Type: application/json

{
  "data": {
    "name": "Apple iPhone 15",
    "description": "Latest Apple smartphone.",
    "imageUrl": "https://example.com/images/iphone15.jpg",
    "category": "Electronics",
    "status": "ACTIVE"
  }
}

Response:

{
  "requestId": "string",
  "timestamp": "2025-05-10T12:34:56.789Z",
  "success": true,
  "message": "Product created successfully.",
  "data": {
    "id": "c2f3e4d5-6789-2345-abcd-2345678901bc",
    "name": "Apple iPhone 15",
    "description": "Latest Apple smartphone.",
    "imageUrl": "https://example.com/images/iphone15.jpg",
    "category": "Electronics",
    "status": "ACTIVE",
    "created": "2025-05-10T12:34:56.789Z"
  },
  "metadata": null
}

4. Update a Product

Request:

PUT /products/{id}
Content-Type: application/json

{
  "data": {
    "name": "Apple iPhone 15 Pro",
    "description": "Updated description.",
    "imageUrl": "https://example.com/images/iphone15pro.jpg",
    "category": "Electronics",
    "status": "ACTIVE"
  }
}

Response:

{
  "requestId": "string",
  "timestamp": "2025-05-10T13:00:00.000Z",
  "success": true,
  "message": "Product updated successfully.",
  "data": {
    "id": "c2f3e4d5-6789-2345-abcd-2345678901bc",
    "name": "Apple iPhone 15 Pro",
    "description": "Updated description.",
    "imageUrl": "https://example.com/images/iphone15pro.jpg",
    "category": "Electronics",
    "status": "ACTIVE",
    "created": "2025-05-10T12:34:56.789Z",
    "updated": "2025-05-10T13:00:00.000Z"
  },
  "metadata": null
}

5. Delete a Product

Request:

DELETE /products/{id}

Response:

{
  "requestId": "string",
  "timestamp": "2025-05-10T13:10:00.000Z",
  "success": true,
  "message": "Product deleted successfully.",
  "data": null,
  "metadata": null
}


πŸ“Š Data Model Reference

Orders Table

Column Type Description
id UUID Primary key, unique order identifier
user_id UUID ID of the user placing the order
tenant_id UUID ID of the tenant (organization/account)
account_id VARCHAR(255) Account identifier
symbol VARCHAR(255) Trading symbol (e.g., AAPL)
type VARCHAR(50) Order type (MARKET, LIMIT, etc.)
side VARCHAR(50) Order side (BUY, SELL)
quantity NUMERIC(38, 10) Quantity of the asset
limit_price NUMERIC(38, 10) Limit price (if applicable)
stop_price NUMERIC(38, 10) Stop price (if applicable)
time_in_force VARCHAR(50) Time in force (e.g., GTC, DAY)
status VARCHAR(50) Order status (PENDING, COMPLETED, etc.)
rejection_reason VARCHAR(255) Reason for rejection (if any)
broker_order_id VARCHAR(255) Broker/exchange order ID
client_order_id VARCHAR(255) Client reference order ID
executed_at TIMESTAMP When the order was executed
executed_price NUMERIC(38, 10) Price at which the order was executed
executed_quantity NUMERIC(38, 10) Quantity executed
commission NUMERIC(38, 10) Commission charged
is_tax_optimized BOOLEAN Whether the order is tax optimized
replaced_by_order_id UUID ID of the order that replaced this one (if any)
replaces_order_id UUID ID of the original order this one replaces (if any)
routing_instructions VARCHAR(255) Special routing instructions
created TIMESTAMP When the order was created
updated TIMESTAMP When the order was last updated
created_by VARCHAR(255) User who created the order
updated_by VARCHAR(255) User who last updated the order

Product Response Fields

Field Type Description
id UUID Unique product identifier
name String Product name
description String Product description
imageUrl String URL to product image
category String Product category
status String Product status (e.g., ACTIVE, INACTIVE)
created String ISO timestamp when the product was created
updated String ISO timestamp when the product was updated
createdBy String User who created the product
updatedBy String User who last updated the product

PageBaseResponse

Field Type Description
requestId String Unique identifier for the request
timestamp Instant When the response was created
success boolean Indicates if the operation was successful
message String Additional information about the response
data T The actual data payload (list or object)
page int Current page number (0-based)
size int Number of items per page
totalElements long Total number of elements across all pages
totalPages int Total number of pages
metadata ResponseMetadata Additional metadata (if any)

BaseResponse

Field Type Description
requestId String Unique identifier for the request
timestamp Instant When the response was created
success boolean Indicates if the operation was successful
message String Additional information about the response
data T The actual data payload (object or list)
metadata Object Additional metadata (if any)

🧩 Project Structure

order-service-java/
β”œβ”€β”€ docker-compose-order-service-local.yml
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ README.md
└── src/
    β”œβ”€β”€ main/
    β”‚   β”œβ”€β”€ java/com/olara/
    β”‚   β”‚   β”œβ”€β”€ controller/
    β”‚   β”‚   β”œβ”€β”€ dto/
    β”‚   β”‚   β”œβ”€β”€ entity/
    β”‚   β”‚   β”œβ”€β”€ enums/
    β”‚   β”‚   β”œβ”€β”€ event/
    β”‚   β”‚   β”œβ”€β”€ mapper/
    β”‚   β”‚   β”œβ”€β”€ repository/
    β”‚   β”‚   β”œβ”€β”€ service/
    β”‚   └── resources/
    β”‚       β”œβ”€β”€ application.yml
    β”‚       └── db.migration/
    └── test/
        └── java/com/olara/

🀝 Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/your-feature)
  3. Commit your changes (git commit -am 'Add new feature')
  4. Push to the branch (git push origin feature/your-feature)
  5. Create a new Pull Request

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.


πŸ“¬ Contact

For questions, reach out to Olara Tech.


Happy Coding!