# Ghostfolio — Suivi & analyse de portefeuille

Ghostfolio est l'outil de suivi de patrimoine du lab : actions, ETF, crypto. Il fournit
le suivi de performance (TWR / ROI), les dividendes, l'allocation, l'analyse de risque
(« X-Ray »). Open-source (AGPL-3.0), self-hosté, données dans PostgreSQL sur storage-01.

---

## Accès

| URL | `http://ghostfolio.lab.local` |
|---|---|
| Namespace k8s | `ai` |
| Port interne | `3333` |
| Données de marché | Yahoo Finance (gratuit, sans clé API) par défaut |

---

## Architecture

```
ghostfolio (pod)  →  PostgreSQL  192.168.10.1:5432  (base « ghostfolio », hors cluster)
                  →  ghostfolio-redis:6379           (cache, in-cluster)
```

- **PostgreSQL** : base + utilisateur `ghostfolio` créés par le rôle Ansible `postgresql`
  (mot de passe vault `vault_pg_ghostfolio_password`). Schéma géré par Ghostfolio (migrations
  Prisma au démarrage) — pas de table à créer à la main.
- **Redis** : déployé dans le cluster (`redis:7-alpine`, `k8s/apps/ghostfolio/redis.yaml`),
  mot de passe via le même secret. Pas de persistance (cache uniquement).
- **Pas de PVC** : Ghostfolio est sans état, tout vit dans PostgreSQL + Redis.

---

## Déploiement (ArgoCD)

Manifests dans `k8s/apps/ghostfolio/` :
- `deployment.yaml` — pod Ghostfolio (:3333)
- `redis.yaml` — Deployment + Service Redis (cache)
- `service.yaml` — ClusterIP :3333
- `ingress.yaml` — IngressRoute Traefik

Application ArgoCD : `k8s/apps-of-apps/apps/ghostfolio.yaml`

> Image épinglée sur `:latest` (cohérent avec n8n). Pour figer une version, remplacer
> par `ghostfolio/ghostfolio:<tag>` dans `deployment.yaml`.

---

## Mise en service (ordre des opérations)

### 1. Créer la base PostgreSQL sur storage-01

Ajouter le secret au vault Ansible (depuis la racine du repo — la cible fait le `cd` seule) :

```bash
make vault-edit   # ajouter : vault_pg_ghostfolio_password: "<mot de passe fort>"
```

La base et l'utilisateur `ghostfolio` sont déjà déclarés dans
`ansible/roles/postgresql/defaults/main.yml`. Appliquer :

```bash
ansible-playbook -i inventory.yml playbooks/storage-01.yml --tags postgresql
```

### 2. Créer le secret k8s (non commité)

```bash
kubectl create secret generic ghostfolio-secret -n ai \
  --from-literal=database-url="postgresql://ghostfolio:PG_PASSWORD@192.168.10.1:5432/ghostfolio?connect_timeout=300&sslmode=disable" \
  --from-literal=redis-password="$(openssl rand -hex 16)" \
  --from-literal=access-token-salt="$(openssl rand -hex 32)" \
  --from-literal=jwt-secret-key="$(openssl rand -hex 32)"
```

- `PG_PASSWORD` = la valeur mise dans `vault_pg_ghostfolio_password` à l'étape 1.
- `sslmode=disable` est **obligatoire** : PostgreSQL sur s01 n'a pas SSL activé, et l'adapter
  `pg` de Prisma 7.x (étape de seed Ghostfolio) échoue en `TlsConnectionError` avec `prefer`.
  Le LAN cluster est interne/de confiance, donc pas de TLS requis ici.
- `redis-password` peut être n'importe quelle valeur aléatoire (Redis est interne au cluster).
- `access-token-salt` / `jwt-secret-key` doivent rester stables : les régénérer invaliderait
  les sessions et les comptes existants.

### 3. Pousser sur Git → ArgoCD synchronise

```bash
git add k8s/apps/ghostfolio/ k8s/apps-of-apps/apps/ghostfolio.yaml \
        ansible/roles/postgresql/defaults/main.yml admin/k8s/ghostfolio.md
git commit -m "feat(ghostfolio): suivi de portefeuille sur k8s (PG s01 + Redis)"
git push
```

ArgoCD crée l'app (~3 min). Au premier démarrage Ghostfolio applique ses migrations Prisma.

### 4. Créer le compte admin

À la première connexion sur `http://ghostfolio.lab.local`, le premier utilisateur créé
devient administrateur. Saisie des positions ensuite via l'UI ou import CSV.

---

## Dépannage

```bash
# Logs du pod
kubectl logs -n ai deploy/ghostfolio --tail=50

# Vérifier l'accès PostgreSQL depuis le pod
kubectl exec -n ai deploy/ghostfolio -- env | grep -i database  # (masqué : secret)

# Santé applicative
kubectl exec -n ai deploy/ghostfolio -- wget -qO- http://localhost:3333/api/v1/health

# Redis joignable ?
kubectl get pods -n ai -l app=ghostfolio-redis
```

- **CrashLoop au 1er démarrage** : souvent la base inaccessible (mot de passe `database-url`
  ≠ `vault_pg_ghostfolio_password`, ou rôle `postgresql` pas réappliqué). Vérifier nftables
  (port 5432 ouvert pour `192.168.10.0/24`, déjà le cas) et `pg_hba.conf` (host scram-sha-256
  pour le LAN cluster, déjà le cas).
- **`Error: permission denied for schema public`** (migrations Prisma) : la base `ghostfolio`
  est possédée par `postgres` (le rôle `postgresql_db` ne fixe pas `owner:`), donc l'utilisateur
  `ghostfolio` n'a pas de droit implicite sur le schéma `public`. Les bases historiques
  (n8n/openwebui/litellm) sont possédées par leur user et n'ont jamais eu ce souci. Correctif
  (idempotent, identique à la task Ansible « Grant schema public ») :
  ```bash
  ssh storage-01 "sudo -u postgres psql -d ghostfolio -c 'GRANT ALL ON SCHEMA public TO ghostfolio;'"
  ```
  Vérifier : `\dn+ public` doit montrer `ghostfolio=UC`.
- **`Error opening a TLS connection: The server does not support SSL`** (seed Prisma 7.x) :
  PostgreSQL sur s01 n'a pas SSL → `database-url` doit finir par `sslmode=disable`, pas `prefer`.
- **Quotes/prix vides** : Yahoo Finance peut throttler ; les prix se mettent à jour via le
  scheduler interne. Optionnellement ajouter une clé d'un autre data provider plus tard.
