The workflow ran on every push to every branch and deployed nothing. It echoed the raw Vault login response, the Kanidm API token response and the OIDC token response to the job log, dumped the environment, and configured kubectl with --insecure-skip-tls-verify. Deployment is handled by gitops-update.yaml. Docs updated to describe that flow; T1 marked done in the cleanup task list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5.6 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:
- Install system packages (
bash,tzdata) - Set timezone to
Europe/Prague - Install Python dependencies via pip
- Copy application files (
app.py,scripts/,templates/,Makefile) - 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:
- Checkout code
- Login to Gitea container registry (
gitea.home.hrajfrisbee.cz) - Build Docker image using
build/Dockerfile - Push to
gitea.home.hrajfrisbee.cz/<owner>/<repo>:<tag>
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_runanduh_cli_versioninputs)
Steps:
- Install
teaanduh-cli - Resolve the image tag of the Go image that was just built
- Open a PR in
kacerr/home-kubernetesbumping thefuj-managementDeployment (namespacefuj) 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.yamlworkflow (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.