{
  "app": "findata",
  "label": "FinData OS — private financial data lakehouse (findata.spboucher.ai)",
  "domain": "findata.spboucher.ai",
  "port": 8600,
  "health_path": "/api/v1/health",
  "dir": "~/apps/findata",
  "extra_paths": [],
  "sync_excludes": [
    ".git/",
    ".DS_Store",
    ".venv/",
    "apps/web/node_modules/",
    "apps/web/.next/",
    "apps/web/out/",
    "data/",
    "logs/",
    "backups/",
    ".env",
    "__pycache__/",
    ".pytest_cache/",
    ".ruff_cache/",
    "tests/_tmp/"
  ],
  "requires": {
    "runtimes": [
      "uv",
      "node",
      "pnpm",
      "pm2",
      "postgresql@17"
    ],
    "ram_gb": 6,
    "disk_gb": 1500,
    "ports": [
      8600
    ]
  },
  "ram_mb_observed": 900,
  "size_mb": 20,
  "placement": {
    "pin": "M3U96a",
    "prefer": "M3U96a",
    "avoid": [
      "M1M32"
    ],
    "reason": "Storage node chosen in docs/DISCOVERY.md: 1 TB Apple NVMe (508 GB free, SMART verified, 5 GB/s), 32 cores / 96 GB for DuckDB, Postgres 17 + Redis already local, wg1 10.67.0.10. Lake at ~/findata-lake (outside the app dir)."
  },
  "processes": [
    {
      "name": "findata-api",
      "manager": "pm2",
      "script": "{{HOME}}/apps/findata/infra/scripts/run-under-sshd.sh",
      "args": [
        "{{HOME}}/apps/findata",
        "{{HOME}}/apps/findata/.venv/bin/python",
        "-m",
        "uvicorn",
        "findata_api.main:app",
        "--host",
        "0.0.0.0",
        "--port",
        "8600",
        "--workers",
        "1"
      ],
      "interpreter": null,
      "cwd": "{{HOME}}/apps/findata",
      "env": {
        "FINDATA_ROOT": "{{HOME}}/apps/findata",
        "PATH": "/opt/homebrew/opt/postgresql@17/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin"
      },
      "cron_restart": null,
      "autorestart": true,
      "max_memory_restart": "6G",
      "kill_timeout": 30000
    },
    {
      "name": "findata-worker",
      "manager": "pm2",
      "script": "{{HOME}}/apps/findata/infra/scripts/run-under-sshd.sh",
      "args": [
        "{{HOME}}/apps/findata",
        "{{HOME}}/apps/findata/.venv/bin/python",
        "-m",
        "findata_ingest.cli",
        "worker"
      ],
      "interpreter": null,
      "cwd": "{{HOME}}/apps/findata",
      "env": {
        "FINDATA_ROOT": "{{HOME}}/apps/findata",
        "PATH": "/opt/homebrew/opt/postgresql@17/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin"
      },
      "cron_restart": null,
      "autorestart": true,
      "max_memory_restart": "24G",
      "kill_timeout": 3600000
    },
    {
      "name": "findata-bulk-1",
      "manager": "pm2",
      "script": "{{HOME}}/apps/findata/infra/scripts/run-under-sshd.sh",
      "args": [
        "{{HOME}}/apps/findata",
        "{{HOME}}/apps/findata/.venv/bin/python",
        "-m",
        "findata_ingest.cli",
        "worker",
        "--role",
        "bulk"
      ],
      "interpreter": null,
      "cwd": "{{HOME}}/apps/findata",
      "env": {
        "FINDATA_ROOT": "{{HOME}}/apps/findata",
        "PATH": "/opt/homebrew/opt/postgresql@17/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin"
      },
      "cron_restart": null,
      "autorestart": true,
      "max_memory_restart": "12G",
      "kill_timeout": 3600000
    },
    {
      "name": "findata-bulk-2",
      "manager": "pm2",
      "script": "{{HOME}}/apps/findata/infra/scripts/run-under-sshd.sh",
      "args": [
        "{{HOME}}/apps/findata",
        "{{HOME}}/apps/findata/.venv/bin/python",
        "-m",
        "findata_ingest.cli",
        "worker",
        "--role",
        "bulk"
      ],
      "interpreter": null,
      "cwd": "{{HOME}}/apps/findata",
      "env": {
        "FINDATA_ROOT": "{{HOME}}/apps/findata",
        "PATH": "/opt/homebrew/opt/postgresql@17/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin"
      },
      "cron_restart": null,
      "autorestart": true,
      "max_memory_restart": "12G",
      "kill_timeout": 3600000
    },
    {
      "name": "findata-bulk-3",
      "manager": "pm2",
      "script": "{{HOME}}/apps/findata/infra/scripts/run-under-sshd.sh",
      "args": [
        "{{HOME}}/apps/findata",
        "{{HOME}}/apps/findata/.venv/bin/python",
        "-m",
        "findata_ingest.cli",
        "worker",
        "--role",
        "bulk"
      ],
      "interpreter": null,
      "cwd": "{{HOME}}/apps/findata",
      "env": {
        "FINDATA_ROOT": "{{HOME}}/apps/findata",
        "PATH": "/opt/homebrew/opt/postgresql@17/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin"
      },
      "cron_restart": null,
      "autorestart": true,
      "max_memory_restart": "12G",
      "kill_timeout": 3600000
    },
    {
      "name": "findata-bulk-4",
      "manager": "pm2",
      "script": "{{HOME}}/apps/findata/infra/scripts/run-under-sshd.sh",
      "args": [
        "{{HOME}}/apps/findata",
        "{{HOME}}/apps/findata/.venv/bin/python",
        "-m",
        "findata_ingest.cli",
        "worker",
        "--role",
        "bulk"
      ],
      "interpreter": null,
      "cwd": "{{HOME}}/apps/findata",
      "env": {
        "FINDATA_ROOT": "{{HOME}}/apps/findata",
        "PATH": "/opt/homebrew/opt/postgresql@17/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin"
      },
      "cron_restart": null,
      "autorestart": true,
      "max_memory_restart": "12G",
      "kill_timeout": 3600000
    }
  ],
  "ngrok": null,
  "launchd": [],
  "env_overrides": {},
  "hooks": {
    "post_sync": [
      "test -f .env || { echo 'ERREUR: .env absent (secrets) — copier ~/Desktop/Cluster/secrets/findata/.env'; exit 1; }; chmod 600 .env",
      "export PATH=\"/opt/homebrew/bin:$HOME/.local/bin:$PATH\"; uv sync --frozen 2>&1 | tail -1 && echo '  python deps ok'",
      "export PATH=\"/opt/homebrew/bin:$PATH\"; cd apps/web && pnpm install --frozen-lockfile --silent && pnpm build 2>&1 | tail -2 && echo '  web build ok'",
      "export PATH=\"/opt/homebrew/opt/postgresql@17/bin:/opt/homebrew/bin:$PATH\"; set -a; . ./.env; set +a; .venv/bin/python -m findata_ingest.cli migrate && echo '  migrations ok'",
      "mkdir -p ~/findata-lake logs && chmod 700 ~/findata-lake && echo '  lake dir ok'"
    ],
    "post_start": []
  },
  "ka_repo": false,
  "tunnel": {
    "domain": "findata.spboucher.ai",
    "gateway": "BHS64",
    "note": "DNS GoDaddy A findata.spboucher.ai → 51.161.112.61 vérifié le 2026-11-01 avant déploiement ; route Caddy posée par mld deploy ; findata-api écoute 0.0.0.0:8600 avec garde de provenance (loopback, wg1 10.67.0.0/16, LAN) ; Caddy → wg1 10.67.0.10:8600"
  },
  "notes": "Monorepo uv (Python 3.13) : services/api (FastAPI :8600, sert aussi la console Next.js statique apps/web/out), services/ingest (worker unique = verrou d'écriture du lac + ordonnanceur), lac Parquet ~/findata-lake, Postgres 17 local (DB findata, rôle findata). Secrets uniquement dans ~/apps/findata/.env (600) ; copie ~/Desktop/Cluster/secrets/findata/.env. Sauvegarde quotidienne 04:00 ET → M4M64a:~/backups/findata (rsync + pg_dump zstd). CLI : .venv/bin/findata status|discover|ingest … | 2026-11-01 soir : lac froid FINDATA_LAKE_COLD=/Volumes/ssd/findata (SSD externe 4 To, marqueur .findata-cold-root) pour les archives brutes et les datasets non « hot » ; 4 workers bulk (findata-bulk-1..4) pour backfill/options/fundamentals en parallèle ; téléchargement complet FirstRate lancé via `findata ingest backfill-all`. | TCC macOS : PM2/launchd n'ont pas l'Accès complet au disque → tous les processus passent par infra/scripts/run-under-sshd.sh (ré-exécution via sshd localhost, clé id_ed25519_maclustr) pour accéder au SSD externe. Alternative propre : accorder FDA à node + python dans Réglages → Confidentialité (GUI)."
}
