Files
fuj-management/docs/by-claude-opus/deployment.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

5.8 KiB

Deployment Guide

Local Development

Prerequisites

  • Python 3.13+ (required by pyproject.toml)
  • uv — Fast Python package manager
  • Google Sheets API credentials (service account JSON)

Setup

git clone <repo-url>
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

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

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:

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/<owner>/<repo>:<tag>

Tag resolution: Uses the git tag name. For manual dispatch, uses the provided input.

2. Deploy to Kubernetes (kubernetes-deploy.yaml)

Triggers:

  • Push to any branch
  • Manual dispatch

Steps:

  1. Checkout code
  2. Install kubectl
  3. Retrieve Kanidm token from HashiCorp Vault:
    • Authenticate to Vault via AppRole (VAULT_ROLE_ID / VAULT_SECRET_ID)
    • Fetch API token from secret/data/gitea/gitea-ci
  4. Exchange API token for K8s OIDC token via Kanidm:
    • POST to https://idm.home.hrajfrisbee.cz/oauth2/token
    • Token exchange using urn:ietf:params:oauth:grant-type:token-exchange
  5. Configure kubectl with the OIDC token
  6. Run kubectl auth whoami and kubectl get ns (deploy commands are commented out — WIP)

Required secrets:

Secret Purpose
REGISTRY_TOKEN Docker registry authentication
VAULT_ROLE_ID HashiCorp Vault AppRole role ID
VAULT_SECRET_ID HashiCorp Vault AppRole secret ID
K8S_CA_CERT Kubernetes cluster CA certificate

Infrastructure Topology

Gitea (git push / tag)
   │
   ├── build.yaml → Docker Build → Gitea Container Registry
   │                                  (gitea.home.hrajfrisbee.cz)
   │
   └── kubernetes-deploy.yaml → Vault → Kanidm → K8s Cluster
                                                   (192.168.0.31:6443)

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.