The problem
A planned billiard club needed a complete operational platform — for members to reserve tables, sign up for tournaments, and track their matches; for staff to manage tables, tournaments, billing, and league seasons. All of it from day one.
What we built
Three components. .NET, with a full domain model (tables, reservations, tournaments with bracket visualization, seasons, table-session billing, user accounts, employees). A Next.js dashboard for staff. A native iOS + Android app (Expo + React Native) for members. Identity through Keycloak, so member authentication, SSO between apps, and staff role management were enterprise-grade from the start. Centralized logging through Seq, so every incident can be found quickly.
Modules & surfaces
- Table reservationsMembers reserve tables from the mobile app; staff see and manage reservations from the dashboard.
- Tournaments with bracket visualizationFull tournament cycle — sign-up, bracket creation, result tracking, final standings. A dedicated page for visual bracket display.
- SeasonsA module for organizing league seasons — calendar, participants, linking tournaments to a season.
- Table-session billing (turnovers)Tracking how much was played on which table and how much was billed — operational records for the club owner.
- Members and user accountsMember registration, profiles, tournament and reservation history.
- Employees and rolesStaff with different access levels — operators, managers — with roles.
- Centralized log (Seq)Every important event in the system (reservation creation, deletion, failed auth) goes to Seq, where it can be searched and alerted on.
- Native mobile appiOS + Android through one Expo / React Native codebase — members reserve, sign up for tournaments, see their history.
- Staff dashboardA Next.js app — overview of all reservations, tournament and season management, session billing, reports.
How we approached it
We approached the system as a long-running project. We chose Keycloak because member authentication isn't trivial (SSO across apps, OAuth flow for the mobile app, password reset, role-based access) and we didn't want to reinvent it. We chose Seq because running a club system means quickly answering "why didn't this member's reservation go through" — without centralized logs, that would be an hour of digging through server files. Clean Architecture for the API because we expected long iteration cycles, with new features arriving over the club's years of operation.
Outcome
Built, tested, ready for production. The club hasn't opened, so the system isn't yet in actual use. The project stays in the portfolio as evidence of how we approach systems intended for long-term use — the architectural decisions still stand, even though the launch hasn't happened yet.