feat: add expense-reimbursement use-case example (uc-14)#22
Merged
Conversation
Add uc-14-expense-reimbursement module with Spring Boot 4.1.0 + Operaton 2.1.1, dual Maven/Gradle build, docker-compose, application config, and main class. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018MQnsh6ZTicNjjhccHMwuh
…ests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018MQnsh6ZTicNjjhccHMwuh
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018MQnsh6ZTicNjjhccHMwuh
…bedded form Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018MQnsh6ZTicNjjhccHMwuh
Without operaton:formData, the Tasklist had no way for a finance user to set the approved variable, making the approval path unreachable via UI. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018MQnsh6ZTicNjjhccHMwuh
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018MQnsh6ZTicNjjhccHMwuh
…reMock + Mailpit Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018MQnsh6ZTicNjjhccHMwuh
- Add full 8-section README covering vision LLM, DMN, user task, email paths - Add placeholder PNG (bpmn-to-image not installed; placeholder committed per brief) - Register example in .operaton-starter.yml after bank-account-opening - Add catalog row in root README Use Cases table (after supply-chain-tracking) - Add Vision LLM (Ollama) row in root README Integrations table Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018MQnsh6ZTicNjjhccHMwuh
- Replace candidateGroups bullet with LLM email drafting bullet (spec requirement) - Fix catalog link text to kebab-case [expense-reimbursement] Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018MQnsh6ZTicNjjhccHMwuh
…cross-stub ambiguity Email stubs (priority 10) take precedence over receipt stubs (priority 5) so the rejection email call is not mismatched by the Charlie Weiss receipt stub. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018MQnsh6ZTicNjjhccHMwuh
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new Operaton use-case example (examples/use-cases/expense-reimbursement) that demonstrates receipt-image verification via a multimodal vision LLM, a FIRST-hit DMN decision for approval routing, optional finance human approval, simulated payment, and LLM-drafted email notifications.
Changes:
- Introduces the new Spring Boot example module with BPMN + DMN models and Java delegates for receipt analysis, payment simulation, and email drafting/sending.
- Adds end-to-end integration tests using Testcontainers (PostgreSQL) plus WireMock (LLM stub) and Mailpit (SMTP sink), including WireMock mappings for deterministic LLM responses.
- Registers the example in the root catalog/module list and starter metadata.
Reviewed changes
Copilot reviewed 42 out of 44 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Adds the new use-case to the repository catalog and concept reference table. |
| pom.xml | Registers the new use-case module in the aggregate Maven build. |
| docs/EXAMPLE_STANDARDS.md | Updates standards text/checklist items related to example registration and screenshots. |
| .operaton-starter.yml | Registers the new example in the starter metadata (entry currently needs to match the established schema). |
| examples/use-cases/expense-reimbursement/README.md | Documents the new example, walkthrough, and how it works. |
| examples/use-cases/expense-reimbursement/pom.xml | Maven build definition for the new example module. |
| examples/use-cases/expense-reimbursement/build.gradle.kts | Gradle build definition for the new example module. |
| examples/use-cases/expense-reimbursement/settings.gradle.kts | Gradle settings for the new example module. |
| examples/use-cases/expense-reimbursement/mvnw | Maven wrapper script for the example module. |
| examples/use-cases/expense-reimbursement/mvnw.cmd | Windows Maven wrapper script for the example module. |
| examples/use-cases/expense-reimbursement/gradlew | Gradle wrapper script for the example module. |
| examples/use-cases/expense-reimbursement/gradlew.bat | Windows Gradle wrapper script for the example module. |
| examples/use-cases/expense-reimbursement/gradle/wrapper/gradle-wrapper.properties | Gradle wrapper distribution configuration for the example module. |
| examples/use-cases/expense-reimbursement/.mvn/wrapper/maven-wrapper.properties | Maven wrapper distribution configuration for the example module. |
| examples/use-cases/expense-reimbursement/docker-compose.yml | Local runtime dependencies (PostgreSQL, Ollama, Mailpit) for running the example. |
| examples/use-cases/expense-reimbursement/src/main/resources/application.yaml | App configuration (DB, mail, LLM endpoint/model/key, admin user). |
| examples/use-cases/expense-reimbursement/src/main/resources/expense-reimbursement.bpmn | BPMN process model for receipt verification, approval routing, payment, and notification. |
| examples/use-cases/expense-reimbursement/src/main/resources/reimbursement-approval.dmn | DMN FIRST-hit decision table determining approvalRequired. |
| examples/use-cases/expense-reimbursement/src/main/resources/expense-reimbursement.png | Process diagram image (currently committed as a non-PNG placeholder). |
| examples/use-cases/expense-reimbursement/src/main/resources/static/forms/expense-form.html | Embedded start form for capturing requester info and uploading a receipt. |
| examples/use-cases/expense-reimbursement/src/main/java/org/operaton/examples/expensereimbursement/ExpenseReimbursementApplication.java | Spring Boot application entry point. |
| examples/use-cases/expense-reimbursement/src/main/java/org/operaton/examples/expensereimbursement/DataInitializer.java | Seeds finance group/users for the user task. |
| examples/use-cases/expense-reimbursement/src/main/java/org/operaton/examples/expensereimbursement/LlmProperties.java | Configuration binding for LLM connection/model properties. |
| examples/use-cases/expense-reimbursement/src/main/java/org/operaton/examples/expensereimbursement/LlmClient.java | HTTP client wrapper (RestTemplate) for calling the LLM endpoint. |
| examples/use-cases/expense-reimbursement/src/main/java/org/operaton/examples/expensereimbursement/PromptBuilder.java | Builds vision + email prompt payloads for chat completions requests. |
| examples/use-cases/expense-reimbursement/src/main/java/org/operaton/examples/expensereimbursement/ResponseParser.java | Parses LLM responses for match results and email body text with safe defaults. |
| examples/use-cases/expense-reimbursement/src/main/java/org/operaton/examples/expensereimbursement/MailProperties.java | Configuration binding for outbound mail “from” address. |
| examples/use-cases/expense-reimbursement/src/main/java/org/operaton/examples/expensereimbursement/EmailDispatcher.java | Delegate that sends the drafted email via Spring Mail. |
| examples/use-cases/expense-reimbursement/src/main/java/org/operaton/examples/expensereimbursement/delegate/ReceiptAnalyzer.java | Delegate that base64-encodes the receipt FileValue and calls the vision LLM. |
| examples/use-cases/expense-reimbursement/src/main/java/org/operaton/examples/expensereimbursement/delegate/PaymentService.java | Delegate that simulates payment and records a payment reference/date. |
| examples/use-cases/expense-reimbursement/src/main/java/org/operaton/examples/expensereimbursement/delegate/ApprovalEmailDrafter.java | Delegate that drafts approval email text via the LLM with fallback. |
| examples/use-cases/expense-reimbursement/src/main/java/org/operaton/examples/expensereimbursement/delegate/RejectionEmailDrafter.java | Delegate that drafts rejection email text via the LLM with fallback. |
| examples/use-cases/expense-reimbursement/src/test/java/org/operaton/examples/expensereimbursement/ExpenseReimbursementDeploymentIT.java | Verifies BPMN/DMN deploy and identity seed data exists. |
| examples/use-cases/expense-reimbursement/src/test/java/org/operaton/examples/expensereimbursement/ExpenseReimbursementIT.java | Full-path integration tests across auto-approve, human-approve, human-reject. |
| examples/use-cases/expense-reimbursement/src/test/java/org/operaton/examples/expensereimbursement/PromptBuilderTest.java | Unit tests for request JSON structure and prompt contents. |
| examples/use-cases/expense-reimbursement/src/test/java/org/operaton/examples/expensereimbursement/ResponseParserTest.java | Unit tests for parsing match results and email body from responses. |
| examples/use-cases/expense-reimbursement/src/test/java/org/operaton/examples/expensereimbursement/LlmPropertiesTest.java | Unit tests for URL/header helpers in LlmProperties. |
| examples/use-cases/expense-reimbursement/src/test/resources/wiremock/mappings/llm-receipt-match.json | WireMock stub for a receipt analysis MATCH scenario. |
| examples/use-cases/expense-reimbursement/src/test/resources/wiremock/mappings/llm-receipt-unrelated.json | WireMock stub for a receipt analysis UNRELATED scenario. |
| examples/use-cases/expense-reimbursement/src/test/resources/wiremock/mappings/llm-receipt-match-overtier.json | WireMock stub for MATCH with over-tier cost scenario. |
| examples/use-cases/expense-reimbursement/src/test/resources/wiremock/mappings/llm-email-approved.json | WireMock stub for approval email drafting response. |
| examples/use-cases/expense-reimbursement/src/test/resources/wiremock/mappings/llm-email-rejected.json | WireMock stub for rejection email drafting response. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -0,0 +1 @@ | |||
| placeholder No newline at end of file | |||
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
examples/use-cases/expense-reimbursement— a new use-case example demonstrating multimodal vision LLM receipt verification, FIRST-hit DMN approval decision, optional human approval by the finance group, simulated payment, and LLM-drafted email notificationoperaton:delegateExpression(Spring beans) instead of the http-connector, because the receipt is a binaryFileValuethat must be base64-encoded for a multimodal vision request — an instructive contrast with the connector-based siblingsoperaton:namespace only,historyTimeToLive="P30D"Review checklist
./mvnw verifypasses from clean checkout (failsafe ran 7 ITs, Failures: 0)operaton:namespace, have full DI, names,historyTimeToLivescripts/render-bpmn.shoncebpmn-to-imageis available)pom.xml==build.gradle.kts== root README tabledemo/demoadmin user, named seed users (alice, bob),application.yaml.operaton-starter.ymland rootREADME.mdNotes
bpmn-to-imageis not installed in this environment. Run./scripts/render-bpmn.sh examples/use-cases/expense-reimbursementand push the rendered PNG before merge../gradlew buildwas not verified (Testcontainers requires Docker; same Colima socket constraint as the sibling examples). Maven build is the primary gate.🤖 Generated with Claude Code
https://claude.ai/code/session_018MQnsh6ZTicNjjhccHMwuh