Docs
  • Solver
  • Models
    • Field Service Routing
    • Employee Shift Scheduling
    • Pick-up and Delivery Routing
  • Platform
Try models
  • Timefold Solver SNAPSHOT
  • Using Timefold Solver
  • Building a service (Preview)
  • Service Model and Enricher
  • Edit this Page

Timefold Solver SNAPSHOT

    • Introduction
    • PlanningAI concepts
    • Getting started
      • Overview
      • Hello World Quick Start Guide
      • Quarkus Quick Start Guide
      • Spring Boot Quick Start Guide
      • Vehicle Routing Quick Start Guide
    • Using Timefold Solver
      • Using Timefold Solver: Overview
      • Configuring Timefold Solver
      • Modeling planning problems
      • Running Timefold Solver
      • Benchmarking and tweaking
      • Building a service (Preview)
        • REST API
        • Service Model and Enricher
        • Constraint weights (optional)
        • Demo data (optional)
        • Exposing metrics (optional)
    • Constraints and score
      • Constraints and Score: Overview
      • Score calculation
      • Understanding the score
      • Adjusting constraints at runtime
      • Load balancing and fairness
      • Performance tips and tricks
    • Optimization algorithms
      • Optimization Algorithms: Overview
      • Construction heuristics
      • Local search
      • Exhaustive search
      • Neighborhoods: A new way to define custom moves
      • Move Selector reference
    • Responding to change
    • Integration
    • Design patterns
    • FAQ
    • New and noteworthy
    • Upgrading Timefold Solver
      • Upgrading Timefold Solver: Overview
      • Upgrade from Timefold Solver 1.x to 2.x
      • Upgrading from OptaPlanner
      • Backwards compatibility
      • Migration Guides
        • Variable Listeners to Custom Shadow Variables
        • Chained planning variable to planning list variable
    • Plus/Enterprise Editions
      • Installation
      • Performance improvements
      • Score analysis
      • Recommendation API
      • Nearby selection
      • Multithreaded solving
      • Partitioned search
      • Constraint profiling
      • Multistage moves
      • Throttling best solution events

Service Model and Enricher

Building Timefold Solver as a service introduces a few concepts which are not relevant when using it as a library when it comes to modeling your problem domain.

This page describes features which are only relevant when running Timefold Solver as a Service (Preview). The information on these pages may describe functionality which may be changed or even removed in a future release.

1. SolverModel interface

Your class which is annotated by @PlanningSolution should implement the SolverModel interface.

Example for School Timetabling
@PlanningSolution
public class Timetable implements SolverModel<HardSoftScore> {

    @ProblemFactCollectionProperty
    @ValueRangeProvider
    private List<Timeslot> timeslots;

    @PlanningEntityCollectionProperty
    private List<Lesson> lessons;

    @PlanningScore
    private HardSoftScore score;

    @Override
    public HardSoftScore getScore() {
        return score;
    }

    // other Getters/Setters/Constructors excluded
}

In case you don’t want control over the score class used, you can also extend the AbstractSimpleModel as used in the getting started guide.

2. SolverModel enrichment

In some situations, the SolverModel must be enriched with additional information. This could be external information such as map data or smaller enhancements such as pinning entities which occurred in the past.

Enrichers usually pre-calculate fields which would otherwise be calculated in a ConstraintStream. Especially when the field depends on external information or is difficult to compute, pre-calculating can lead to much faster results.

In this example, we enrich the Timetable PlanningSolution described above by filling in the "isHoliday" field for all Timeslot objects.

Timeslot class for the School Timetabling example
public class Timeslot {

    private LocalDateTime startTime;
    private LocalDateTime endTime;

    private boolean isHoliday;

    public void setHoliday(boolean isHoliday) {
        this.isHoliday = isHoliday;
    }

    // other Getters/Setters/Constructors excluded
}

Enrichment of the SolverModel is possible by implementing a SolverModelEnricher.

Timeslot Enricher for the School Timetabling example
@ApplicationScoped
public class TimeslotHolidayEnricher implements SolverModelEnricher<Timetable> {

    @Override
    public Timetable enrich(Timetable solverModel) {
        for (Timeslot timeslot : solverModel.getTimeslots()) {
            boolean isHoliday = overlapsWithKnownHoliday(timeslot.getStartTime(), timeslot.getEndTime());
            timeslot.setHoliday(isHoliday);
        }

        return solverModel;
    }

    private boolean overlapsWithKnownHoliday(LocalDateTime start, LocalDateTime end) {
        //Implementation excluded. Potential call external service / database
    }
}

Next, register a SolverModelEnrichmentDirector implementation. This class allows you to determine the order in which enrichers are executed. This might be important when 1 of your custom enrichers depends on an enricher provided by Timefold Solver.

Timetable Enrichment Director for the School Timetabling example
@ApplicationScoped
public class TimetableEnrichmentDirector implements SolverModelEnrichmentDirector<Timetable> {

    private final TimeslotHolidayEnricher timeslotEnricher;

    @Inject
    public TimetableEnrichmentDirector(TimeslotHolidayEnricher timeslotEnricher) {
        this.timeslotEnricher = timeslotEnricher;
    }

    @Override
    public Timetable enrich(Timetable solverModel) {
        var enrichedModel = timeslotEnricher.enrich(solverModel);
        // Additional enrichers.
        return enrichedModel;
    }
}
  • © 2026 Timefold BV
  • Timefold.ai
  • Documentation
  • Changelog
  • Send feedback
  • Privacy
  • Legal
    • Light mode
    • Dark mode
    • System default