This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is a Camunda 8 Developer Training repository containing hands-on exercises for learning Zeebe process orchestration, BPMN testing, distributed transaction patterns, and custom connector development. The project is a multi-module Maven build with exercises available in both Java and Kotlin.
Root level:
mvn clean install- Build all modulesmvn test- Run all tests across modules
Individual exercises:
- Navigate to specific exercise directory (e.g.,
cd exercises/exercise-1-testing-java) mvn test- Run tests for that exercisemvn spring-boot:run- Run Spring Boot application (for exercises 2 and 3)
Infrastructure:
cd stack && docker-compose up -d- Start Camunda 8 stack (Zeebe, Operate, Tasklist, Connectors, PostgreSQL, Elasticsearch)docker-compose down- Stop infrastructure- Access Camunda UI at http://localhost:8080 (credentials: demo/demo)
API Testing:
- Bruno API collection available in
bruno/directory for testing process endpoints
- Java 21 & Kotlin
- Spring Boot 3.4.1
- Camunda 8 (Zeebe 8.8.2)
- PostgreSQL 17.5 for persistence
- H2 for test database
- Mockito for mocking in tests
- Maven for build management
The codebase follows hexagonal architecture principles:
src/main/java/io/miragon/example/
├── adapter/ # Infrastructure layer
│ ├── in/ # Inbound adapters (REST controllers, message receivers)
│ ├── out/ # Outbound adapters (database, external APIs)
│ └── process/ # Process adapters (Zeebe workers, process message handling)
├── application/ # Application services (use cases)
└── domain/ # Core domain models and business logic
Key concepts:
- Domain layer: Pure business logic, no framework dependencies
- Application layer: Orchestrates domain objects and coordinates workflows
- Adapter layer: Framework-specific implementations (Spring, Zeebe, JPA)
- Inbound adapters: REST APIs, Zeebe workers that receive jobs
- Outbound adapters: Database persistence, process engine clients, external services
Exercises 1 (Java/Kotlin) focus on BPMN process testing using @CamundaSpringProcessTest:
Key testing patterns:
- Use
processTestContext.increaseTime(Duration)to trigger timer events - Message correlation:
processPort.sendPaymentReceived(correlationKey) - Process assertions:
assertThatProcessInstance(byKey(instanceKey)).isCompleted() - Element completion checks:
hasCompletedElement(elementId, count) - Mock workers with Mockito to verify business logic invocation
Test scenarios covered:
- Happy path flows
- Error/cancellation paths
- Timer-triggered events (reminders, timeouts)
- Message correlation patterns
- End-to-end integration tests
Outbox Pattern:
- Ensures reliable message delivery to Zeebe by storing messages in database first
ProcessMessageEntitywith status (PENDING → SENT)- Background scheduler (
ProcessEngineOutboxScheduler) processes outbox every 200ms - Uses pessimistic locking (
@Lock(LockModeType.PESSIMISTIC_WRITE)) to prevent race conditions - Database write + outbox write = same transaction = guaranteed delivery
Idempotency Pattern:
- Prevents duplicate operations from job retries
ProcessedOperationEntitytracks completed operations with composite key (subscriptionId + elementId)- Check-Execute-Record pattern in workers:
- Check if operation already processed
- Execute business logic
- Record operation as completed (in same transaction)
Exercise 3 teaches building custom Camunda outbound connectors:
Key principles:
- Keep BPMN clean by encapsulating technical complexity in connectors
- Use domain-focused activities in process models (e.g., "Notify Customer" instead of "Send Email via SendGrid")
- Connectors should be reusable and environment-agnostic
- Implement hexagonal architecture in connectors to decouple external APIs from business logic
- Separate input/output adapters for vendor-specific implementations
Process definitions are located in src/main/resources/bpmn/:
newsletter.bpmn- Newsletter subscription process (completed reference)bike-subscription.bpmn- Bike subscription process (exercise to implement)
PostgreSQL runs on localhost:5432 (credentials: admin/admin):
-- Monitor outbox pattern
SELECT * FROM process_message ORDER BY created_at DESC;
-- Monitor idempotency tracking
SELECT * FROM processed_operations ORDER BY processed_at DESC;Zeebe Worker Implementation:
@JobWorker(type = "check-bike-availability")
public void checkAvailability(ActivatedJob job) {
// Extract variables
var subscriptionId = job.getVariableAsType("subscriptionId", String.class);
// Business logic
var isAvailable = useCase.checkAvailability(subscriptionId);
// Complete job with result
client.newCompleteCommand(job)
.variables(Map.of("available", isAvailable))
.send();
}Process Port Pattern:
Process interaction abstraction separates BPMN engine details from application layer. Implement ProcessPort interface in adapter layer.
- Unit tests for domain logic (pure Java/Kotlin)
- Integration tests for adapters with mocked dependencies
- Process tests using
camunda-process-test-springwith in-memory engine - Use
@SpringBootTestwith H2 database for full integration tests - Mock external dependencies (email services, APIs) in tests
- Camunda Platform: 8.8.9
- Zeebe: 8.8.2
- Elasticsearch: 8.17.0
- Camunda Connectors: 8.8.5