Java 21, Spring Boot, MyBatis, port 8080. The service that accepts orders, records
them, publishes them, and answers every question the frontend asks about an account.
This is the largest of the six and the one that grows most. It starts in Sprint 6 as a controller,
a service layer and a set of mappers. Sprint 5's domain model is absorbed into it as a source package
rather than a separate artifact, so a clean checkout builds with one command. Sprint 10 adds the
extension modules as further packages inside the same deployable, each with its own routes and its own
consumer group.
Read the diagram top to bottom. A request enters at web, is authenticated at
security, is orchestrated at service, is decided at domain, is
persisted at repository and is published at messaging. The direction never
reverses. The domain package holds no Spring annotation beyond validation and performs no I/O, and that
rule is now enforced by review rather than by a Maven boundary.
Package names and class names are the ones in the source tree. The extension packages are
the ones a team creates in Sprint 10, one per capability it picks from the catalogue.
The two execution modes
TRADING_EXECUTION_MODE decides what POST /api/v1/orders returns, and it is
the single switch that separates Sprint 6 from Sprint 7. Set it deliberately and know which one you are
running.
Mode
Sprint
What happens
Response
sync
6
Validate, settle in process, write the order and the position, return. No broker involved.
FILLED or REJECTED
async
7 onwards, the default
Validate, insert the order, publish to orders after the commit, return.
NEW
What this service owns and what it does not
Owns
Does not own
Validating an order against the five business rules
Deciding the fill price. That is the executor's job, against a live quote.
Recording the order with a unique idempotency_key
Moving cash or updating a position on a fill. That happens in the executor's transaction.
Publishing ORDER_PLACED to orders
Publishing to trade-events. It consumes that topic, it does not write to it.
Verifying the JWT on every /api/** route
Issuing or refreshing a JWT, and hashing a password.
Serving the portfolio routes from the extension modules
Holding a Fauxnance key. It has no reason to call that API.
Where extension modules change the security problem
In a separate service a team could lean on the service boundary for authorisation. Inside one
application there is no boundary to lean on. Every extension route enforces its own account check, and
a route that returns another customer's portfolio is now a defect in the same process that holds the
order book. The Sprint 10 security review has more to find, not less.