Context
Padelium is a mobile-first fantasy padel app, built on my own, where scores are calculated tournament by tournament.
A fantasy game is only credible if its scoring can be explained and checked, so the weight of the project sits in the backend and the rules of the domain rather than in the screens.
Architecture
The rule I set at the beginning was: managed services at the edges, business logic in Spring Boot.
Supabase provides authentication and the PostgreSQL database. Everything that makes the product what it is lives in a Spring Boot backend, organised by feature rather than by technical layer. Schema changes go through Flyway migrations, and the API is documented with OpenAPI, generated by springdoc. Integration tests run against H2.
The reason for the split is control. Authentication and the database are commodity problems that a managed service handles well, while scoring is the product, and I want it in code that I own and can test.
Domain
The backend owns four things:
- feed ingestion, which brings in match data from a third-party padel data API;
- scoring, which turns that data into points;
- official team snapshots, a fixed record of each team;
- read-only leaderboards, plus the base for private leagues.
Scoring and leaderboards are treated as domain logic of their own, not as something the client calculates or presents on its own.
Mobile client
The client is written in Flutter. State is handled with Riverpod, HTTP calls with Dio and navigation with go_router. Sentry reports errors and PostHog collects product analytics.
Status (beta, paused)
The beta reached three milestones: authentication, the scoring loop and a seeded leaderboard. A beta was deployed.
Development has been paused since May 2026. Scoring currently runs as a manual batch for each tournament, because there is no scheduler yet.
What I would change
The first change would be the scheduler: scoring after every tournament should not depend on me running a batch by hand.
The second would be to finish private leagues, which today exist only as a base. And because all match data comes from one third-party API, I would put a clearer boundary around feed ingestion before adding any other source.