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

199 lines
5.8 KiB
Markdown

# 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 <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
```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/<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.*