Skip to content

feat: add expense-reimbursement use-case example (uc-14)#22

Merged
kthoms merged 18 commits into
mainfrom
feat/expense-reimbursement
Jul 1, 2026
Merged

feat: add expense-reimbursement use-case example (uc-14)#22
kthoms merged 18 commits into
mainfrom
feat/expense-reimbursement

Conversation

@kthoms

@kthoms kthoms commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Adds 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 notification
  • Deliberately uses operaton:delegateExpression (Spring beans) instead of the http-connector, because the receipt is a binary FileValue that must be base64-encoded for a multimodal vision request — an instructive contrast with the connector-based siblings
  • Full BPMN DI, operaton: namespace only, historyTimeToLive="P30D"
  • DMN hit policy FIRST with an UNRELATED override row, followed by per-kind cost thresholds (MEALS ≤ €50, TRAVEL ≤ €250, ACCOMMODATION ≤ €400, EQUIPMENT ≤ €1000)
  • WireMock (LLM stub) + Mailpit (SMTP sink) + PostgreSQL Testcontainers IT covering 3 paths: auto-approve, UNRELATED→human-approve, over-tier→human-reject

Review checklist

  • ./mvnw verify passes from clean checkout (failsafe ran 7 ITs, Failures: 0)
  • BPMN/DMN use operaton: namespace, have full DI, names, historyTimeToLive
  • ITs use Testcontainers (PostgreSQL + WireMock + Mailpit), no H2, no sleeps
  • Happy path + two alternative paths tested end-to-end
  • README has all 8 sections; placeholder PNG committed (render with scripts/render-bpmn.sh once bpmn-to-image is available)
  • Versions match pom.xml == build.gradle.kts == root README table
  • demo/demo admin user, named seed users (alice, bob), application.yaml
  • No dead code, no unused dependencies, no TODO/stub delegates
  • Example registered in .operaton-starter.yml and root README.md

Notes

  • BPMN PNG is a placeholder — bpmn-to-image is not installed in this environment. Run ./scripts/render-bpmn.sh examples/use-cases/expense-reimbursement and push the rendered PNG before merge.
  • ./gradlew build was 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

kthoms and others added 11 commits July 1, 2026 06:03
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
…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
…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
Copilot AI review requested due to automatic review settings July 1, 2026 10:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread .operaton-starter.yml Outdated
Comment thread docs/EXAMPLE_STANDARDS.md Outdated
Comment thread examples/use-cases/expense-reimbursement/README.md Outdated
@@ -0,0 +1 @@
placeholder No newline at end of file
Comment thread examples/use-cases/expense-reimbursement/README.md Outdated
kthoms and others added 7 commits July 1, 2026 21:26
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>
@kthoms kthoms merged commit efff129 into main Jul 1, 2026
3 checks passed
@kthoms kthoms deleted the feat/expense-reimbursement branch July 1, 2026 20:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants