133 lines
3.7 KiB
Markdown
133 lines
3.7 KiB
Markdown
# Poker Portal
|
|
|
|
A small Flask app I put together for tracking our low-stakes hold'em nights without having to keep a spreadsheet open all the time.
|
|
|
|
The idea is pretty simple: public pages for stats and session history, plus a small admin area for recording buy-ins, gross cashout results, actual paid-out cash, and notes. The data sits in a CSV audit log, so everything is append-only and easy to follow later.
|
|
|
|
## What it does
|
|
|
|
- all-time leaderboard
|
|
- per-session pages
|
|
- per-player stat pages
|
|
- admin login for recording events
|
|
- open / closed session tracking
|
|
- actual cash payout tracking with `paid_out` events
|
|
- debt repayments and write-offs with `debt_repayment` / `writeoff` events
|
|
- session and player charts
|
|
- CSV import / export from the admin page
|
|
- append-only `entries.csv` ledger instead of overwriting old rows
|
|
|
|
## Stack
|
|
|
|
Built with a pretty lightweight setup:
|
|
|
|
- Python
|
|
- Flask
|
|
- Jinja templates
|
|
- Chart.js
|
|
- plain CSS
|
|
- CSV event log for storage
|
|
|
|
## Ledger model
|
|
|
|
The app treats `data/entries.csv` as the source of truth.
|
|
|
|
Each row is an event, not a final snapshot. Instead of editing an old row, I append another one. That keeps rebuys, corrections, payouts, and session state changes visible in the log instead of hiding them behind edits.
|
|
|
|
Current event types:
|
|
|
|
- `buyin`
|
|
- `front`
|
|
- `debt_repayment`
|
|
- `writeoff`
|
|
- `cashout`
|
|
- `paid_out`
|
|
- `rollover_in`
|
|
- `payout_carry_in`
|
|
- `rollover_out`
|
|
- `note`
|
|
- `session_open`
|
|
- `session_close`
|
|
|
|
A few examples:
|
|
|
|
- another `buyin` for a rebuy
|
|
- another `cashout` if chip counts are corrected later
|
|
- a `paid_out` event when someone is actually settled up
|
|
- a `debt_repayment` event when a front is repaid outside poker
|
|
- a `writeoff` event when a front will not be collected
|
|
- a `note` event for bookkeeping context
|
|
- `session_open` / `session_close` to mark whether a game night is still live
|
|
|
|
Accounting in the app keeps poker results separate from banker cashflow:
|
|
|
|
- poker investment is `buyin + front + rollover_in`
|
|
- poker net is `cashout - poker investment`
|
|
- real cash in is `buyin + debt_repayment`
|
|
- real cash out is `paid_out`
|
|
- `rollover_out` settles the source session without counting as cash out
|
|
- `rollover_in` enters play in the destination session without counting as cash in
|
|
- `payout_carry_in` records prior-session value carried into a later payout; it increases the destination payout due without counting as poker investment or cash in
|
|
- `writeoff` resolves a receivable without counting as cash in
|
|
|
|
Older ledgers may still contain `paid`, `front_collected`, or `front_writeoff`.
|
|
The app reads those historical names as aliases for `paid_out`,
|
|
`debt_repayment`, and `writeoff`.
|
|
|
|
It is still just a small side project, but I wanted the event model to stay clean enough that the numbers are easy to trust and the history is easy to read back through.
|
|
|
|
## CSV format
|
|
|
|
Main file:
|
|
|
|
`data/entries.csv`
|
|
|
|
Header:
|
|
|
|
```csv
|
|
id,created_at,session_id,session_date,player_name,event_type,amount_cents,note,actor
|
|
```
|
|
|
|
Amounts are stored in cents to avoid floating-point issues.
|
|
|
|
## Running it locally
|
|
|
|
```bash
|
|
python -m venv .venv
|
|
source .venv/bin/activate
|
|
pip install -r requirements.txt
|
|
cp .env.example .env
|
|
python app.py
|
|
```
|
|
|
|
Then open:
|
|
|
|
`http://127.0.0.1:8000`
|
|
|
|
## Environment values
|
|
|
|
The app reads these from `.env`:
|
|
|
|
- `SECRET_KEY`
|
|
- `ADMIN_USERNAME`
|
|
- `ADMIN_PASSWORD`
|
|
|
|
Example:
|
|
|
|
```env
|
|
SECRET_KEY=change-this
|
|
ADMIN_USERNAME=admin
|
|
ADMIN_PASSWORD=change-me
|
|
```
|
|
|
|
## Notes
|
|
|
|
A few choices here were deliberate:
|
|
|
|
- no database for now
|
|
- no user accounts, just one admin login
|
|
- public-facing stats pages, admin-only controls
|
|
- CSV backup before importing a replacement ledger
|
|
|
|
If I ever decide to take it further, the first real upgrade would probably be moving the storage layer to SQLite while keeping the rest of the app roughly the same.
|