Java for business complexity. Rust for runtime-critical services. TeaQL for a consistent engineering experience.
This repository demonstrates how Java and Rust can coexist in a microservice-based payment platform without forcing services to share one domain model or one codebase.
The Java service handles merchant onboarding, KYC, approvals and integration-heavy workflows. The Rust service handles client-facing payment execution, callbacks and high-concurrency workloads.
Each service owns its domain model, database and deployment lifecycle. TeaQL provides a consistent way to model, query, audit, test and evolve both services.
The system is split into two microservices, following the Database-per-Service design principle:
+-----------------------------------------+
| Java Merchant Service |
| (Merchant Registry, KYC, Approvals) |
+--------------------+--------------------+
|
(1) Writes Merchant & OutboxEvent
v
+------+------+
| merchant_db |
+------+------+
|
(2) Fetches Target IP from Consul
|
+-------------------v-------------------+
| Consul Registry |
| (Service Discovery & Load Balancing) |
+-------------------+-------------------+
|
(3) HTTP Sync Event (Load Balanced)
v
+--------------------+--------------------+
| Rust Payment Service |
| (High-Concurrency Orders & webhooks) |
+--------------------+--------------------+
|
(4) Writes Orders & Cached Merchants
v
+------+------+
| payment_db |
+------+------+
-
Spring Cloud Merchant Service (
spring-cloud-merchant-service/):- Handles merchant registration, KYC document verification, and status updates (Pending -> Active -> Suspended).
- Uses the Transactional Outbox Pattern via TeaQL. Status updates and outbox events are persisted in
merchant_dbin a single local transaction. - An asynchronous task triggers immediate sync post-commit. It queries Consul to discover available instances of the Rust Payment Service and sends the sync payload using a LoadBalanced
RestTemplate.
-
Axum Payment Service (
axum-payment-service/):- High-concurrency client-facing checkout service built with Axum and TeaQL Cloud Starter.
- Upon startup, it automatically registers itself with the Consul Registry, enabling Java services to discover and route traffic to it.
- Maintains a local
CachedMerchanttable to authenticate incoming checkout calls instantly without making gRPC/HTTP round-trips to the Java service. - Exposes internal sync endpoints for Java to propagate merchant status changes, and webhook callback endpoints for payment gateways.
- Typed Constants & States: System states (e.g., payment status
CREATED,SUCCESS,FAILED) are modeled as typed entities, automatically populated during schema migration. Helper methods like.status_is_success()and.update_status_to_success()prevent invalid state updates. - Micro-Audit Trails & Purposes: Every DB read or write requires specifying a business purpose (e.g.,
Q.merchants().purpose("validate_merchant")ororder.audit_as("Initiate Transaction").save()). This guarantees that SQL logs and telemetry capture the intent of every action. - Spring Boot & Axum Integration: Seamlessly integrates with Spring Boot's dependency injection / transactional management on the Java side, and Axum's routing and state management on the Rust side.
Ensure PostgreSQL is running and create the databases:
CREATE DATABASE merchant_db;
CREATE DATABASE payment_db;Note: TeaQL automatically executes schema migrations on startup. All tables, foreign keys, and indexes will be generated automatically when the services boot.
Navigate to the directory:
cd spring-cloud-merchant-serviceFirst, compile and install the generated TeaQL domain library:
cd generate-lib/lib
mvn clean install -DskipTests
cd ../../Now run the Spring Boot application:
cd app
mvn spring-boot:runThe service will start on port 8081 (or as configured in application.properties), and automatically register with the local Consul server.
Navigate to the directory:
cd axum-payment-serviceSet the database environment variables:
export PAYMENT_SERVICE_CORE_DATABASE_URL="host=127.0.0.1 dbname=payment_db user=postgres password=postgres"
export PAYMENT_SERVICE_CORE_DATABASE_USER="postgres"
export PAYMENT_SERVICE_CORE_DATABASE_PASSWORD="postgres"
export SCHEMA_MODE="execute"Compile and run the Axum server:
cargo runThe payment service registers with Consul, exposes health metrics, and listens on port 8080.
POST /api/merchant/register: Registers a new merchant with KYC details.POST /api/merchant/{id}/approve: Approves a merchant (transitions toACTIVEand pushes sync event).POST /api/merchant/{id}/suspend: Suspends a merchant (transitions toSUSPENDEDand pushes sync event).GET /api/merchant/{id}: Retrieves merchant profile.
POST /api/pay/create: Initiates a checkout transaction.POST /api/pay/callback: Simulates payment gateway status callback.GET /api/pay/status: Checks payment transaction status.POST /api/internal/sync-merchant: Internal endpoint called by Java to synchronize merchant state.