Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .mvn/wrapper/maven-wrapper.jar
Binary file not shown.
2 changes: 2 additions & 0 deletions .mvn/wrapper/maven-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
19 changes: 19 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FROM maven:3.9-eclipse-temurin-21 AS builder

WORKDIR /app

COPY pom.xml ./
RUN mvn dependency:go-offline -q

COPY src/ src/
RUN mvn package -DskipTests -q

FROM eclipse-temurin:21-jre-alpine AS runtime

WORKDIR /app

COPY --from=builder /app/target/*.jar app.jar

EXPOSE 4110

ENTRYPOINT ["java", "-jar", "app.jar"]
155 changes: 63 additions & 92 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,116 +1,87 @@
# Allo Bank Backend Developer Take-Home Test
Youtube: https://www.youtube.com/@learnwithkenedy
email: kenedinovriansyah@gmail.com

Welcome, and thank you for your interest in joining Allo Bank Engineering!
# Split Bill API

This challenge is intentionally open-ended. There is no skeleton, no guided steps, and no single correct answer. We want to see how you think, how you structure a solution, and what you consider important in production-grade code.
A Spring Boot REST API for managing shared expenses and calculating settlements among a group of people.

---
## Build & Run

## The Challenge: Split Bill API
**Prerequisites:** Java 17+, Docker (optional)

Build a **Spring Boot REST API** that helps a group of people manage shared expenses and calculate who owes whom at the end.
### Local

Think of a real scenario: a group trip, a team lunch, a shared apartment. People take turns paying for things, and at the end someone needs to figure out the fairest way to settle up.
```bash
GITHUB_USERNAME=kydevx ./mvnw spring-boot:run
```

**Your API should, at minimum, support:**
### Docker

1. Creating a bill group with a name and a list of participants
2. Adding expenses to a group — who paid, how much, and who it was for
3. Retrieving a settlement summary — a clear breakdown of who owes whom and how much
```bash
docker build -t split-bill-api .
docker run -p 4110:4110 -e GITHUB_USERNAME=kydevx split-bill-api
```

Everything else is up to you.
## Example Curl Commands

---
### 1. Create a group

## Technical Requirements
```bash
curl -X POST http://localhost:4110/api/groups \
-H "Content-Type: application/json" \
-d '{
"name": "Weekend Trip",
"participants": ["Alice", "Bob", "Charlie"]
}'
```

These are non-negotiable:
Response includes the `id` needed for subsequent requests.

- **Java 17+**, **Spring Boot**, **Maven**
- **`BigDecimal`** for all monetary values — no `float` or `double`
- **A `Dockerfile`** using a multi-stage build (see `Dockerfile.template` in this repo)
- At least **one unit test** covering your settlement calculation logic
- A **`README.md`** in your submission with:
- How to build and run your project
- Example `curl` commands for each endpoint
- Your **GitHub username** and your calculated **service charge** value (see Personalization section below)
- Answer to the submission question (see below)
### 2. Add an expense

---
```bash
curl -X POST http://localhost:4110/api/groups/{groupId}/expenses \
-H "Content-Type: application/json" \
-d '{
"paidBy": "Alice",
"amount": 60.00,
"description": "Pizza dinner",
"splitAmong": ["Alice", "Bob", "Charlie"]
}'
```

## Personalization

Every settlement response must include two additional fields: `service_charge_pct` and `service_charge_amount`.

The `service_charge_pct` is unique to you and is calculated as follows:

1. Take your GitHub username in **lowercase**
2. Sum the Unicode (ASCII) values of all characters
3. `service_charge_pct = (sum % 10)` — this gives a value between 0 and 9 (representing a percentage)

**Example:** GitHub username `johndoe47`
- Unicode sum: `106+111+104+110+100+111+101+52+55` = `850`
- `service_charge_pct = 850 % 10` = **0** (0%)

The `service_charge_amount` is this percentage applied to the total group expenses.
### 3. Get settlement summary

Include both fields in your settlement response. This value must be computed in code — do not hardcode it.
```bash
curl http://localhost:4110/api/groups/{groupId}/settlement
```

---
Sample response:

## Show Your Skills
```json
{
"groupId": "...",
"groupName": "Weekend Trip",
"totalExpenses": 60.0,
"debts": [
{ "from": "Bob", "to": "Alice", "amount": 20.0 },
{ "from": "Charlie", "to": "Alice", "amount": 20.0 }
],
"serviceChargePct": 7,
"serviceChargeAmount": 4.2
}
```

The minimum requirements get you through the door. What you build beyond that is how you stand out.

Some directions to explore — pick what interests you, or invent your own:

- **Multiple split strategies** — equal split, split by percentage, split by exact amount per person
- **Settlement optimization** — minimize the total number of transactions needed to settle all debts
- **Payment recording** — mark a debt as paid and update outstanding balances
- **Expense categories** — tag expenses (food, transport, accommodation) and show per-category summaries
- **Audit trail** — track when expenses and payments were added

There is no bonus point checklist. We are looking at the quality of what you choose to build, not the quantity.
## Personalization

---
- **GitHub Username:** kydevx
- **Service Charge Calculation:**
- Unicode sum: 107+121+100+101+118+120 = 667
- `service_charge_pct = 667 % 10 = 7` (7%)
- The `service_charge_amount` is 7% of the total group expenses, computed in code at runtime.

## Submission Question

In your `README.md`, answer the following in a short paragraph (3–5 sentences):

> **"What was the hardest design decision you made while building this, and what trade-off did you accept?"**

There is no wrong answer. We ask this because it tells us more about how you think than the code itself.

---

## Submission Process

1. **Create a private GitHub repository** for your solution
2. **Add `allobankdev` as a collaborator** (Settings → Collaborators → Add people)
3. **Include a `Dockerfile`** in the root of your project (see `Dockerfile.template`)
4. **Submit via the form:** [Click Here](https://forms.gle/nZKQ2EjTCPfAKHog7)

The form will ask for:
- Your full name and contact details
- Your private GitHub repository URL
- Your GitHub username (for personalization verification)

> Do not open a Pull Request to this repository. Submissions are private.

---

## What We Look For

| Area | What it signals |
|---|---|
| Data modeling | How you think about domain entities and relationships |
| API design | Clarity, consistency, and REST conventions |
| Monetary handling | Awareness of precision issues in financial systems |
| Code structure | Separation of concerns, readability, maintainability |
| Testing | What you consider worth testing and why |
| Submission answer | Genuine engagement with the problem |

We review every submission before the interview. The interview will include questions directly about your code — be ready to walk through it and extend it live.
**"What was the hardest design decision you made while building this, and what trade-off did you accept?"**

Good luck!
The hardest decision was choosing between an in-memory store and a database. I chose in-memory (ConcurrentHashMap) to keep the setup zero-config and focus the evaluation on the API design and settlement algorithm rather than infrastructure wiring. The trade-off is that all data is lost on restart, but the problem's requirements didn't specify persistence, and the settlement logic is the core deliverable. If this were production, I'd swap in a database repository — the service layer is already fully decoupled from storage through the repository interface, so the migration would be straightforward.
Loading