Skip to content

tomyrd/MendelJavaChallenge

Repository files navigation

Transaction Service, Mendel Java Challenge

This is a simple transaction service implemented in Java using Spring Boot. It allows you to store transactions (along with their parent-child relationships), retrieve transaction IDs by type, and calculate the total amount of a transaction including all its descendants.

It is an implementation of the Mendel Java Code Challenge, specified in Java_Code_Challenge.pdf.

Running the app

With Docker (recommended)

docker build -t transactions-service .
docker run --rm -p 8080:8080 transactions-service

The service listens on port 8080.

With Maven

Requires Java 17+ installed locally (the Maven wrapper handles the rest).

./mvnw spring-boot:run

Running the tests

With Docker

docker build -f Dockerfile.test -t transactions-service-test .
docker run --rm transactions-service-test

With Maven

./mvnw test

API

PUT /transactions/{id}

Creates or overwrites the transaction with id {id}.

Request body:

{ "amount": 5000, "type": "cars", "parent_id": 10 }
Field Type Required Notes
amount double yes
type string yes non-blank
parent_id long no must reference an existing transaction

Response:

{ "status": "ok" }

GET /transactions/types/{type}

Returns the ids of every transaction stored with the given type.

GET /transactions/types/cars
=> [10]

Unexistant types return an empty array, not an error.

GET /transactions/sum/{id}

Returns the sum of the transaction's own amount plus the amount of every transaction transitively linked to it via parent_id (i.e. its full descendant subtree — not its ancestors).

GET /transactions/sum/10
=> { "sum": 20000.0 }

Error responses

Situation Status Body
GET /transactions/sum/{id} for unknown id 404 { "error": "Transaction not found: {id}" }
PUT with a parent_id that doesn't exist 400 { "error": "Invalid parent transaction: {id}" }
PUT that would create a parent cycle 400 { "error": "Transaction parent cycle detected" }

Worked example (from the spec)

PUT /transactions/10 { "amount": 5000, "type": "cars" }                     => { "status": "ok" }
PUT /transactions/11 { "amount": 10000, "type": "shopping", "parent_id": 10 } => { "status": "ok" }
PUT /transactions/12 { "amount": 5000, "type": "shopping", "parent_id": 11 }  => { "status": "ok" }

GET /transactions/types/cars => [10]
GET /transactions/sum/10     => { "sum": 20000.0 }
GET /transactions/sum/11     => { "sum": 15000.0 }

This exact sequence is covered by an integration test (TransactionControllerIntegrationTest.reproducesTheChallengeSpecExample).

Architecture / Design Decisions

  • Layers: for clarity and SOLID principles, the code is organized into three layers. Each layer only depends on interfaces from the layer below it. Specific implementations are later injected by Spring.
    • web (controllers, DTOs, error mapping)
    • service (validation, business rules)
    • repository (storage)
  • Storage: InMemoryTransactionRepository keeps the transactions in a Map<Long, Transaction> plus two secondary indexes to keep both GET endpoints O(1)/O(children) instead of scanning every transaction.
  • Parent validation and cycle detection are not specified in the spec but were added to show some edge case, exception handling.
  • Thread-safety: This requirement is also not mentioned so a simple read-write lock is used to protect the app from concurrent access issues.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors