mirror of
https://github.com/Alkatrazz24/Funk-lab.git
synced 2026-07-08 11:44:43 +02:00
feat(finlab): dashboard web (graphiques/portefeuille/actions) + fix seed NFS (#65)
Ajoute une interface graphique à finlab, en plus de la console Claude Code (les deux cohabitent sur finance.lab.local) : - dashboard/ : backend FastAPI (sans LLM/clé) exposant les données finlab en JSON (/api/portfolio, /api/scan, /api/ohlc, /api/plan, /api/alerts) + front statique (lightweight-charts) : graphiques chandeliers MM50/200 + volume, portefeuille (P&L/poids/secteurs), watchlists thématiques scannées, alertes, plan de trade R:R - Découplage code/data : finlab lit ses configs depuis FINLAB_HOME si défini (workspace persistant) ; repli sur le dossier du package en dév local - Image double usage (un build, deux conteneurs) : code → /opt/app, seed minimal (configs + persona + MCP) → workspace - Fix seed NFS (cause racine du workspace vide) : WORKDIR n'est plus sur le volume (le runtime le créait en root sur NFS) ; seed déplacé dans un initContainer robuste (recrée le dossier s'il est non-inscriptible) - Deployment : initContainer seed + 2 conteneurs (console ttyd -b /console, dashboard uvicorn) ; Service 2 ports ; IngressRoute 2 routes (/console + dashboard), basicAuth Validé en local (podman) : seed OK, dashboard /api/portfolio → 16k€/10 positions via FINLAB_HOME, endpoints ohlc/scan/plan/alerts OK, ttyd/claude/finlab présents. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
607e5e6c0a
commit
56cb32eacc
19 changed files with 700 additions and 149 deletions
|
|
@ -1,32 +1,34 @@
|
|||
# FinLab — console Claude Code finance (in-cluster)
|
||||
# FinLab — dashboard + console Claude Code (in-cluster)
|
||||
|
||||
Une **vraie session Claude Code** (sur l'**abonnement** d'Alkatrazz, login persisté) servie
|
||||
dans un **terminal web** (`ttyd`), spécialisée analyse de marché via la persona `CLAUDE.md` et
|
||||
la boîte à outils **finlab** (Yahoo Finance, exposée en **MCP**). Esprit OpenAlice, mais c'est
|
||||
Claude Code + le toolkit maison — **aucune facturation API**, **aucun broker**, analyse seule.
|
||||
Deux usages, **une image**, un workspace partagé :
|
||||
|
||||
> ⚠️ La console expose un **shell web** → protégée par **basicAuth Traefik**. Analyse et aide à
|
||||
> la décision uniquement : **aucun ordre réel** (seul le paper trading Alpaca fictif existe).
|
||||
- **Dashboard** (`finance.lab.local/`) — interface web : graphiques chandeliers (MM50/200 +
|
||||
volume), portefeuille (P&L, poids, secteurs), watchlists thématiques scannées, alertes du
|
||||
jour, actions (plan de trade R:R). Données finlab (Yahoo Finance) — **aucun LLM, aucune clé**.
|
||||
- **Console** (`finance.lab.local/console/`) — vraie session **Claude Code** dans un terminal
|
||||
web (`ttyd`), sur ton **abonnement** (login persisté), persona finance + outils finlab en MCP.
|
||||
|
||||
## Image
|
||||
> ⚠️ La console expose un **shell web** → tout est derrière **basicAuth Traefik**. Analyse et
|
||||
> aide à la décision uniquement : **aucun ordre réel** (paper trading Alpaca fictif seul).
|
||||
|
||||
Pas d'image publique : la CI (`.github/workflows/build-finlab.yml`) build depuis
|
||||
`tools/finlab/` (notre code) → `ghcr.io/alkatrazz24/funk-finlab`, tag `sha-<court>`, bump du
|
||||
manifest sur `main`.
|
||||
## Image & code
|
||||
|
||||
## Architecture du déploiement
|
||||
CI (`.github/workflows/build-finlab.yml`) build depuis `tools/finlab/` → `ghcr.io/alkatrazz24/funk-finlab`.
|
||||
Le **code** (package `finlab` + backend `dashboard`) vit dans l'image (`/opt/app`) et se met à
|
||||
jour avec elle. Les **configs éditables** (portefeuille/watchlists/alertes) + la persona + le
|
||||
login vivent dans le **workspace persistant** (`FINLAB_HOME=/home/finlab/workspace`, sur le PVC).
|
||||
|
||||
| Composant | Détail |
|
||||
## Architecture du pod
|
||||
|
||||
| Élément | Rôle |
|
||||
|---|---|
|
||||
| Deployment | 1 réplica, `Recreate` (volume RWO), PodSecurity *restricted* (uid 1000, `fsGroup` 1000) |
|
||||
| PVC `finlab-data` | 5Gi NFS → `/home/finlab` : `~/.claude` (login abonnement) + workspace (code finlab seedé, `portfolio.yaml`/`watchlists.yaml`/`alerts.yaml` éditables, `.cache`) |
|
||||
| Service `finlab` | `web:7681` (ttyd) |
|
||||
| Middleware `finlab-auth` | basicAuth Traefik (secret `finlab-auth`, htpasswd) |
|
||||
| IngressRoute | `finance.lab.local` → 7681 (via `finlab-auth`) |
|
||||
|
||||
Le workspace est **seedé depuis l'image au 1er boot** (`cp -rn`, no-clobber) puis vit sur le
|
||||
PVC : tes edits (portefeuille, etc.) et ton login persistent ; une nouvelle image n'apporte que
|
||||
les fichiers manquants.
|
||||
| initContainer `seed` | Peuple le workspace depuis l'image (`cp -rn`), robuste au piège NFS (recrée le dossier si root/non-inscriptible). Tourne **avant** les conteneurs |
|
||||
| container `console` | `ttyd -b /console` → `claude` dans le workspace (port 7681) |
|
||||
| container `dashboard` | `uvicorn dashboard.server:app` (port 8800), lit `FINLAB_HOME` |
|
||||
| PVC `finlab-data` (5Gi NFS) | `/home/finlab` : `~/.claude` (login) + workspace (configs + `.cache`) |
|
||||
| Service `finlab` | `web:8800` + `console:7681` |
|
||||
| Middleware `finlab-auth` | basicAuth Traefik (secret htpasswd) |
|
||||
| IngressRoute | `/console` → 7681 · reste → 8800 (les deux derrière `finlab-auth`) |
|
||||
|
||||
## Pré-requis manuels (une fois)
|
||||
|
||||
|
|
@ -34,35 +36,21 @@ les fichiers manquants.
|
|||
|
||||
```bash
|
||||
kubectl -n ai create secret docker-registry ghcr-pull \
|
||||
--docker-server=ghcr.io \
|
||||
--docker-username=Alkatrazz24 \
|
||||
--docker-server=ghcr.io --docker-username=Alkatrazz24 \
|
||||
--docker-password=<GHCR_PAT_read_packages>
|
||||
```
|
||||
|
||||
### 2. Secret basicAuth de la console (`finlab-auth`)
|
||||
### 2. Secret basicAuth `finlab-auth`
|
||||
|
||||
```bash
|
||||
# htpasswd (paquet apache2-utils). Remplace <user>/<pass>.
|
||||
htpasswd -nbB <user> '<pass>' > /tmp/finlab.htpasswd
|
||||
kubectl -n ai create secret generic finlab-auth \
|
||||
--from-file=users=/tmp/finlab.htpasswd
|
||||
rm -f /tmp/finlab.htpasswd
|
||||
--from-literal=users="alkatrazz:$(openssl passwd -apr1 'MOT_DE_PASSE')"
|
||||
```
|
||||
|
||||
### 3. Premier boot — login Claude Code (abonnement)
|
||||
### 3. Premier boot — login Claude Code (pour la console)
|
||||
|
||||
1. Ouvrir **http://finance.lab.local** (basicAuth → identifiants de l'étape 2).
|
||||
2. Dans le terminal, lancer `claude`, puis `/login` → suivre l'OAuth (ouvrir l'URL sur ta
|
||||
machine, autoriser, coller le code). Persisté dans `~/.claude` sur le PVC.
|
||||
3. À l'invite, FinLab a déjà sa persona (`CLAUDE.md`) et les outils finlab (MCP `finlab`,
|
||||
auto-activé). Essaie : *« résume mon portefeuille »*, *« plan de trade pour Micron »*.
|
||||
1. Ouvrir **http://finance.lab.local/console/** (basicAuth), lancer `claude`, puis `/login`.
|
||||
2. Le dashboard est sur **http://finance.lab.local/** (rien à configurer).
|
||||
|
||||
> Le workspace `/home/finlab/workspace` contient `portfolio.yaml` etc. — éditables directement
|
||||
> (par toi ou par Claude à ta demande). Pour une vue rapide hors console :
|
||||
> `kubectl -n ai exec deploy/finlab -- python -m finlab.cli digest`.
|
||||
|
||||
## Accès depuis le terminal (sans navigateur)
|
||||
|
||||
```bash
|
||||
kubectl -n ai exec -it deploy/finlab -- bash -lc 'cd "$WORKSPACE" && claude'
|
||||
```
|
||||
> Configs éditables dans le workspace (`portfolio.yaml`…) : depuis la console, ou
|
||||
> `kubectl -n ai exec deploy/finlab -c console -- python -m finlab.cli digest`.
|
||||
|
|
|
|||
|
|
@ -16,12 +16,9 @@ spec:
|
|||
labels:
|
||||
app: finlab
|
||||
spec:
|
||||
# Image privée sur GHCR → secret de pull créé manuellement dans le ns ai
|
||||
# (cf. README : kubectl create secret docker-registry ghcr-pull ...).
|
||||
imagePullSecrets:
|
||||
- name: ghcr-pull
|
||||
# Conformité PodSecurity « restricted » (namespace ai). fsGroup 1000 → le PVC NFS monté
|
||||
# en /home/finlab (HOME : ~/.claude du login abonnement + workspace) est inscriptible.
|
||||
# PodSecurity « restricted » (ns ai). fsGroup 1000 → PVC NFS monté en /home/finlab.
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
|
|
@ -29,40 +26,72 @@ spec:
|
|||
fsGroup: 1000
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: finlab
|
||||
# Tag bumpé par la CI (build-finlab.yml) sur main.
|
||||
# initContainer : prépare le workspace (seed robuste NFS) AVANT console + dashboard,
|
||||
# pour qu'il soit peuplé et inscriptible quand les deux conteneurs démarrent.
|
||||
initContainers:
|
||||
- name: seed
|
||||
image: ghcr.io/alkatrazz24/funk-finlab:sha-54f6f7c
|
||||
command: ["/usr/local/bin/entrypoint-seed.sh"]
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
volumeMounts:
|
||||
- name: home
|
||||
mountPath: /home/finlab
|
||||
containers:
|
||||
# ── CONSOLE : Claude Code dans un terminal web (ttyd), sous /console ──
|
||||
- name: console
|
||||
image: ghcr.io/alkatrazz24/funk-finlab:sha-54f6f7c
|
||||
command: ["/usr/local/bin/entrypoint-console.sh"]
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
ports:
|
||||
- name: console
|
||||
containerPort: 7681
|
||||
readinessProbe:
|
||||
tcpSocket: { port: 7681 }
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 15
|
||||
livenessProbe:
|
||||
tcpSocket: { port: 7681 }
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 30
|
||||
resources:
|
||||
requests: { cpu: 150m, memory: 512Mi }
|
||||
limits: { cpu: "1", memory: 1536Mi }
|
||||
volumeMounts:
|
||||
- name: home
|
||||
mountPath: /home/finlab
|
||||
# ── DASHBOARD : interface web (FastAPI), graphiques + données finlab ──
|
||||
- name: dashboard
|
||||
image: ghcr.io/alkatrazz24/funk-finlab:sha-54f6f7c
|
||||
command:
|
||||
- /opt/venv/bin/uvicorn
|
||||
- dashboard.server:app
|
||||
- --host=0.0.0.0
|
||||
- --port=8800
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
ports:
|
||||
- name: web
|
||||
containerPort: 7681
|
||||
env:
|
||||
- name: TZ
|
||||
value: "Europe/Paris"
|
||||
# ttyd écoute en TCP : sonde TCP (pas de endpoint HTTP de santé dédié). Démarrage
|
||||
# rapide, mais on laisse de la marge (seed du workspace au 1er boot).
|
||||
containerPort: 8800
|
||||
# FINLAB_HOME/PYTHONPATH viennent de l'image ; FINLAB_HOME = workspace (configs live).
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: 7681
|
||||
initialDelaySeconds: 10
|
||||
httpGet: { path: /healthz, port: 8800 }
|
||||
initialDelaySeconds: 8
|
||||
periodSeconds: 15
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: 7681
|
||||
initialDelaySeconds: 30
|
||||
httpGet: { path: /healthz, port: 8800 }
|
||||
initialDelaySeconds: 20
|
||||
periodSeconds: 30
|
||||
# Node + Claude Code peuvent consommer ; nœuds 8 Go (OOM actif) → limite raisonnable.
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: 1536Mi
|
||||
requests: { cpu: 100m, memory: 256Mi }
|
||||
limits: { cpu: 500m, memory: 768Mi }
|
||||
volumeMounts:
|
||||
- name: home
|
||||
mountPath: /home/finlab
|
||||
|
|
|
|||
|
|
@ -7,11 +7,21 @@ spec:
|
|||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`finance.lab.local`)
|
||||
# /console → console Claude Code (ttyd sert sous ce préfixe via -b /console).
|
||||
- match: Host(`finance.lab.local`) && PathPrefix(`/console`)
|
||||
kind: Rule
|
||||
priority: 20
|
||||
middlewares:
|
||||
# basicAuth : un shell web ne doit pas être ouvert sans auth (cf. middleware.yaml).
|
||||
- name: finlab-auth
|
||||
services:
|
||||
- name: finlab
|
||||
port: 7681
|
||||
# Tout le reste → dashboard web (graphiques, portefeuille, watchlists, actions).
|
||||
- match: Host(`finance.lab.local`)
|
||||
kind: Rule
|
||||
priority: 10
|
||||
middlewares:
|
||||
- name: finlab-auth
|
||||
services:
|
||||
- name: finlab
|
||||
port: 8800
|
||||
|
|
|
|||
|
|
@ -8,5 +8,8 @@ spec:
|
|||
app: finlab
|
||||
ports:
|
||||
- name: web
|
||||
port: 8800
|
||||
targetPort: 8800
|
||||
- name: console
|
||||
port: 7681
|
||||
targetPort: 7681
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue