docs: experiment with generated documentation, let's keep it in git for
All checks were successful
Deploy to K8s / deploy (push) Successful in 8s
All checks were successful
Deploy to K8s / deploy (push) Successful in 8s
now
This commit is contained in:
198
docs/by-claude-opus/deployment.md
Normal file
198
docs/by-claude-opus/deployment.md
Normal file
@@ -0,0 +1,198 @@
|
||||
# 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.*
|
||||
Reference in New Issue
Block a user