# Workspace

## Overview

**bwg** (headless whmcs) — a production-ready headless CRM dashboard for a digital marketing agency. Built as a pnpm monorepo with a React+Vite frontend, Express 5 API server, PostgreSQL database, and integrations with WHMCS (billing/clients) and Claude AI.

Design: dark charcoal (#1a1a1a) sidebar, bold crimson (#CC2200) primary accent, clean white content areas. Logo: pixel W in red box.

## Stack

- **Monorepo tool**: pnpm workspaces
- **Node.js version**: 24
- **Package manager**: pnpm
- **TypeScript version**: 5.9
- **API framework**: Express 5
- **Database**: PostgreSQL + Drizzle ORM
- **Validation**: Zod (`zod/v4`), `drizzle-zod`
- **API codegen**: Orval (from OpenAPI spec)
- **Build**: esbuild (CJS bundle)
- **Frontend**: React + Vite + shadcn/ui + Tailwind CSS + Wouter routing
- **AI**: Anthropic Claude (`@anthropic-ai/sdk`)
- **Auth**: JWT via `jsonwebtoken` + `bcryptjs`

## Key Commands

- `pnpm run typecheck` — full typecheck across all packages
- `pnpm run build` — typecheck + build all packages
- `pnpm --filter @workspace/api-spec run codegen` — regenerate API hooks and Zod schemas from OpenAPI spec
- `pnpm --filter @workspace/db run push` — push DB schema changes (dev only)
- `pnpm --filter @workspace/api-server run dev` — run API server locally

See the `pnpm-workspace` skill for workspace structure, TypeScript setup, and package details.

## Architecture

### Artifacts
| Artifact | Path | Port | Description |
|---|---|---|---|
| `proposa` | `/` | 20222 | React+Vite frontend |
| `api-server` | `/api` | 8080 | Express 5 REST API |
| `mockup-sandbox` | `/__mockup` | 8081 | Component preview canvas |

### Libraries
| Package | Purpose |
|---|---|
| `@workspace/db` | Drizzle ORM schema + DB client |
| `@workspace/api-spec` | OpenAPI spec + Orval codegen config |
| `@workspace/api-client-react` | Generated React Query hooks + custom fetch |
| `@workspace/api-zod` | Generated Zod schemas for server validation |

### Database Tables
- `users` — agency staff (admin, manager, freelancer roles)
- `clients` — synced from WHMCS
- `prospects` — lead pipeline
- `prospect_notes` — notes on prospects
- `projects` — synced from WHMCS, with billing info
- `project_tasks` — tasks within projects
- `project_assignees` — user-project assignments
- `activity_log` — system-wide audit trail
- `app_settings` — key/value settings store

### API Routes (all under `/api`)
- `POST /auth/login` · `GET /auth/me` · `POST /auth/logout`
- `GET /dashboard/summary` · `GET /dashboard/my-tasks` · `GET /dashboard/recent-activity` · `GET /dashboard/project-stats`
- `GET /clients` · `POST /clients/sync` · `GET /clients/:id`
- `GET /prospects` · `POST /prospects` · `GET /prospects/:id` · `PUT /prospects/:id` · `DELETE /prospects/:id` · `POST /prospects/:id/convert`
- `GET /projects` · `POST /projects/sync` · `GET /projects/:id` · `PATCH /projects/:id` (status/title/desc — also calls WHMCS UpdateProject)
- `GET /projects/:id/tasks` · `POST /projects/:id/tasks` · `PATCH /projects/:id/tasks/:taskId`
- `GET /users` · `POST /users` · `GET /users/:id` · `PUT /users/:id` · `DELETE /users/:id`
- `GET /activity`
- `GET /settings` · `PUT /settings` · `POST /settings/connectivity/:service`
- `POST /ai/summarize-project/:id` · `POST /ai/generate-update/:id` · `POST /ai/suggest-next-steps/:id`
- `GET /whmcs/available-calls` · `POST /whmcs/execute` (GetQuotes uses local cache fallback; writes update cache)
- `POST /whmcs/quotes/sync` — force re-pull all quotes from WHMCS into local cache
- `GET /webhooks/whmcs` — webhook health/status · `POST /webhooks/whmcs` — WHMCS event receiver

### Sync Architecture
- **Auto-sync scheduler**: Runs syncClients + syncProjects + syncQuotes on server start (30 s delay) then every `sync_interval` minutes (default 60). Reads interval from DB settings dynamically.
- **Quote local cache**: `whmcs_quotes` table mirrors WHMCS quotes. GetQuotes tries WHMCS live first; on failure returns local cache with `cached: true`. AddQuote/UpdateQuote/DeleteQuote update cache after WHMCS success.
- **Project write-back**: PATCH /projects/:id updates local DB, then calls WHMCS UpdateProject. Fails gracefully with `whmcsSynced: false` if WHMCS is unreachable.
- **Webhook receiver**: POST /api/webhooks/whmcs receives WHMCS events and triggers targeted re-syncs. Responds in <1ms, processes async. Optional `WHMCS_WEBHOOK_SECRET` env var for query-param verification.
- **Shared sync lib**: `artifacts/api-server/src/lib/whmcsSync.ts` — all sync logic lives here, used by scheduler + routes + webhooks.

### Frontend Pages
- `/login` — JWT login screen
- `/` or `/dashboard` — Overview metrics, active projects, my tasks, activity feed
- `/clients` — Client directory (syncs from WHMCS)
- `/clients/:id` — Client detail with projects
- `/prospects` — WHMCS native Quotes — full pipeline management (Draft → Delivered → Accepted etc.)
- `/projects` — Project overview with status/billing
- `/projects/:id` — Project detail with tasks and AI actions
- `/activity` — Audit trail / activity log
- `/admin` — Settings, integrations config, user management
- `/whmcs-explorer` — Interactive WHMCS API explorer
- `/modules` — Developer documentation

## Auth
- JWT stored in `localStorage` under key `"token"`
- All API requests use `setAuthTokenGetter(() => localStorage.getItem("token"))` from `@workspace/api-client-react`
- JWT secret uses `process.env.SESSION_SECRET`
- Default credentials: `admin@proposa.com` / `password`

## Configuration (Admin Settings)
Settings stored in `app_settings` table:
- `whmcs_url`, `whmcs_api_identifier`, `whmcs_api_secret` — WHMCS API credentials
- `claude_api_key` — Anthropic Claude API key
- `sync_interval` — Auto-sync interval in minutes
- `feature_ai`, `feature_prospects` — Feature toggles

## Seeded Demo Data
- 3 users: admin@proposa.com, manager@proposa.com, dev@proposa.com (password: `password`)
- 4 clients (Boston Web Group, Acme Corp, TechStart LLC, Fresh Eats Co)
- 5 prospects in various pipeline stages
- 3 projects with tasks and billing info
- Activity log entries
