Speeding rules change over time, so a reading taken on 30 September must be fined by September's rules even if it reaches the server in October. Traffic Engine picks the rule set that was in force on the reading's date, works out the fine, and stores a citation that names the rule version and explains the amount.
Needs Java 21 (brew install --cask temurin@21) and Docker.
# Start PostgreSQL 17
docker compose up -d
# Run with Maven Wrapper (./mvnw on macOS/Linux, mvnw.cmd on Windows)
./mvnw spring-boot:runOpen http://localhost:8080. Flyway automatically applies database migrations and creates the citations table on first start. docker build -t trafficengine . builds the container image.
Defaults match docker-compose.yml. For custom configurations, set environment variables:
| Variable | Default | Purpose |
|---|---|---|
DB_HOST |
localhost |
PostgreSQL host |
DB_PORT |
5432 |
PostgreSQL port |
DB_NAME |
traffic |
Database name |
DB_USER |
traffic |
Database user |
DB_PASSWORD |
traffic |
Database password |
PORT |
8080 |
Application HTTP server port |
- The dashboard sends
POST /api/readingswith a vehicle id, zone, speed and an optional observed time. CitationServicenormalises the ids (school zonebecomesSCHOOL-ZONE) and uses the current time if none was sent.RuleCatalogreturns the rule set whose start date is the latest one on or before the observed time. Rule sets live inapplication.ymland start at midnight India time.SpeedRuleEnginereads the zone's limit (or the default limit) and returnsWITHIN_LIMIT,EXEMPTfor an emergency vehicle, orVIOLATIONwith the fine tier for how far over the limit it is.- A violation is saved as a
Citationwith its rule version and a one-line reason, and is never updated.
Example: 55 km/h in the school zone under the 2026-10 rules is limit 25, +30 over, above the +20 tier, so the fine is ₹3000. The same reading dated 30 September uses 2026-09: limit 30, +25 over, fine ₹2000.
Speeds and fines are BigDecimal in Java and numeric in PostgreSQL, so there is no floating point in the money.
| Method | Path | What it does |
|---|---|---|
POST |
/api/readings |
Judge one reading: 201 with the citation for a violation, 200 otherwise, 400 for bad input |
GET |
/api/citations?zone= |
The newest 50 citations, optionally for one zone |
GET |
/api/citations/{id} |
One citation with its reason, or 404 |
GET |
/api/analytics/summary |
Citation count and fine total per zone |
POST /api/readings
{ "vehicleId": "KA 01 AB 1234", "zone": "school zone", "speedKph": 55 }Errors are Spring ProblemDetail JSON; a 400 lists each rejected field.
./mvnw testRuns 22 pure domain unit tests (SpeedRuleEngineTest) and API slice tests (CitationApiTest) in ~3 seconds. No database or Docker required.
./mvnw verifyRuns the unit tests plus integration tests (CitationRepositoryIT) against an ephemeral PostgreSQL 17 container using Testcontainers. Automatically verifies Flyway database migrations (V1__create_citations.sql), Hibernate schema validation (ddl-auto: validate), and repository queries.
./mvnw package -DskipTestsGenerates an executable Spring Boot fat JAR at target/trafficengine-1.0.0.jar.