| .. | ||
| app | ||
| common | ||
| docker/keycloak | ||
| gradle/wrapper | ||
| modules | ||
| workers/notification-worker | ||
| .gitignore | ||
| build.gradle.kts | ||
| docker-compose.yml | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| README.md | ||
| requests.http | ||
| settings.gradle.kts | ||
Mosenioring Backend
Production-ready Kotlin/Spring Boot 3 modular monolith skeleton for patient-caregiver-doctor coordination.
🏛 Architecture
This project follows a Modular Monolith architecture:
app: Main entry point, configuration, and shared controllers.common: Cross-cutting concerns (security, tenant handling, outbox pattern).modules/*: Independent business modules (Clinical, Identity, Messaging, etc.).workers/*: Background event consumers/processors.
🛠 Requirements
- Java 21
- Docker + Docker Compose
🚀 Local Run
1. Start Dependencies
docker compose up -d
2. Run the API
Choose a profile:
Local Development (with mock auth):
SPRING_PROFILES_ACTIVE=local ALLOW_LOCAL_AUTH=true ./gradlew :app:bootRun
Allows bypassing Keycloak using X-Local-* headers.
Dev Mode (with Keycloak):
SPRING_PROFILES_ACTIVE=dev ./gradlew :app:bootRun
3. Run the Worker (Optional)
./gradlew :workers:notification-worker:bootRun
🧪 Testing
Run all tests:
./gradlew test
🔐 Auth & Multi-tenancy
- JWT Resource Server: Uses Keycloak by default.
- Multi-tenancy: Enforced via
X-Tenant-Idheader (local) ortenant_idJWT claim. - Local Auth Headers (only when
ALLOW_LOCAL_AUTH=true):X-Local-Email: User identity.X-Local-Roles: e.g.,ADMIN, DOCTOR, CAREGIVER.X-Tenant-Id: Target tenant.
🔗 Key Services & Links
- OpenAPI: http://localhost:8080/swagger-ui/index.html
- Health: http://localhost:8080/health
- Postgres:
localhost:5432(mosenioring/mosenioring) - Keycloak: http://localhost:8081 (admin/admin)
- RabbitMQ: http://localhost:15672 (guest/guest)
- MinIO: http://localhost:9001 (minio/minio123)
📝 Notes
- Outbox Pattern: Medication plans publish events to an outbox table for reliable messaging.
- Idempotency: Workers use Redis to ensure events are processed only once.