A production-ready microservices system built with Spring Boot and Spring Cloud for managing time-based reservations of shared scientific instruments (SEM/TEM, AFM, XRD, cryostats, lasers, cleanroom tools, GPU nodes, etc.) in research laboratories.
- Time-based Reservations with conflict detection (no double-booking)
- Approval Workflow (instrument owner approval required)
- Training Gates (required certification before booking)
- Session Tracking (check-in/check-out) and usage-based billing
- Event-driven Notifications via Apache Kafka
- Comprehensive Observability with Prometheus, Grafana, Loki, and Zipkin
- Data Engineering & Analytics with ETL pipelines, data warehouse, and business intelligence
- OAuth2 Security with Keycloak integration
- Service Discovery with Netflix Eureka
- Centralized Configuration with Spring Cloud Config
The system follows a microservices architecture pattern with the following components:
βββββββββββββββ
β Gateway β (Spring Cloud Gateway)
ββββββββ¬βββββββ
β
βββββΊ User Service (MongoDB)
βββββΊ Product/Instrument Service (PostgreSQL)
βββββΊ Order/Reservation Service (PostgreSQL)
βββββΊ Notification Service
βββββΊ Analytics API (PostgreSQL Analytics DB)
Infrastructure:
- Config Server (Spring Cloud Config)
- Eureka Server (Service Discovery)
- Keycloak (OAuth2/OIDC)
- Kafka (Event Streaming)
- Kafka Connect (Event to Data Lake)
- PostgreSQL (OLTP + OLAP Analytics DB)
- MongoDB (User Data)
- MinIO (Data Lake - S3-compatible)
- Prometheus + Grafana (Metrics & Analytics Dashboards)
- Loki (Logs)
- Zipkin (Distributed Tracing)
Data Pipeline:
Kafka Events β Kafka Connect β MinIO (Data Lake)
PostgreSQL/MongoDB β ETL Service β Analytics DB (Star Schema)
Analytics DB β Analytics API β Grafana Dashboards
-
Gateway Service (
gateway)- API Gateway with routing, security, and CORS
- Port:
8080 - Routes requests to backend services
- JWT token validation
-
User Service (
user)- User management, lab groups, roles, and training records
- Port:
8082 - Database: MongoDB
- Manages researchers, PIs, instrument owners, and admins
-
Product/Instrument Service (
product)- Instrument catalog with policies and availability
- Port:
8081 - Database: PostgreSQL
- Manages instruments, maintenance windows, and rate plans
-
Order/Reservation Service (
order)- Reservation lifecycle with conflict detection and approvals
- Port:
8083 - Database: PostgreSQL
- Handles reservations, sessions, and approval workflows
-
Notification Service (
notification)- Event-driven notifications via Kafka
- Port:
8084 - Sends email notifications for reservation events
-
Analytics API (
analytics-api)- Business intelligence and analytics queries
- Port:
8085 - Database: PostgreSQL (
analyticsdb) - Provides pre-built analytics endpoints and custom SQL query execution
- Role-based access: ADMIN, ANALYST
-
Analytics Service (
analytics-service)- ETL pipeline for data transformation
- Extracts data from PostgreSQL, MongoDB, and MinIO data lake
- Transforms and loads data into analytics warehouse (star schema)
- Runs scheduled data quality checks
- Technology: Python with pandas, SQLAlchemy
-
Config Server (
configserver)- Centralized configuration management
- Port:
8888 - Serves configuration from Git repository
-
Eureka Server (
eureka)- Service discovery and registration
- Port:
8761 - Service registry dashboard
-
Kafka Connect (
kafka-connect)- Connects Kafka topics to data lake (MinIO)
- Port:
8083 - S3 sink connectors for event persistence
-
MinIO (
minio)- S3-compatible object storage for data lake
- Ports:
9000(API),9001(Console) - Stores raw events, metrics, logs, and database snapshots
Services use Spring Cloud Config for centralized configuration. Local overrides can be set via:
application-local.yml(not committed to Git)- Environment variables
- Docker environment variables
See KEYCLOAK_SETUP.md for detailed Keycloak configuration:
- Create realm:
labreserve - Create client:
labreserve-api - Configure roles: RESEARCHER, PI, INSTRUMENT_OWNER, ADMIN
PostgreSQL databases are automatically created via deploy/docker/init-multi-db.sql:
orderdb- Reservation service (OLTP)productdb- Instrument service (OLTP)analyticsdb- Analytics data warehouse (OLAP) with star schema
MongoDB is used for user service (database: userdb).
The analytics database uses a star schema design with:
- Dimension tables:
dim_time,dim_instruments,dim_users,dim_lab_groups,dim_experiment_types - Fact tables:
fact_reservations,fact_sessions,fact_approvals,fact_events - Pre-populated time dimension (2020-2025) for time-series analysis
All API requests go through the Gateway at http://localhost:8080:
GET /api/users/{id}- Get user detailsPOST /api/users- Create userGET /api/users/{id}/training- Get training records
GET /api/products- List instrumentsGET /api/products/{id}- Get instrument detailsGET /api/products/{id}/availability- Check availabilityPOST /api/products- Register instrument
POST /api/orders- Create reservationGET /api/orders/{id}- Get reservation detailsPUT /api/orders/{id}/approve- Approve reservationPUT /api/orders/{id}/reject- Reject reservationPOST /api/orders/{id}/check-in- Start sessionPOST /api/orders/{id}/check-out- End session
POST /api/analytics/query- Execute custom SQL queryGET /api/analytics/reservations/summary- Reservation summary statisticsGET /api/analytics/instruments/utilization- Instrument utilization metricsGET /api/analytics/instruments/latency- Instrument approval latency analysisGET /api/analytics/users/activity- User activity metricsGET /api/analytics/users/no-show- Users with high no-show ratesGET /api/analytics/reservations/failure-patterns- Patterns leading to reservation failuresGET /api/analytics/sessions/utilization-by-hour- Utilization by time of dayGET /api/analytics/reservations/peak-demand- Peak demand periodsGET /api/analytics/export?query=...&format=csv|json- Export query results
All endpoints require OAuth2 JWT tokens from Keycloak. Include the token in the Authorization header:
curl -H "Authorization: Bearer <token>" http://localhost:8080/api/users/1- Prometheus UI: http://localhost:9090
- Metrics Endpoint:
http://service:port/actuator/prometheus
Custom business metrics:
reservations.created- Reservation creation counterreservations.approved- Approval countersessions.duration- Session duration histograminstruments.active.count- Active instruments gauge
- Grafana UI: http://localhost:3000
- Default Login: admin/admin
- Pre-configured Dashboards:
- Reservation metrics dashboard (operational metrics)
- Analytics Reservation Dashboard (business intelligence)
- Analytics Instrument Utilization Dashboard
- Analytics User Behavior Dashboard
See OBSERVABILITY_GUIDE.md for detailed metrics and dashboards.
- Loki Query API: http://localhost:3100
- Grafana Explore: Query logs via Loki datasource
Example query:
{service="reservation-service"} |= "ERROR"
- Zipkin UI: http://localhost:9411
- Search traces by service, trace ID, or time range
Data pipeline for business intelligence and analytics.
Kafka Events β Kafka Connect β MinIO (Parquet, partitioned by date)
PostgreSQL/MongoDB β ETL Service β Analytics DB (Star Schema)
MinIO Data Lake: S3-compatible storage (http://localhost:9001)
Buckets: raw-events, raw-metrics, raw-logs, raw-db-snapshots
ETL Pipeline: Extracts from PostgreSQL, MongoDB, MinIO β transforms through staging β loads into analytics warehouse. Runs daily at 2 AM with data quality checks.
Analytics Warehouse: Star schema with dimension tables (SCD Type 2) and fact tables. Pre-built views for common queries.
Analytics API: REST API with pre-built endpoints and custom SQL query execution. Data export in CSV/JSON. Requires ADMIN or ANALYST role.
# Get reservation summary
curl -H "Authorization: Bearer <token>" \
"http://localhost:8080/api/analytics/reservations/summary?startDate=2024-01-01&endDate=2024-12-31"
# Get instrument utilization
curl -H "Authorization: Bearer <token>" \
"http://localhost:8080/api/analytics/instruments/utilization"
# Execute custom query
curl -X POST -H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"query": "SELECT instrument_name, COUNT(*) FROM fact_reservations fr JOIN dim_instruments di ON fr.instrument_key = di.instrument_key GROUP BY instrument_name"}' \
"http://localhost:8080/api/analytics/query"For detailed documentation, see:
- Analytics Service README - ETL pipeline documentation
- Analytics API README - API documentation
- Analytics Database README - Schema and query examples
.
βββ configserver/ # Configuration server
βββ eureka/ # Service discovery
βββ gateway/ # API Gateway
βββ user/ # User service
βββ product/ # Instrument service
βββ order/ # Reservation service
βββ notification/ # Notification service
βββ analytics-api/ # Analytics API service
βββ analytics-service/ # ETL pipeline service
βββ deploy/
β βββ docker/ # Docker Compose and deployment configs
β βββ docker-compose.yml
β βββ prometheus/
β βββ grafana/
β βββ analytics/ # Analytics database schema
β βββ kafka-connect/ # Kafka Connect configuration
β βββ logging/
βββ KEYCLOAK_SETUP.md # Keycloak configuration guide
βββ OBSERVABILITY_GUIDE.md # Monitoring and observability guide
Build images using JIB (recommended):
./deploy/docker/build-images-jib.shOr using Buildpacks:
./deploy/docker/build-images-buildpacks.sh# Run all tests
mvn test
# Run tests for specific service
cd order && mvn testAll services can be containerized and run via Docker Compose. See deploy/docker/docker-compose.yml for infrastructure services.
To build and run application services:
# Build images
./deploy/docker/build-images-jib.sh
# Run with docker-compose (add application services to compose file)
docker-compose up -d- Authentication: OAuth2/OIDC via Keycloak
- Authorization: Role-based access control (RBAC)
- API Gateway: JWT token validation
- Service-to-Service: Secure communication (configure TLS in production)
- RESEARCHER: Can create reservations
- PI: Can approve group member reservations
- INSTRUMENT_OWNER: Can approve instrument reservations
- ADMIN: Full system access
- ANALYST: Can access analytics API and run queries