ServiceFlow API
Field-service operations are straightforward—until two dispatchers schedule the same technician at the same time.
I built ServiceFlow as a production-minded Java backend where the business rules remain correct under concurrency, authorization is explicit, and every delivery claim has executable evidence.
- Java 21
- Spring Boot 4.1
- Spring Security
- PostgreSQL
- Flyway
- Testcontainers
- Docker
- OpenAPI
- GitHub Actions
- unit & architecture tests
- 140
- PostgreSQL integration tests
- 88
- line coverage
- 95.5%
- fixed high/critical findings
- 0
The brief
Model the operational truth, not just CRUD screens.
Dispatchers need to manage customers and technicians, qualify work by skill, assign appointments, advance jobs through a controlled lifecycle, and understand current workload. Technicians should see only their own assignments. Invalid state must fail predictably.
The subtle requirement is scheduling integrity. An application-level “check then insert” looks correct in a single request but can fail when two requests race. ServiceFlow treats PostgreSQL as the final authority for that invariant while retaining a useful API response.
Architecture
One deployable application. Deliberate internal boundaries.
A modular monolith keeps operations simple while feature packages own their API, application, domain, and persistence concerns. ArchUnit tests prevent controllers and entities from leaking across those boundaries.
auth · customer · technician · workorder · reporting · common
The hard part
Make double-booking impossible, even during a race.
The service first checks for an overlap so normal conflicts can name the existing work order. PostgreSQL independently guards the same rule with a half-open timestamp range, allowing adjacent appointments while rejecting true overlap.
If simultaneous requests both pass the friendly check, the database accepts one and rejects the other. The constraint violation is translated into the same stable HTTP 409 contract.
EXCLUDE USING gist (
technician_id WITH =,
tstzrange(
scheduled_start,
scheduled_end,
'[)'
) WITH &&
)
WHERE (
status <> 'CANCELLED'
AND scheduled_start IS NOT NULL
AND scheduled_end IS NOT NULL
);{
"status": 409,
"code": "TECHNICIAN_SCHEDULE_CONFLICT",
"detail": "The technician is already assigned during the requested time.",
"conflictingWorkOrderId": "40000000-...-0003"
}Engineering outcomes
The portfolio value is in the guarantees.
Concurrency-safe scheduling
Application checks produce useful conflicts while a PostgreSQL exclusion constraint closes the race between simultaneous requests.
Security at two boundaries
JWT roles and technician ownership are enforced at HTTP and application-service boundaries, with active users revalidated from persistence.
Schema under source control
Six forward-only Flyway migrations define the production schema. Hibernate validates it; application startup never invents it.
Evidence, not assertions
Unit, architecture, HTTP, repository, concurrency, clean-copy, container, vulnerability, and secret-scan checks all run against the release.
Delivery evidence
Reproducible from a clean checkout.
- Java 21 and Maven verification
- Real PostgreSQL integration suite
- Architecture boundary enforcement
- Production-profile startup and restart
- Non-root multi-stage container
- OpenAPI and authenticated smoke test
- Trivy image vulnerability scan
- Gitleaks full-history secret scan
Inspect the implementation
Every claim links back to working code.
The repository includes the complete source, database migrations, API contract, architecture decisions, security policy, demo script, and CI workflow.
Explore jgerton/service-flow