# Deployment Guide ## Local Development ### Prerequisites - **Python 3.13+** (required by `pyproject.toml`) - **[uv](https://docs.astral.sh/uv/)** — Fast Python package manager - Google Sheets API credentials (service account JSON) ### Setup ```bash git clone cd fuj-management # Install dependencies uv sync # Configure credentials mkdir -p .secret cp /path/to/credentials.json .secret/fuj-management-bot-credentials.json # Optional: Set Fio API token for richer bank data export FIO_API_TOKEN=your_token_here # Start the web dashboard make web # → Flask server at http://localhost:5001 ``` ### Makefile Targets | Target | Command | Description | |--------|---------|-------------| | `help` | `make help` | List all available targets | | `venv` | `make venv` | Sync virtual environment with pyproject.toml | | `fees` | `make fees` | Print fee calculation table | | `match` | `make match` | (Legacy) Direct bank matching | | `web` | `make web` | Start Flask dashboard on port 5001 | | `sync` | `make sync` | Sync last 30 days of bank transactions | | `sync-2026` | `make sync-2026` | Sync full year 2026 transactions | | `infer` | `make infer` | Auto-fill Person/Purpose in the sheet | | `reconcile` | `make reconcile` | Print CLI balance report | | `test` | `make test` | Run test suite | | `test-v` | `make test-v` | Run tests with verbose output | | `image` | `make image` | Build Docker image | | `run` | `make run` | Run Docker container locally | The Makefile includes **automatic venv management**: targets that need Python depend on `.venv/.last_sync`, which triggers `uv sync` when `pyproject.toml` changes. --- ## Docker Container ### Building ```bash make image # → docker build -t fuj-management:latest -f build/Dockerfile . ``` ### Dockerfile Details **Base image**: `python:3.13-alpine` **Build stages**: 1. Install system packages (`bash`, `tzdata`) 2. Set timezone to `Europe/Prague` 3. Install Python dependencies via pip 4. Copy application files (`app.py`, `scripts/`, `templates/`, `Makefile`) 5. Copy entrypoint script **Exposed port**: 5001 **Health check**: `wget -q -O /dev/null http://localhost:5001/` every 60s ### Running Locally via Docker ```bash make run # → docker run -it --rm -p 5001:5001 fuj-management:latest # With credentials and environment: docker run -it --rm \ -p 5001:5001 \ -v $(pwd)/.secret:/app/.secret:ro \ -e FIO_API_TOKEN=your_token \ -e BANK_ACCOUNT=CZ8520100000002800359168 \ fuj-management:latest ``` ### Entrypoint The `build/entrypoint.sh` script simply runs: ```bash exec python3 /app/app.py ``` This uses Flask's built-in server directly. For a production deployment, consider adding gunicorn or waitress (noted as a TODO in the entrypoint). ### Environment Variables | Variable | Default | Description | |----------|---------|-------------| | `BANK_ACCOUNT` | `CZ8520100000002800359168` | IBAN for QR code generation | | `FIO_API_TOKEN` | *(none)* | Fio REST API token | | `PYTHONUNBUFFERED` | `1` (set in Dockerfile) | Ensures real-time log output | --- ## CI/CD Pipeline ### Gitea Actions The project uses two Gitea Actions workflows: #### 1. Build and Push (`build.yaml`) **Triggers**: - Push of any tag - Manual dispatch (with custom tag input) **Steps**: 1. Checkout code 2. Login to Gitea container registry (`gitea.home.hrajfrisbee.cz`) 3. Build Docker image using `build/Dockerfile` 4. Push to `gitea.home.hrajfrisbee.cz//:` **Tag resolution**: Uses the git tag name. For manual dispatch, uses the provided input. #### 2. GitOps image update (`gitops-update.yaml`) **Triggers**: - Completion of a successful "Build and Push" run - Manual dispatch (with `tag`, `dry_run` and `uh_cli_version` inputs) **Steps**: 1. Install `tea` and `uh-cli` 2. Resolve the image tag of the Go image that was just built 3. Open a PR in `kacerr/home-kubernetes` bumping the `fuj-management` Deployment (namespace `fuj`) to that image The cluster picks the change up once that PR is merged. CI does not talk to the cluster directly. > The earlier `kubernetes-deploy.yaml` workflow (Vault → Kanidm → `kubectl`) was removed on 2026-10-08. It never deployed anything and printed credentials to the job log. **Required secrets**: | Secret | Purpose | |--------|---------| | `REGISTRY_TOKEN` | Docker registry authentication | | `GITOPS_TOKEN` | Gitea token with write and PR access to `home-kubernetes` | ### Infrastructure Topology ``` Gitea (git push / tag) │ ├── build.yaml → Docker Build → Gitea Container Registry │ (gitea.home.hrajfrisbee.cz) │ └── gitops-update.yaml → PR in home-kubernetes → K8s Cluster ``` This is a self-hosted infrastructure stack: - **Gitea** for git hosting and CI/CD - **HashiCorp Vault** for secret management - **Kanidm** for identity/OIDC - **Kubernetes** for container orchestration --- ## Credentials Management ### Google Sheets API The system uses a **Google Cloud service account** for accessing the Payments Google Sheet. The credentials file must be: - Stored at `.secret/fuj-management-bot-credentials.json` - In Google Cloud service account JSON format - The service account must be shared (as editor) on the target Google Sheet For local development with OAuth2 (personal Google account), the system also supports the OAuth2 installed app flow — it will generate a `token.pickle` file on first use. ### Fio Bank API Optional. Set the `FIO_API_TOKEN` environment variable. The token is generated in Fio internetbanking under Settings → API. **Rate limit**: 1 request per 30 seconds per token. --- *Deployment documentation generated from comprehensive code analysis on 2026-03-03.*