Skip to content
Merged
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
145 changes: 128 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,32 @@

A modern web application for transparently splitting expenses and settling debts among groups. Built with **event sourcing** to maintain a complete audit trail of all financial transactions.

Track shared costs, calculate who owes whom, and manage group finances effortlessly. Perfect for roommates, travel groups, and collaborative projects.

Follows DDD principles for separating the application into generic, core, and supporting domains - enforced by [deptrac](https://github.com/deptrac/deptrac).

## Local Development (Docker Compose)
## Screenshots

<table>
<tr>
<td><img src="./images/login.png" alt="Login view" width="300px"></td>
<td><img src="./images/track.png" alt="Track view" width="300px"></td>
<td><img src="./images/calculate.png" alt="Calculate view" width="300px"></td>
</tr>
</table>

## Prerequisites

### For Docker Compose (Local Development)
- [Make](https://www.gnu.org/software/make/)
- [Docker](https://www.docker.com/)
- [Docker Compose](https://docs.docker.com/compose/)

### For Kubernetes Deployment
- [Make](https://www.gnu.org/software/make/)
- [Docker](https://www.docker.com/)
- [Kubernetes](https://kubernetes.io/) (kind, minikube, or Docker Desktop)
- [Helm 3](https://helm.sh/)

For development without Kubernetes:
## Local Development (Docker Compose)

```bash
make start # Build images, start services, and open in browser
Expand All @@ -20,23 +39,115 @@ make help # Show all available targets

Visit `http://localhost:8000` in your browser.

## Getting Started
## Architecture

```
Browser / Client
┌────────────────┼─────────────────┐
│ :8000 │ :8080 │ :5173 (dev)
▼ ▼ ▼
┌────────────┐ ┌──────────────┐ ┌───────────────┐
│ dashboard │ │ web (Nginx) │ │ npm-dev │
│ (Homer) │ │ │ │ (Vite/React/ │
└────────────┘ └──────┬───────┘ │ TypeScript) │
│ FastCGI └───────────────┘
│ :9000
┌──────────────────┐ async ┌──────────────┐
│ app (PHP-FPM) │────messages────▶│ worker │
│ Symfony │ │ (Messenger) │
└──────────────────┘ └──────────────┘
│ │
└────────────────┬────────────────┘
│ SQL
┌─────────────────┐
│ db (MySQL) │
└─────────────────┘

───────────────────────── Backend Layers ─────────────────────────

### Quick Start (Docker Compose)
┌─────────────────────────────────────────────────────────────────┐
│ Supporting │ Controllers · Auth · Repositories · Async │
│ │ Normalizers · Instrumentation · EventListeners │
├──────────────┴──────────────────────────────────────────────────┤
│ Core │ ExpenseTracker · Calculator │
│ (Domain) │ Event Sourcing · Expenses · Compensation │
├──────────────┴──────────────────────────────────────────────────┤
│ Generic │ Symfony · Doctrine · Twig · DomPDF · Monolog |
| │ PhpParser · phpDocumenter · OpenAPI |
└─────────────────────────────────────────────────────────────────┘
Supporting depends on Core & Generic · Core has no deps
```

## Kubernetes Deployment

```bash
make start # Build image, start services, and open in browser
make help # to show all targets
# Build production images
make prod

# Deploy to cluster
helm upgrade --install app ./helm

# Watch pods come up
kubectl get pods -w

# View application logs
kubectl logs deployment/app-split-fairly-app -f
kubectl logs deployment/app-split-fairly-worker -f

# Access the application
# - Direct: http://localhost:30190
# - Port-forward: kubectl port-forward svc/app-split-fairly-web 8080:80

# Login credentials (auto-loaded from fixtures)
# Email: admin@example.com
# Password: secret
```

Visit `http://localhost:8000` in your browser.
### Kubernetes Architecture

---
```
┌─────────────────────────────────────────────────────────────┐
│ Kubernetes Cluster │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ nginx (web) │ │ app (PHP-FPM) │ │
│ │ Split-Fairly │ │ Deployment │ │
│ │ NodePort:30190 │─→│ Pods × 1 │ │
│ └──────────────────┘ └──────────────────┘ │
│ │ │ │
│ │ Serves SPA │ Processes requests │
│ │ EasyAdmin │ Event sourcing │
│ │ │ Session management │
│ │ ┌─────▼──────┐ │
│ │ │ worker │ │
│ │ │ Pod × 1 │ │
│ │ │ Async jobs │ │
│ │ └────────────┘ │
│ │ │ │
│ └───────────┬───────────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ MySQL │ │
│ │ StatefulSet │ │
│ │ PVC Storage │ │
│ └─────────────┘ │
│ △ │
│ │ init Job │
│ ┌──────┴──────┐ │
│ │ db-init │ │
│ │ (one-time) │ │
│ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
```

<table>
<tr>
<td><img src="./images/login.png" alt="Login view" width="300px"></td>
<td><img src="./images/track.png" alt="Track view" width="300px"></td>
<td><img src="./images/calculate.png" alt="Calculate view" width="300px"></td>
</tr>
</table>
**Components:**
- **nginx (web)**: Serves React SPA frontend, EasyAdmin assets, proxies API to PHP
- **PHP-FPM (app)**: Symfony backend, handles business logic & API endpoints
- **Worker**: Processes async jobs via Messenger (background tasks)
- **MySQL**: Persistent data storage with PVC
- **db-init Job**: One-time database initialization (schema + fixtures)