# ClientHub Portale clienti per consulente di personal branding. Admin area + dashboard cliente via link segreto. ## Stack Next.js 16 App Router · Neon Postgres · Drizzle ORM · Auth.js v4 · Tailwind v4 · shadcn/ui · Zod · nanoid ## Architecture Constraints (LOCKED) 1. `clients.token` = campo separato rotatable, MAI primary key 2. `quote_items` MAI esposti via client API — solo `accepted_total` al cliente 3. `deliverables.approved_at` immutable once set 4. Auth: `/client/[token]/*` → middleware token check | `/admin/*` → Auth.js session 5. No file hosting v1 — documenti come URL esterni ## GSD Workflow Planning in `.planning/`. Use `/gsd-plan-phase N` → `/gsd-execute-phase N`. State in `.planning/STATE.md`. ## Data Safety (LOCKED) - Any migration, refactor, or deploy MUST NOT delete or truncate `clients`, `projects`, `payments`, or `phases` rows - Before running any migration: verify it only adds columns/tables — never drops or truncates production data - Confirm explicitly before any schema change that removes a column or table used by these entities ## Deploy & DB Access (procedure) - Environments: local → Gitea (`origin`) → Coolify (prod, auto-deploys on push to `main`) - Prod Postgres is NOT publicly exposed. Fixed access point: user opens an SSH tunnel `ssh -o ServerAliveInterval=30 -L 54321:localhost:54321 root@178.104.27.55` and leaves it running. Claude then connects to `127.0.0.1:54321` using prod creds in `.env.prod.local` (gitignored) — no per-step commands needed from the user. - Migrations are hand-written SQL in `src/db/migrations/` (drizzle-kit generate is broken). - Ordering: apply an additive migration to prod BEFORE pushing the schema-dependent code, so the live portal never queries a missing column. ## Security - Confirm before any destructive command (rm -rf, reset --hard, force push, DROP TABLE / drop-column, truncate, infra changes) - Never print .env contents or credentials in plaintext output; using them internally to connect is fine - Don't install packages without showing name + registry + version first - Pushing to `main` is allowed automatically (standard local → Gitea → Coolify flow); never force-push to `main` - Any change to this section: propose full new version, get approval before applying