Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ ADMIN_PASSWORD=your-secure-password
ANTHROPIC_API_KEY=sk-ant-...
# OPENAI_API_KEY=sk-...

# Auth (required for login/session; NextAuth)
# Auth (required for login/session; NextAuth / Auth.js)
AUTH_SECRET=generate-with-openssl-rand-base64-32
# Dev only: set this to log in as ANY email with this password (skips DB). Use when DB login fails.
# AUTH_DEV_PASSWORD=changeme
# Production: must match your public URL (stops redirect loops)
# Production: origin only (https://evenslouis.ca). Do NOT append /pro — Auth.js mis-parses
# /api/auth/* actions (UnknownAction) if AUTH_URL/NEXTAUTH_URL includes a path.
NEXTAUTH_URL=https://evenslouis.ca
# Required for Compose `pro` service (NEXT_PUBLIC_BASE_PATH=/pro on :3204)
AUTH_TRUST_HOST=true
# NEXT_PUBLIC_BASE_PATH is set by docker-compose for the `pro` service only — do not set on root app.

# OAuth (prod): add for real Google sign-in. Get from https://console.cloud.google.com/apis/credentials
# GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
Expand All @@ -39,7 +43,7 @@ NEXTAUTH_URL=https://evenslouis.ca
PIPELINE_DRY_RUN=0
# E2E / smoke tests: use 1 to run pipeline without LLM (placeholder artifacts)
# PIPELINE_DRY_RUN=1
# Prod e2e (learning ingest, etc.): set so Playwright can log in at PLAYWRIGHT_BASE_URL=https://evenslouis.ca
# Prod e2e (operator OS): PLAYWRIGHT_BASE_URL=https://evenslouis.ca/pro
# E2E_EMAIL=your-prod-login@example.com
# E2E_PASSWORD=your-prod-password
# On the production server, also set these so e2e login works without relying on DB password:
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)

### Added
- Path-aware `/pro` production build: environment-driven Next.js base path, prefixed browser API/navigation helpers, and an isolated Docker Compose service on `127.0.0.1:3204` while preserving the root `:3200` app.
- Operator/docs cutover for canonical home `https://evenslouis.ca/pro`: smoke-test covers public + `/pro`, deploy checklists and README/ROADMAP point operator paths at `/pro`, Auth.js origin-only `NEXTAUTH_URL` + `AUTH_TRUST_HOST` documented.

## [2026-08-07] — /pro on main

### Added
- Merged isolated `/pro` basePath deployment onto `main` (PR #10 / ADR 007).
- Session notes: `docs/sessions/2026-08-06-pro-domain-migration.md`, `docs/sessions/2026-08-07-pro-cutover-main.md`.

### Fixed
- Conversion page crash "Cannot read properties of undefined (reading 'winRate')" — API now returns page-expected shape (counts.total/won/lost, rates.winRate, medianMs); fetchConversionInput adds won/lost from Lead.dealOutcome; route maps to counts/rates/medianMs; page useEffect uses defensive guards
Expand Down
2 changes: 2 additions & 0 deletions PROJECT_CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ ACCEPT → PROPOSE → BUILD. Nothing ships unless explicitly allowed.

**Baseline:** main = deployable truth (auth, schema, API hardening, health, retry, dry-run, error classifier, E2E scaffold).

**Canonical operator home (2026-08):** `https://evenslouis.ca/pro/dashboard` via isolated Compose `pro` service (`NEXT_PUBLIC_BASE_PATH=/pro` on `:3204`). Public site stays at `https://evenslouis.ca` (`:3200`). See ADR 007. Do not start Architecture Phase 2–4 until `/pro` cut + smoke are closed.

---

## 1. What ships now (client-engine-1 — “Money Path Machine”)
Expand Down
21 changes: 13 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ bash deploy.sh
1. **Env (VPS or `.env`):** Must include:
- `DATABASE_URL`
- `AUTH_SECRET`
- `NEXTAUTH_URL` (e.g. `https://evenslouis.ca`)
- `OPENAI_API_KEY`
- `NEXTAUTH_URL` (origin only, e.g. `https://evenslouis.ca` — **do not** append `/pro`)
- `AUTH_TRUST_HOST=true` (required for the `/pro` Compose service)
- `ANTHROPIC_API_KEY` and/or `OPENAI_API_KEY`
2. **Database:** `deploy.sh` runs `prisma db push`. If you deploy without it, run `npx prisma db push` on the server once.
3. **Health:** After deploy, confirm `GET /api/health` returns **200** with `ok: true` and all checks true (db, pipelineTables, authSecret, nextAuthUrl).
3. **Health:** After deploy, confirm root `GET /api/health` and operator `GET /pro/api/health` both return **200** with `ok: true`.
4. **Architecture:** Root app `:3200` (public) + isolated `pro` service `:3204` with `NEXT_PUBLIC_BASE_PATH=/pro`. See [ADR 007](docs/decisions/007-pro-base-path-deployment.md).

## Operations

Expand All @@ -50,15 +52,18 @@ bash logs.sh postgres # Tail DB logs

**One-command deploy from your machine:** Use `./scripts/sync-and-deploy.sh` to keep dev and prod in sync (push, rsync, deploy). If the server has an SSH deploy key, you can use `./scripts/deploy-remote.sh` instead. See [docs/DEPLOY_SSH_SETUP.md](docs/DEPLOY_SSH_SETUP.md).

**Post-deploy smoke test:** `./scripts/smoke-test.sh` (or `./scripts/smoke-test.sh https://evenslouis.ca`) — checks homepage, login, dashboard, `/api/health`, `/api/ops/command`, SSL. Exit 0 = all pass.
**Post-deploy smoke test:** `./scripts/smoke-test.sh` — checks public site + `/pro` operator health/login/dashboard. Exit 0 = all pass.

**VPS out of disk (ENOSPC / rsync or deploy fails):** Run `./scripts/run-vps-cleanup.sh` from your Mac to prune Docker and free space on the server, then run `./scripts/sync-and-deploy.sh` again. See [docs/VPS_DEPLOY_CHECKLIST.md](docs/VPS_DEPLOY_CHECKLIST.md) § Disk space maintenance.

## URLs

- **https://evenslouis.ca** — Public site
- **https://evenslouis.ca/dashboard** — Private dashboard (login required)
- **https://evenslouis.pro** — Redirects to dashboard
- **https://evenslouis.ca** — Public site (root app `:3200`)
- **https://evenslouis.ca/pro/dashboard** — Operator OS (isolated `pro` app `:3204`, `basePath=/pro`)
- **https://evenslouis.ca/pro/login** — Operator login
- **https://evenslouis.pro** — Legacy host; redirect to `/pro` only after operator smoke is green (see ADR 007)

Public marketing/proof/campaign/portal pages stay on the root host unless product intent moves them.

## Local development

Expand Down Expand Up @@ -99,7 +104,7 @@ To run without an OpenAI key (pipeline uses placeholder artifacts):
PIPELINE_DRY_RUN=1 npm run test:e2e
```

**Production:** Use `PLAYWRIGHT_BASE_URL=https://evenslouis.ca` only after fixing redirect loops (set `NEXTAUTH_URL` and `AUTH_SECRET` on the server).
**Production operator E2E:** `PLAYWRIGHT_BASE_URL=https://evenslouis.ca/pro` (set `NEXTAUTH_URL` to the origin without `/pro`, plus `AUTH_SECRET` / `AUTH_TRUST_HOST`).

**Testing strategy:** [docs/TESTING_SIDE_PANEL.md](docs/TESTING_SIDE_PANEL.md) — two-tier approach (Playwright automated + manual production checks), page-by-page test matrix, and embedded browser notes.

Expand Down
15 changes: 12 additions & 3 deletions ROADMAP.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
# Roadmap — Client Engine

## Current State (March 2026)
## Current State (August 2026)

Phase 9+ complete. Full business OS operational with AI Brain, 10 agents, memory pipeline, NBA system, risk engine, scoring, notifications, growth engine, signal engine, builder integration, Outcome Ledger + Scorecard (Sprint 9), and 92 dashboard pages.

**Canonical operator home:** `https://evenslouis.ca/pro/dashboard` (isolated Compose `pro` service on `:3204`, ADR 007). Public site remains `https://evenslouis.ca` (`:3200`).

## Active Work

### Performance Refactor (Phase 1 — Done, pending production deploy)
### `/pro` cutover (current)
- [x] Isolated `/pro` basePath deploy on main (PR #10 / ADR 007)
- [x] VPS: `pro` healthy on `127.0.0.1:3204`; Caddy `/pro*`; login → `/pro/dashboard`; `/pro/api/health`
- [ ] Finish Sprint 1–9 checklist smoke at `/pro/...` URLs ([DEPLOY_CHECKLIST_SPRINTS_1_9.md](docs/DEPLOY_CHECKLIST_SPRINTS_1_9.md) §5)
- [ ] Redirect `evenslouis.pro` → `https://evenslouis.ca/pro` after smoke
- [ ] Keep docs/smoke/E2E pointed at `/pro` for operator paths

### Performance Refactor (Phase 1 — Done)
- [x] Add 6 composite database indexes
- [x] Fix unbounded queries in metrics
- [x] Parallelize sequential queries (3 files)
Expand All @@ -15,7 +24,7 @@ Phase 9+ complete. Full business OS operational with AI Brain, 10 agents, memory
- [x] Add cache to fetchBottlenecks
- [x] Fix LIKE pattern full scan
- [x] Playwright review: all pages pass, zero console errors
- [ ] Apply indexes to production (`prisma db push` on VPS)
- [x] Apply indexes to production (`db4c0de`)

### Documentation System — Done
- [x] CLAUDE.md, ARCHITECTURE.md, CONTRIBUTING.md, CHANGELOG.md, ROADMAP.md
Expand Down
37 changes: 22 additions & 15 deletions docs/AFTER_DEPLOY_SMOKE_CHECKLIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,25 @@
Run immediately after every production deploy. Do not skip.
**Goal:** confirm nothing broke. If anything fails, rollback first, investigate second.

**Canonical operator home:** `https://evenslouis.ca/pro/dashboard`
**Public site:** `https://evenslouis.ca`

---

## Automated (30 seconds)

Run these from your terminal. Both must pass before you do manual checks.

```bash
# 1. Curl-based smoke test (homepage, login, dashboard, health, ops/command, SSL)
./scripts/smoke-test.sh https://evenslouis.ca
# 1. Curl-based smoke test (public + /pro login/dashboard/health)
./scripts/smoke-test.sh https://evenslouis.ca https://evenslouis.ca/pro

# 2. Health only (quick sanity)
curl -s https://evenslouis.ca/api/health
curl -s https://evenslouis.ca/pro/api/health
```

**Expected:** smoke-test.sh exits 0. Health returns `{ "ok": true }` with all checks green.
**Expected:** smoke-test.sh exits 0. Both health endpoints return `{ "ok": true }` with checks green.

**If health fails → rollback immediately:**
```bash
Expand All @@ -28,16 +32,16 @@ ssh $DEPLOY_SERVER 'cd /root/client-engine && git reset --hard HEAD~1 && bash de

## Manual checks (3–5 min)

Open production in MCP browser or a real browser.
Open production in a real browser (operator paths under `/pro`).

| # | Check | How | Pass | Fail → do this |
|---|-------|-----|------|-----------------|
| 1 | **Login** | `https://evenslouis.ca/login` → log in | Dashboard loads, no redirect loop | Rollback. Check `NEXTAUTH_URL`, `AUTH_SECRET`, run `npm run reset-auth` on VPS |
| 2 | **Command Center** | Open `/dashboard/command` | Scorecard renders, Failures card renders, data is not stale | Rollback. Check server logs for query errors |
| 3 | **Lead detail** | Open any lead at `/dashboard/leads/[id]` | Artifacts load, pipeline actions visible | Rollback. Check DB connectivity |
| 4 | **Proposals** | Open `/dashboard/proposals` | List loads, at least one proposal visible (if any exist) | Rollback |
| 5 | **Metrics** | Open `/dashboard/metrics` | Page loads, recent runs visible | Rollback |
| 6 | **API auth gate** | `curl -s https://evenslouis.ca/api/leads` | Returns 401 (no cookie = auth working) | **Critical:** Auth is broken. Rollback immediately |
| 1 | **Login** | `https://evenslouis.ca/pro/login` → log in | `/pro/dashboard` loads, no redirect loop | Rollback. Check `NEXTAUTH_URL` is origin-only (no `/pro`), `AUTH_TRUST_HOST=true`, `AUTH_SECRET`, run `npm run reset-auth` on VPS |
| 2 | **Command Center** | Open `/pro/dashboard/command` (or founder home) | Scorecard/Failures render, data is not stale | Rollback. Check server logs for query errors |
| 3 | **Lead detail** | Open any lead at `/pro/dashboard/leads/[id]` | Artifacts load, pipeline actions visible | Rollback. Check DB connectivity |
| 4 | **Proposals** | Open `/pro/dashboard/proposals` | List loads | Rollback |
| 5 | **Metrics** | Open `/pro/dashboard/metrics` | Page loads | Rollback |
| 6 | **API auth gate** | `curl -s https://evenslouis.ca/pro/api/leads` | Returns 401 (no cookie = auth working) | **Critical:** Auth is broken. Rollback immediately |
| 7 | **SSL** | smoke-test.sh checks this, or manually check cert | Certificate valid, not expired | Renew cert (certbot or hosting panel) |

---
Expand All @@ -51,21 +55,24 @@ If any check fails after deploy:
ssh $DEPLOY_SERVER '/root/rollback-client-engine.sh'

# Option B: manual
ssh $DEPLOY_SERVER 'cd /root/client-engine && git log --oneline -5 && git reset --hard HEAD~1 && bash deploy.sh && curl -fsS https://evenslouis.ca/api/health'
ssh $DEPLOY_SERVER 'cd /root/client-engine && git log --oneline -5 && git reset --hard HEAD~1 && bash deploy.sh && curl -fsS https://evenslouis.ca/pro/api/health'
```

See [DEPLOY_SSH_SETUP.md](DEPLOY_SSH_SETUP.md) for full rollback details.

---

## Optional: run Playwright against prod
## Optional: run Playwright against prod operator OS

```bash
USE_EXISTING_SERVER=1 PLAYWRIGHT_BASE_URL=https://evenslouis.ca npm run test:e2e
USE_EXISTING_SERVER=1 PLAYWRIGHT_BASE_URL=https://evenslouis.ca/pro npm run test:e2e
```

21 tests run without login. Set `E2E_EMAIL`/`E2E_PASSWORD` for all tests.
Set `E2E_EMAIL`/`E2E_PASSWORD` for authenticated tests. Keep `NEXTAUTH_URL` as origin-only.

---

*See also: [VPS_DEPLOY_CHECKLIST.md](VPS_DEPLOY_CHECKLIST.md) (full deploy process), [TESTING_SIDE_PANEL.md](TESTING_SIDE_PANEL.md) (testing strategy).*
## Related

- Full Sprint 1–9 path smoke: [DEPLOY_CHECKLIST_SPRINTS_1_9.md](DEPLOY_CHECKLIST_SPRINTS_1_9.md) §5 (use `/pro/...` URLs)
- Architecture: [decisions/007-pro-base-path-deployment.md](decisions/007-pro-base-path-deployment.md)
4 changes: 2 additions & 2 deletions docs/BEFORE_CLIENTS_CHECKLIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ Run before any client call, demo, screenshare, or proposal send.

| # | Check | How | Pass | Fail → do this |
|---|-------|-----|------|-----------------|
| 1 | **Health** | `curl -s https://evenslouis.ca/api/health` | 200, `ok: true`, all checks green | Do not demo. Fix health first (see [VPS_DEPLOY_CHECKLIST.md](VPS_DEPLOY_CHECKLIST.md)) |
| 2 | **Command Center** | Open `/dashboard/command` | Scorecard, Failures, Constraint all render with current data | If cards are blank → check last workday run, restart app |
| 1 | **Health** | `curl -s https://evenslouis.ca/pro/api/health` (and root `/api/health`) | 200, `ok: true`, all checks green | Do not demo. Fix health first (see [VPS_DEPLOY_CHECKLIST.md](VPS_DEPLOY_CHECKLIST.md)) |
| 2 | **Command Center** | Open `/pro/dashboard/command` (or founder home) | Scorecard, Failures, Constraint all render with current data | If cards are blank → check last workday run, restart app |
| 3 | **Target lead** | Open the lead(s) you'll reference | Artifacts present, proposal content correct, no stale data | If missing → run pipeline or check for errors |
| 4 | **Proposal console** | Open the relevant proposal at `/dashboard/proposals/[id]` | Sections render, snippet correct, ready/sent toggles work | If stale → revise proposal before the call |
| 5 | **No visible errors** | Open browser DevTools Console on pages you'll show | No red errors | Fix or note before screensharing |
Expand Down
4 changes: 3 additions & 1 deletion docs/DEPLOY_CHECKLIST_SPRINTS_1_9.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,10 @@ Deploy scripts run `prisma migrate deploy` automatically. If deploying manually:

## 5. Smoke Test Production (do these manually)

**Use operator URLs under `https://evenslouis.ca/pro/...`** (isolated `pro` service). Public proof/campaign/portal pages remain on the root host unless product intent moves them.

### Critical path — must all work
- [ ] **Login** — dashboard loads, no blank screens
- [ ] **Login** — `https://evenslouis.ca/pro/login` → `/pro/dashboard` loads, no blank screens
- [ ] **Sidebar** — shows all 6 groups: Capture, Convert, Build, Prove, Optimize, System
- [ ] **Create a lead** — fill form, submit, verify it appears in pipeline
- [ ] **Pipeline view** — leads visible with correct status badges
Expand Down
13 changes: 8 additions & 5 deletions docs/VPS_DEPLOY_CHECKLIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
|----------|----------|--------|
| `DATABASE_URL` | Yes | PostgreSQL connection string |
| `AUTH_SECRET` | Yes | NextAuth secret; generate with `openssl rand -base64 32` |
| `NEXTAUTH_URL` | Yes | Full app URL e.g. `https://evenslouis.ca` |
| `NEXTAUTH_URL` | Yes | Origin only e.g. `https://evenslouis.ca` (**no** `/pro` path) |
| `AUTH_TRUST_HOST` | Yes (for `/pro`) | `true` — required by Compose `pro` service |
| `ADMIN_EMAIL` | For login | Used by seed/reset-auth to create the single admin user (default `admin@evenslouis.ca`) |
| `ADMIN_PASSWORD` | For login | Used by seed/reset-auth; use the same value when you run reset-auth and when you log in (default `changeme`) |
| `OPENAI_API_KEY` | For pipeline | Omit or use dry-run for no LLM calls |
Expand Down Expand Up @@ -107,23 +108,25 @@ Run immediately after every production deploy. Do not skip.
### Automated (fast, 30 seconds)

```bash
# Curl-based smoke test
./scripts/smoke-test.sh https://evenslouis.ca
# Curl-based smoke test (public site + /pro operator)
./scripts/smoke-test.sh https://evenslouis.ca https://evenslouis.ca/pro

# Health only
curl -s https://evenslouis.ca/api/health
curl -s https://evenslouis.ca/pro/api/health
```

Both must pass. If health check fails, **rollback immediately** (see below).

### Manual production checks (MCP browser or real browser, 3-5 min)

- [ ] **Login:** Open `https://evenslouis.ca/login`, log in → dashboard loads
- [ ] **Operator login:** Open `https://evenslouis.ca/pro/login`, log in → `/pro/dashboard` loads
- [ ] **Pro health:** `curl -s https://evenslouis.ca/pro/api/health` → 200
- [ ] **Command Center:** Scorecard renders, Failures card renders, data is current
- [ ] **One lead detail:** Open any lead → artifacts load, pipeline actions visible
- [ ] **Proposals:** List loads, at least one proposal visible (if any exist)
- [ ] **Metrics:** Page loads, recent runs visible
- [ ] **API auth gate:** `curl -s https://evenslouis.ca/api/leads` → 401 (confirms auth is working)
- [ ] **API auth gate:** `curl -s https://evenslouis.ca/pro/api/leads` → 401 (confirms auth is working)
- [ ] **SSL:** Certificate valid (smoke-test.sh checks this for HTTPS)

If any check fails after deploy, rollback first, investigate second. See `docs/DEPLOY_SSH_SETUP.md` for rollback commands.
Expand Down
33 changes: 33 additions & 0 deletions docs/sessions/2026-08-07-pro-cutover-main.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Session: /pro cutover onto main

## Goal

Land the isolated `/pro` operator OS on `main`, verify live VPS wiring, and sweep docs/smoke so the next deploy does not regress to root `/dashboard` URLs.

## Decisions

- Merge PR #10 (`cursor/domain-path-consolidation-59dd` @ `46558a3`) onto `main` — do not reinvent architecture.
- Keep ADR 007: second image `NEXT_PUBLIC_BASE_PATH=/pro` on `127.0.0.1:3204`; root `:3200` unchanged; shared Postgres/Redis; Caddy `/pro*` without stripping.
- Auth.js: `NEXTAUTH_URL` origin-only + `AUTH_TRUST_HOST=true` (never put `/pro` in AUTH_URL).
- Do **not** redirect `evenslouis.pro` until Sprint 1–9 §5 smoke at `/pro` is finished.
- Do **not** start Architecture Phase 2–4.

## What was done

- Merged `/pro` onto `main` (`c81ac32` Merge PR #10).
- VPS checkout synced to `main`; Compose `pro` service present; containers healthy.
- Auth smoke inside `pro` container: CSRF → credentials callback → session → `/pro/dashboard` **200**.
- Public: `https://evenslouis.ca/pro/api/health` **200**.
- Doc/config sweep branch `cursor/pro-cutover-docs-59dd`: README, ROADMAP, PROJECT_CONTEXT, CHANGELOG, VPS/AFTER/BEFORE/DEPLOY checklists, `.env.example`, `scripts/smoke-test.sh` (public + `/pro`), `tests/e2e/prod.spec.ts` comment.

## Insights

- Live `/pro` was already healthy while `main` lacked the code — **merge drift** was the real risk; merging closed it.
- A checkout on an unrelated feature branch without Compose `pro` does not stop the existing `pro` container, but the next `docker compose up` from that tree would drift — keep VPS on `main` (or a branch that includes `pro`).

## Next steps

- Finish manual Sprint 1–9 §5 smoke at `/pro/...` URLs.
- Only then redirect `evenslouis.pro` → `https://evenslouis.ca/pro`.
- Merge remaining product PRs as needed (e.g. AI Brain Sonnet 5 / YouTube PR #13) without blocking `/pro` cut.
- Human decides when Architecture Phase 2 starts.
Loading
Loading