# Phase 0 — Discovery: environment and existing infrastructure (2026-11-02) ## Summary tools.spboucher.ai is deployed exactly like the other spboucher.ai applications: a Next.js + PostgreSQL app placed on a MacLustr node by the `mld` orchestrator, exposed through the MacLustr Tunnel (WireGuard → Caddy on the OVH gateway BHS64) with DNS at GoDaddy. No new tunnel, proxy or DNS mechanism was introduced. ## What was inspected (commands run from the operator laptop) | Area | Command / source | Finding | |---|---|---| | Orchestrator | `mld nodes`, `mld status`, `M1M32:~/dispatch/apps/*.json` | 38 apps registered; manifests describe dir, PM2 processes, hooks, placement, `tunnel.domain`. Convention: `~/apps/`, Homebrew Node + pnpm + PM2, PostgreSQL 17 local to the node, `.env` (mode 600) excluded from rsync. | | Tunnel | `mld tunnel status` | Single gateway BHS64 (51.161.112.61, OVH Beauharnois); 17 WireGuard peers; Caddy with 38 routes `host → 10.67.0.x:port`, automatic Let's Encrypt. Routes are created by `mld deploy` from the manifest. | | DNS | `dig tools.spboucher.ai`, `dig .spboucher.ai` | `tools.spboucher.ai` already has an explicit A record → 51.161.112.61 (not a wildcard). No Caddy route existed; HTTPS failed at the TLS handshake (no content to preserve). Nameservers: GoDaddy (domaincontrol.com). | | Registrar access | memory notes, `cluster-skill` docs | DNS changes are made in the GoDaddy web console; there is no API-token integration in the cluster tooling. Not needed here because the record exists. | | Secrets | existing manifests, `~/Desktop/Cluster/secrets/` | Pattern: secrets live in `/.env` on the node (600) plus an offline copy under `~/Desktop/Cluster/secrets//`; never in git. Some older manifests inline secrets in PM2 env — this project does **not** (hook requires `.env`). | | Identity | note/chat/akos apps | Owner-only auth with argon2id passwords, TOTP and WebAuthn passkeys (simplewebauthn) — reused here. There is no shared SSO/IdP in the cluster. | | Node candidates | `mld nodes` + SSH probes | **M2M32c** (Mac Studio, 12 cores, 32 GB, 417 GB free SSD): PostgreSQL 17.11 + pgvector 0.8.6 (Homebrew, localhost), Redis, Node 26, pnpm 12, PM2 7, wg1 peer 10.67.0.20, **zero PM2 processes** → chosen to avoid interfering with production nodes. Alternatives considered: M4M64c (hosts akos/chat/note), M3U96a (10 processes), M5M36 (no Postgres). | | Remote-first rule | `MACLUSTR-PROCEDURE.md` | After first deploy, the node directory is a git clone (`mld adopt`), `origin` = spbgit (`gitsrv`). Edits happen on the node; laptop copy is a mirror. | | Laptop toolchain | `node -v`, `pnpm -v`, `psql --version` | Node 25.9, pnpm 11.1, PostgreSQL 17.9 + pgvector 0.8.2 (dev DB), Playwright Chromium, pandoc/weasyprint. | ## Conventions adopted - Port **8540** (unused across the Caddy route table and on M2M32c). - Dir `~/apps/tools-spboucher-ai`, PM2 processes `tools-web` (Next) and `tools-worker` (tsx). - Database `tools_spboucher` on the node's local PostgreSQL; roles `tools_app` (read/write) and `tools_reader` (SELECT on public views only, `default_transaction_read_only`). - Backups: encrypted `pg_dump` nightly to `~/backups/tools-spboucher-ai` with rsync to a second node (M3U96b), retention 14. - Health endpoint `/api/health` used by `mld`. ## Risk register | Risk | Likelihood | Impact | Mitigation | |---|---|---|---| | Link checker flagged as a bot (403/429) on vendor sites | High | Low | 401/403/405/429 counted as *unverifiable*, not broken; weekly sweep; admin dashboard surfaces them. | | Vendor renames/acquisitions make records stale | Medium | Medium | Source rescan job hashes official pages and flags changes; freshness policy per field. | | Single residential uplink / node outage | Medium | Medium | `mld heal` restarts PM2 + routes; `mld move` relocates the app; backups off-node. | | Secrets leakage via manifests | Low | High | Secrets only in node `.env`; manifest hook refuses to deploy without it; public role cannot read private tables. | | Prompt injection through fetched pages (AI suggestions) | Medium | Medium | Fetched text wrapped as untrusted data; model output must be JSON and evidence quotes are verified against the page; nothing is written automatically. | | Search quality regressions | Medium | Low | `pnpm eval:ranking` fixture (MRR threshold) in CI. | | macOS TCC blocking PM2 file access | Low | Medium | App data stays inside the home directory (no external volumes). |