Files
fuj-management/docs/by-claude-opus/README.md
Jan Novak 9b99f6d33b
All checks were successful
Deploy to K8s / deploy (push) Successful in 8s
docs: experiment with generated documentation, let's keep it in git for
now
2026-03-11 11:57:30 +01:00

215 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# FUJ Management — Comprehensive Documentation
> **FUJ = Frisbee Ultimate Jablonec** — a small sports club in the Czech Republic.
## What Is This Project?
FUJ Management is a purpose-built financial management system for a small ultimate frisbee club. It automates the tedious process of tracking **who attended practice**, **how much they owe**, **who has paid**, and **who still owes money** — a workflow that would otherwise require manual cross-referencing between attendance spreadsheets and bank statements.
The system is built around two Google Sheets (one for attendance, one for payments) and a Fio bank transparent account. A set of Python scripts sync and process the data, while a Flask-based web dashboard provides real-time visibility into fees, payments, and reconciliation status.
### The Problem It Solves
Before this system, the club treasurer had to:
1. **Manually count** attendance marks for each member each month
2. **Calculate** whether each person owes 0, 200, or 750 CZK based on how many times they showed up
3. **Cross-reference** bank statements to figure out who paid and for which month
4. **Chase** members who hadn't paid, often losing track of partial payments and advance payments
5. **Handle edge cases** like members paying for multiple months at once, using nicknames in payment messages, or paying via a family member's account
This system automates steps 14 entirely, and provides tooling for step 5.
## System Overview
```
┌──────────────────────────┐ ┌──────────────────────────┐
│ Attendance Sheet │ │ Fio Bank Account │
│ (Google Sheets) │ │ (transparent account) │
│ │ │ │
│ Members × Dates × ✓/✗ │ │ Incoming payments with │
│ Tier (A/J/X) │ │ sender, amount, message │
└──────────┬───────────────┘ └──────────┬───────────────┘
│ │
│ CSV export │ API / HTML scraping
│ │
▼ ▼
┌─────────────────┐ ┌───────────────────────┐
│ attendance.py │ │ sync_fio_to_sheets.py │
│ │ │ │
│ Fetches sheet, │ │ Syncs bank txns to │
│ computes fees │ │ Payments Google Sheet │
└────────┬────────┘ └───────────┬────────────┘
│ │
│ ▼
│ ┌───────────────────────┐
│ │ Payments Sheet │
│ │ (Google Sheets) │
│ │ │
│ │ Date|Amount|Person| │
│ │ Purpose|Sender|etc. │
│ └───────────┬────────────┘
│ │
│ ┌─────────────────────────┤
│ │ │
│ ▼ ▼
│ ┌──────────────┐ ┌──────────────────┐
│ │infer_payments│ │ match_payments.py │
│ │ .py │ │ │
│ │ │ │ Reconciliation │
│ │ Auto-fills │ │ engine: matches │
│ │ Person, │ │ payments against │
│ │ Purpose, │ │ expected fees │
│ │ Amount │ └────────┬──────────┘
│ └──────────────┘ │
│ │
└────────────────┬───────────────┘
┌──────────────────────┐
│ Flask Web App │
│ (app.py) │
│ │
│ /fees fee │
│ table │
│ /reconcile balance │
│ matrix │
│ /payments ledger │
│ /qr QR code │
└───────────────────────┘
```
## Quick Start
### Prerequisites
- **Python 3.13+**
- **[uv](https://docs.astral.sh/uv/)** — fast Python package manager
- **Google Sheets API credentials** — a service account JSON file placed at `.secret/fuj-management-bot-credentials.json`
- *Optional*: `FIO_API_TOKEN` environment variable for Fio REST API access (falls back to transparent page scraping)
### Setup
```bash
# Clone and install dependencies
git clone <repo-url>
cd fuj-management
uv sync # Installs all dependencies from pyproject.toml
# Place your Google API credentials
mkdir -p .secret
cp /path/to/your/credentials.json .secret/fuj-management-bot-credentials.json
```
### Common Operations
| Command | Purpose |
|---------|---------|
| `make web` | Start the web dashboard at `http://localhost:5001` |
| `make sync` | Pull new bank transactions into the Google Sheet |
| `make infer` | Auto-fill Person/Purpose/Amount for new transactions |
| `make reconcile` | Print a CLI balance report |
| `make fees` | Print fee calculation table from attendance |
| `make test` | Run the test suite |
| `make image` | Build the Docker container image |
### Typical Workflow
```
make sync → make infer → (manual review in Google Sheets) → make web
↓ ↓ ↓ ↓
Pull new bank Auto-match Fix any [?] View live
transactions payments to flagged rows dashboard
into sheet members/months in the sheet
```
## Documentation Index
| Document | Contents |
|----------|----------|
| [Architecture](architecture.md) | System design, data flow diagrams, module dependency graph |
| [Web Application](web-app.md) | Flask app architecture, routes, templates, interactive features |
| [User Guide](user-guide.md) | End-user guide for the web dashboard — what each page shows |
| [Scripts Reference](scripts.md) | Detailed reference for all CLI scripts and shared modules |
| [Data Model](data-model.md) | Google Sheets schemas, fee calculation rules, bank integration |
| [Deployment](deployment.md) | Docker containerization, Gitea CI/CD, Kubernetes deployment |
| [Testing](testing.md) | Test infrastructure, coverage, how to write new tests |
| [Development Guide](development.md) | Local setup, coding conventions, tooling, project history |
## Technology Stack
| Layer | Technology |
|-------|-----------|
| Language | Python 3.13+ |
| Web framework | Flask 3.1 |
| Package management | uv + pyproject.toml |
| Data sources | Google Sheets API, Fio Bank API / HTML scraping |
| QR codes | `qrcode` library (PIL backend) |
| Containerization | Docker (Alpine-based) |
| CI/CD | Gitea Actions |
| Deployment target | Self-hosted Kubernetes |
| Frontend | Server-rendered HTML/CSS/JS (terminal-aesthetic theme) |
## Project Structure
```
fuj-management/
├── app.py # Flask web application (4 routes)
├── Makefile # Build automation (13 targets)
├── pyproject.toml # Python dependencies and metadata
├── scripts/
│ ├── attendance.py # Shared: attendance data + fee calculation
│ ├── calculate_fees.py # CLI: print fee table
│ ├── match_payments.py # Core: reconciliation engine + CLI report
│ ├── infer_payments.py # Auto-fill Person/Purpose in Google Sheet
│ ├── sync_fio_to_sheets.py # Sync Fio bank → Google Sheet
│ ├── fio_utils.py # Shared: Fio bank data fetching
│ └── czech_utils.py # Shared: diacritics normalization + Czech month parsing
├── templates/
│ ├── fees.html # Attendance/fees dashboard
│ ├── reconcile.html # Payment reconciliation with modals + QR
│ └── payments.html # Payments ledger grouped by member
├── tests/
│ ├── test_app.py # Flask route tests (mocked data)
│ └── test_reconcile_exceptions.py # Reconciliation with fee exceptions
├── build/
│ ├── Dockerfile # Alpine-based container image
│ └── entrypoint.sh # Container entry point
├── .gitea/workflows/
│ ├── build.yaml # CI: build + push Docker image
│ └── kubernetes-deploy.yaml # CD: deploy to K8s cluster
├── .secret/ # (gitignored) API credentials
├── docs/ # Project documentation
│ ├── project-notes.md # Original brainstorming and design notes
│ ├── fee-calculation-spec.md # Fee rules and payment matching spec
│ ├── scripts.md # Legacy scripts documentation
│ └── spec/
│ └── fio_to_sheets_sync.md # Fio-to-Sheets sync specification
└── CLAUDE.md # AI assistant context file
```
## Key Design Decisions
1. **No database** — Google Sheets serves as both the data store and the manual editing interface. This keeps the system simple and accessible to non-technical club members who can review and edit data directly in the spreadsheet.
2. **PII separation** — No member names or personal data are stored in the git repository. All data is fetched at runtime from Google Sheets and the bank account.
3. **Idempotent sync** — The Fio-to-Sheets sync uses SHA-256 hashes as deduplication keys, making re-runs safe and append-only.
4. **Graceful fallbacks** — Bank data can be fetched via the REST API (if a token is available) or by scraping the public transparent account page. The system doesn't break if the API token is missing.
5. **Czech language support** — Payment messages are in Czech and use diacritics. The system normalizes text (strips diacritics) and understands Czech month names in all grammatical declensions.
6. **Terminal aesthetic** — The web dashboard uses a monospace, dark-themed, terminal-inspired design that matches the project's pragmatic, CLI-first philosophy.
---
*This documentation was generated on 2026-03-03 by Claude Opus, based on a comprehensive analysis of the complete codebase.*