docs: experiment with generated documentation, let's keep it in git for
All checks were successful
Deploy to K8s / deploy (push) Successful in 8s

now
This commit is contained in:
2026-03-11 11:57:30 +01:00
parent e83d6af1f5
commit 9b99f6d33b
17 changed files with 2367 additions and 0 deletions

View File

@@ -0,0 +1,214 @@
# 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.*