Skip to content
Build 9234610

2. Tech Stack & Anatomy of a Service

The stack

Layer What we use
Language Java 21 (Temurin)
Framework Spring Boot 3.4.x
Integration Apache Camel 4.6+ (camel-spring-boot-starter)
Build Maven, via the wrapper ./mvnw — there is no global Maven
Messaging Azure Service Bus (camel-azure-servicebus)
Data PostgreSQL (service state); some Snowflake
Scheduling @Scheduled + ShedLock (so only one pod runs a cron job)
Boilerplate Lombok (getters/builders via annotations)
Logging Logstash logback encoder → JSON logs → Datadog
Tracing Micrometer + Brave (distributed traces)
Style Checkstyle (Google baseline, 4-space indent) — build fails on violations

Anatomy of a service

Every service follows the same package convention: com.popsockets.integration.<app> (e.g. order_prc). Inside:

com/popsockets/integration/order_prc/
├── route/            # Camel routes — the pipelines (the heart of the service)
├── controller/       # Spring REST controllers (sync HTTP endpoints)
├── service/          # business logic  (interfaces here, impl/ underneath)
│   └── impl/
├── dto/              # data objects — the shapes of messages in/out
├── configuration/    # Spring @Configuration beans, clients, wiring
├── actuator/         # custom actuator endpoints (e.g. route control)
├── util/             # helpers
└── exceptions/       # custom exception types

And under src/main/resources/:

application.properties        # base config (overridden by Config Server in cloud)
application-dev.yml           # per-environment overrides…
application-qa.yml
application-stage.yml
application-prod.yml
logback-spring.xml            # log format (JSON)
key/                          # AES keys for payload encryption (where used)

Rule of thumb

routes orchestrate, services hold logic, DTOs are the data. If a route is getting fat, the logic probably belongs in a service.

Where the real work lives

Routes are named after the capability they implement, and they read top-to-bottom:

  • CirroIntegrationRouter — talks to the Cirro warehouse system
  • NavOrderReleaseRouter — releases orders to NAV
  • PsSftpRouter / SpsSftpRouter — poll SFTP folders for EDI files
  • IntServiceRouter — calls the internal service layer

Open one, find its configure() method, and follow the from(...) → … → to(...). That single method is the flow.

Booting one up

./mvnw spring-boot:run -Dspring-boot.run.profiles=dev

First run downloads dependencies (~2–3 min); after that boot is a couple of seconds. Full build & test with ./mvnw clean package. More in page 5.