refactor(conference-scheduling): convert to Models Service SDK structure#1126
refactor(conference-scheduling): convert to Models Service SDK structure#1126larsbeck wants to merge 12 commits into
Conversation
- Move solver justifications to domain/justification with shared ConferenceSchedulingJustification interface - Add DTO layer (input/output/metrics/config overrides/validation) - Add DemoDataBuilder/DemoDataGenerator for demo data - Update pom.xml for platform model conventions
- replace generated withXxx bloat and telescoping constructors with builders - fail fast on unknown references in model conversion - drop node/npm from the maven build and custom coverage harness - move to 999-SNAPSHOT parent, drop JFrog repositories Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qae2bExuXdkKjDJjFXynGi
Reverts the removal of the vacuum OpenAPI lint and markdownlint from the maven build and drops the DtoSchemaDescriptionTest that stood in for them. Also commits the previously missing .vacuum-ruleset.yaml and .markdownlint-cli2.jsonc (the root .gitignore's ".*" pattern had silently excluded them, so the lint steps could never run) and adds the missing @Schema description on ConferenceScheduleIssue that the restored vacuum lint caught. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qae2bExuXdkKjDJjFXynGi
Vacuum is a Go binary; the npm package was only a distribution channel. Download the pinned platform binary from GitHub releases instead of installing node/npm via frontend-maven-plugin. Markdownlint is removed entirely (spotless keeps formatting markdown). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qae2bExuXdkKjDJjFXynGi
Moves the vacuum lint out of the maven build into a dedicated GitHub workflow, following vacuum's documented CI/CD setup. The workflow lints the committed spec of every model shipping a .vacuum-ruleset.yaml, so future converted models are covered automatically. The generated src/build/openapi.json is now committed (force-added past the root .gitignore's "build" pattern) to keep the lint standalone and make spec drift visible in diffs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qae2bExuXdkKjDJjFXynGi
Unknown prerequisite talk codes now fail fast like every other reference, the dataset info span is closed properly, a stray jQuery .fail() argument is removed and DemoDataBuilderTest uses assertNull. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qae2bExuXdkKjDJjFXynGi
The UI loads all assets from CDNs, so the WebJars runtime dependencies and the web-dependency-locator extension were dead weight. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qae2bExuXdkKjDJjFXynGi
…leset The header still pointed at the removed exec-maven-plugin wiring; the lint now runs in the lint_openapi.yml workflow. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qae2bExuXdkKjDJjFXynGi
There was a problem hiding this comment.
Pull request overview
This pull request refactors the conference-scheduling quickstart to align with the Timefold Models Service SDK structure, introducing a DTO-first API surface and SDK-compatible model conversion/validation while simplifying build/CI and updating the UI to the new REST contract.
Changes:
- Introduces a DTO layer (+ validation issues/metrics/config overrides) and a
ConferenceScheduleModelConvertor/ConferenceScheduleValidatorfor SDK model I/O. - Replaces the bespoke REST resources with an SDK
ModelRestinterface and updates the UI + tests to use the/v1/...endpoints and ModelRequest/ModelResponse shapes. - Adds OpenAPI spec linting in CI via vacuum rulesets and commits the generated OpenAPI JSON.
Reviewed changes
Copilot reviewed 61 out of 63 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| use-cases/conference-scheduling/src/test/java/org/acme/conferencescheduling/solver/SolverTestDataFactory.java | Adds DTO-based test data factory for solver tests. |
| use-cases/conference-scheduling/src/test/java/org/acme/conferencescheduling/solver/SolverManagerTest.java | Adds solver smoke test using model conversion + metrics assertions. |
| use-cases/conference-scheduling/src/test/java/org/acme/conferencescheduling/solver/ConferenceSchedulingConstraintProviderTest.java | Minor formatting adjustment in constraint provider tests. |
| use-cases/conference-scheduling/src/test/java/org/acme/conferencescheduling/solver/ConferenceScheduleResourceIT.java | Adds native IT targeting /v1 endpoints and async solving status. |
| use-cases/conference-scheduling/src/test/java/org/acme/conferencescheduling/solver/ConferenceScheduleEnvironmentTest.java | Updates env-mode test to use DTO input + convertor (no REST demo-data). |
| use-cases/conference-scheduling/src/test/java/org/acme/conferencescheduling/rest/ConferenceSchedulingResourceIT.java | Removes old REST IT for legacy endpoints. |
| use-cases/conference-scheduling/src/test/java/org/acme/conferencescheduling/rest/ConferenceScheduleResourceTest.java | Removes old REST test for legacy endpoints. |
| use-cases/conference-scheduling/src/test/java/org/acme/conferencescheduling/ProjectStructureTest.java | Adds ArchUnit rules enforcing layered architecture + DTO/record conventions. |
| use-cases/conference-scheduling/src/test/java/org/acme/conferencescheduling/demo/DemoDataBuilderTest.java | Adds test coverage for new demo input builder. |
| use-cases/conference-scheduling/src/main/resources/META-INF/resources/index.html | Switches UI assets to CDN and updates curl examples + platform embed hooks. |
| use-cases/conference-scheduling/src/main/resources/META-INF/resources/app.js | Refactors UI to ModelRest contract, /v1 endpoints, and platform embedding params. |
| use-cases/conference-scheduling/src/main/resources/application.properties | Adopts model metadata/settings + updated termination properties. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/solver/justifications/ConferenceSchedulingJustification.java | Removes old solver justification record (moved to domain justification). |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/solver/ConstraintGroupTag.java | Introduces tags for constraint group classification. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/solver/ConferenceScheduleConstraintGroup.java | Adds SDK-facing constraint group definitions. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/service/ConferenceScheduleValidator.java | Adds SDK ModelValidator producing structured validation issues. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/service/ConferenceScheduleModelConvertor.java | Adds SDK ModelConvertor between DTOs and solver domain model. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/service/ConferenceScheduleIssues.java | Defines concrete validation issue classes for the model. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/rest/exception/ErrorInfo.java | Removes legacy error payload type for old REST layer. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/rest/exception/ConferenceScheduleSolverExceptionMapper.java | Removes legacy exception mapper (old REST stack). |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/rest/exception/ConferenceScheduleSolverException.java | Removes legacy REST exception type. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/rest/DemoDataGenerator.java | Removes legacy demo-data generator that returned domain model directly. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/rest/ConferenceSchedulingResource.java | Removes legacy bespoke REST resource implementation. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/rest/ConferenceSchedulingDemoResource.java | Removes legacy demo-data REST resource. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/rest/ConferenceScheduleResource.java | Adds SDK ModelRest resource interface for schedules. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/dto/TimeslotIdDetail.java | Adds validation metadata record for timeslot ID issues. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/dto/TimeslotDTO.java | Adds timeslot DTO for wire format. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/dto/TalkTypeDTO.java | Adds talk type DTO for wire format. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/dto/TalkIdDetail.java | Adds validation metadata record for talk ID issues. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/dto/TalkDTO.java | Adds talk DTO + builder + minimal withers for solver output merging. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/dto/SpeakerIdDetail.java | Adds validation metadata record for speaker ID issues. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/dto/SpeakerDTO.java | Adds speaker DTO + builder for wire format. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/dto/RoomIdDetail.java | Adds validation metadata record for room ID issues. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/dto/RoomDTO.java | Adds room DTO for wire format. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/dto/ConferenceScheduleValidationIssue.java | Enumerates validation issue types/codes for the model. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/dto/ConferenceScheduleOutputMetrics.java | Adds structured output metrics DTO. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/dto/ConferenceScheduleOutput.java | Adds model output DTO for API responses. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/dto/ConferenceScheduleInputMetrics.java | Adds structured input metrics DTO. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/dto/ConferenceScheduleInput.java | Adds model input DTO for API requests. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/dto/ConferenceScheduleConfigOverrides.java | Adds nullable constraint-weight overrides per SDK conventions. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/domain/Timeslot.java | Adjusts overlap semantics and formatting in equals/overlap helpers. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/domain/TalkType.java | Switches compatible sets to linked sets + formatting in equals. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/domain/Talk.java | Replaces large constructors with builder and adds isScheduled(). |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/domain/Speaker.java | Replaces large constructors with builder. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/domain/Room.java | Formatting/consistency updates in equals. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/domain/justification/UndesiredTagsJustification.java | Moves justification to domain + enforces non-null description. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/domain/justification/UnavailableTimeslotJustification.java | Moves justification to domain + enforces non-null description. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/domain/justification/RequiredTagsJustification.java | Moves justification to domain + enforces non-null description. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/domain/justification/ProhibitedTagsJustification.java | Moves justification to domain + enforces non-null description. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/domain/justification/PreferredTagsJustification.java | Moves justification to domain + enforces non-null description. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/domain/justification/DiversityTalkJustification.java | Moves justification to domain + enforces non-null description. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/domain/justification/ConflictTalkJustification.java | Moves justification to domain + enforces non-null description. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/domain/justification/ConferenceSchedulingJustification.java | Adds shared justification record in domain package. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/domain/ConferenceSchedule.java | Adapts solution to SDK SolverModel, adds metrics + weight overrides. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/domain/ConferenceConstraintProperties.java | Removes redundant explicit no-arg constructor. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/demo/DemoDataGenerator.java | Adds SDK demo-data generator returning ModelRequest. |
| use-cases/conference-scheduling/src/main/java/org/acme/conferencescheduling/demo/DemoDataBuilder.java | Adds deterministic demo dataset builder producing DTO input. |
| use-cases/conference-scheduling/README.md | Updates CLI snippets and paths for consistency. |
| use-cases/conference-scheduling/pom.xml | Migrates module to platform parent conventions + quality gates + OpenAPI spec copy. |
| use-cases/conference-scheduling/.vacuum-ruleset.yaml | Adds vacuum ruleset enforcing schema/property descriptions for OpenAPI. |
| .github/workflows/lint_openapi.yml | Adds CI job linting committed OpenAPI specs for models with vacuum rulesets. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This is imo expected, and it's the direct result of that we want the use-cases folder to contain examples that are feature complete, platform compatible and well structured. Which comes at a cost.
(We should keep pushing so "fully featured" doesn't have to mean "this much code" forever. But that's a follow-up?) |
Error Prone requires -XDaddTypeAnnotationsToSymbol=true on JDK 21 (the flag is ignored on newer JDKs). Also commits .pmd-ruleset.xml, which the root .gitignore's ".*" pattern had silently excluded — the PMD check could not run in CI without it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qae2bExuXdkKjDJjFXynGi
|
@triceo @pieterdeschepper granted me permission now so I could create a new branch, hence the new PR. We want these use-cases to be fully featured and be in the right "shape". They are not getting started experiences. They are in fact almost the opposite. Think of them as an opinionated way to build a production ready model (even though they are small models). When someone wants to build a production ready model, they should not need to think about what goes where, are there any building blocks missing - they should be able to take this and start modifying. See #1126 (comment) |
…m 'orbit' to 'platform'
| Timeslot timeslot = new Timeslot(dto.id(), LocalDateTime.parse(dto.startDateTime()), | ||
| LocalDateTime.parse(dto.endDateTime()), talkTypes(dto.talkTypeNames(), talkTypeMap), | ||
| new LinkedHashSet<>(dto.tags())); |
…heck Replaces the in-module ArchUnit ProjectStructureTest (and the archunit test dependency) with .github/scripts/ArchitectureCheck.java, a JBang script running the identical rules against target/classes in the new architecture_check.yml workflow. The workflow covers every Models Service SDK quickstart automatically, so the guarantees are unchanged while the model modules stay free of test scaffolding. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qae2bExuXdkKjDJjFXynGi
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qae2bExuXdkKjDJjFXynGi
| return { | ||
| onPlatform: q.has('onPlatform'), | ||
| runId: q.get('runId'), | ||
| apiUrl: q.has('apiUrl') ? decodeURIComponent(q.get('apiUrl')).replace(/\/+$/, '') : null, | ||
| apiKey: q.has('apiKey') ? q.get('apiKey') : null, | ||
| }; |
| <h3>5. Fetch the analysis of the solution</h3> | ||
| <pre> | ||
| <button class="btn btn-outline-dark btn-sm float-end" | ||
| onclick="copyTextToClipboard('curl5')">Copy</button> | ||
| <code id="curl5">curl -X PUT -H 'Content-Type:application/json' http://localhost:8080/schedules/analyze -d@solution.json</code> | ||
| <code id="curl5">curl -X GET -H 'Accept:application/json' http://localhost:8080/v1/schedules/{jobId}/score-analysis</code> | ||
| </pre> |
| SequencedSet<Talk> prerequisites = dto.prerequisiteTalkCodes().stream() | ||
| .map(code -> require(talkMap, code, "prerequisite talk")) | ||
| .collect(toCollection(LinkedHashSet::new)); | ||
| talkMap.get(dto.code()).setPrerequisiteTalks(prerequisites); | ||
| } |
| }).fail(function (xhr) { | ||
| showError("Getting the schedule has failed.", xhr); | ||
| refreshSolvingButtons("SOLVING_COMPLETED"); | ||
| }); |
Converts the conference-scheduling quickstart to the Models Service SDK structure:
domain/justificationwith a sharedConferenceSchedulingJustificationinterfaceDemoDataBuilder/DemoDataGeneratorfor demo datapom.xmlfor platform model conventionsReview feedback incorporated
Addresses the review comments from @triceo, @TomCools and Copilot:
Less code, readable construction (net ~-970 lines)
Talk/Speakerand onTalkDTO/SpeakerDTO; the telescoping 22-/11-arg constructors and theirPMD.ExcessiveParameterListsuppressions are gone, so the PMD parameter-list rule is enforced againwithXxxmethods deleted except the three actually used; the ArchUnit wither-per-component rule (which manufactured the bloat) is removed,with_methods_must_be_usedstays and now bans dead withersimmutableCopy/orEmpty/nonNegativehelpersTooManyStaticImportsraised to 30)ConfigOverrides: the 20 withers are gone and the no-arg constructor now yields all-null "no overrides" (previously it silently overrode every weight with 1). The constructor itself must stay because the SDK requires it reflectively — tracked in Service SDK: ModelConfigOverrides records are forced to declare an all-null no-arg constructor timefold-solver#2493Build & quality gates
CoverageReportSummary,ShadowSourcesCoverageCheck,RecordWithMethodCoverageTest) removed — plain JaCoCo gates unchanged (30% instruction / 20% branch bundle, 100% line on the ConstraintProvider).github/workflows/lint_openapi.ymllints the committed spec of every model shipping a.vacuum-ruleset.yaml(covers future models automatically).src/build/openapi.jsonand.vacuum-ruleset.yamlare now actually committed — the root.gitignore's.*andbuildpatterns had been silently excluding them, so the lint could never run beforequarkus-web-dependency-locatordropped (UI loads assets from CDN)999-SNAPSHOT(replaced on release; CI builds the solver from source), JFrog repositories removed — everything resolves from Maven CentralCorrectness
IllegalArgumentException("Unknown <kind> '<key>'.")on unknown talk-type/speaker/timeslot/room/prerequisite references instead of leaking nulls into the solver modeltalkTypeName, not just nullConferenceScheduleIssuegot its missing OpenAPI description (vacuum scores 100/100); small UI/test fixes (unclosed span, stray jQuery.failargument,assertNull), READMEcdpath correctedNote on CI: the failing
Maven Long-Runningjobs are pre-existing repo infrastructure breakage —actions/checkoutv7 refuses fork-PR checkouts underpull_request_target(see this comment); unrelated to this PR.🤖 Generated with Claude Code