116 lines
3.2 KiB
Markdown
116 lines
3.2 KiB
Markdown
# myboker.org
|
|
|
|
Flask app for running home-poker leagues without keeping a spreadsheet open all night.
|
|
|
|
The current app is account-based and league-based. League owners/managers record sessions and ledger events, viewers can inspect public-facing league data, and site-admin access is reserved for internal tooling.
|
|
|
|
## What It Does
|
|
|
|
- account signup, login, and email verification
|
|
- league creation, invitations, ownership transfer, and member roles
|
|
- player, season, session, and ledger management per league
|
|
- append-only ledger events with void/correction support
|
|
- public/private league visibility
|
|
- leaderboards, charts, dashboard stats, and session summaries
|
|
- CSV import/export for league ledgers
|
|
|
|
## Stack
|
|
|
|
- Python
|
|
- Flask
|
|
- SQLAlchemy / Flask-Migrate
|
|
- Jinja templates
|
|
- Chart.js
|
|
- plain CSS
|
|
|
|
## Project Layout
|
|
|
|
- `app.py` is the deployment entrypoint for `flask --app app` and Gunicorn.
|
|
- `boker/` contains the Flask application package, routes, models, services, repositories, and config.
|
|
- `templates/` and `static/` contain Jinja views and public assets.
|
|
- `migrations/` contains Alembic migrations for database deploys.
|
|
- `tests/` contains the committed regression suite.
|
|
|
|
## Ledger Model
|
|
|
|
Each ledger row is an event, not a final snapshot. Corrections are made by appending or voiding events, so the history remains auditable.
|
|
|
|
Current event types:
|
|
|
|
- `buyin`
|
|
- `front`
|
|
- `debt_repayment`
|
|
- `writeoff`
|
|
- `cashout`
|
|
- `paid_out`
|
|
- `rollover_in`
|
|
- `payout_carry_in`
|
|
- `rollover_out`
|
|
- `note`
|
|
- `session_open`
|
|
- `session_close`
|
|
|
|
Accounting 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 without counting as poker investment or cash in
|
|
- `writeoff` resolves a receivable without counting as cash in
|
|
|
|
Older imports may still contain `paid`, `front_collected`, or `front_writeoff`; those are read as aliases for `paid_out`, `debt_repayment`, and `writeoff`.
|
|
|
|
## Running 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:5000`
|
|
|
|
## Environment Values
|
|
|
|
The app reads these from `.env`:
|
|
|
|
- `SECRET_KEY`
|
|
- `APP_ENV`
|
|
- `DATABASE_URL`
|
|
- `APP_BASE_URL`
|
|
- `RATELIMIT_STORAGE_URI`
|
|
- `MAIL_SERVER`
|
|
- `MAIL_PORT`
|
|
- `MAIL_USE_TLS`
|
|
- `MAIL_USE_SSL`
|
|
- `MAIL_USERNAME`
|
|
- `MAIL_PASSWORD`
|
|
- `MAIL_DEFAULT_SENDER`
|
|
|
|
For public deployments, set `APP_ENV=production`. Production mode enables secure cookies and refuses to start with the development `SECRET_KEY`. Set `RATELIMIT_STORAGE_URI` to a shared backend such as Redis so login and signup limits are enforced across processes.
|
|
|
|
## Site Admin Access
|
|
|
|
Internal admin access uses normal database-backed accounts, not hardcoded `.env` credentials.
|
|
|
|
Grant access:
|
|
|
|
```bash
|
|
flask --app app grant-site-admin user@example.com
|
|
```
|
|
|
|
Revoke access:
|
|
|
|
```bash
|
|
flask --app app revoke-site-admin user@example.com
|
|
```
|
|
|
|
The old single-password `/admin` system has been removed.
|