diff --git a/README.md b/README.md index adb5d9f..6cd8e9f 100644 --- a/README.md +++ b/README.md @@ -136,24 +136,32 @@ pnpm preview # Preview production build ### Production Environments -- **Web Application**: [worksight.vercel.app](https://worksight.vercel.app) -- **Documentation**: [worksight.github.io](https://worksight.github.io) +- **Web Application** (`@worksight/web`): Vercel โ€” + [worksight.vercel.app](https://worksight.vercel.app) +- **Documentation** (`@worksight/docs`): GitHub Pages (optionally Vercel) +- **API** (`@worksight/api`): Docker (`docker-compose.yml` + `nginx/`) ### Deployment Process -1. **Automatic Deployment**: - - Push to `main` branch triggers production deployment - - Pull requests create preview deployments (web app only) - -2. **Manual Deployment**: - - ```bash - # Trigger GitHub Actions workflow - gh workflow run deploy.yml - ``` - -See [Deployment Guide](./apps/docs/guide/deployment.md) for detailed -instructions. +This is a Turborepo + pnpm monorepo, so each app deploys as its **own** Vercel +project (or non-Vercel target). Vercel loads a single `vercel.json` per project +based on its dashboard **Root Directory** setting: + +- **Web** (`worksight`): Root Directory `apps/web` โ†’ `apps/web/vercel.json`. +- **API** (`worksight-api`): Root Directory `apps/api` โ†’ `apps/api/vercel.json` + (still needs a serverless handler; Docker is the working path today). +- **Docs** (`worksight-docs`): Root Directory `apps/docs` โ†’ + `apps/docs/vercel.json`. + +All three share `pnpm install --frozen-lockfile`, a +`pnpm turbo run build --filter=@worksight/` command, production branch `canary`, and +skip-unaffected-project deploys. No environment values are committed to +`vercel.json`. + +Dashboard-only steps (creating projects, setting Root Directory, adding env +vars) cannot be performed by repo files. See the +[Deployment Guide](./doc/DEPLOYMENT.md) for the full setup, including the +required Vercel dashboard configuration. ## ๐Ÿงช Testing diff --git a/apps/api/vercel.json b/apps/api/vercel.json index 7b3f518..0a14dae 100644 --- a/apps/api/vercel.json +++ b/apps/api/vercel.json @@ -1,16 +1,6 @@ { - "version": 2, - "builds": [ - { - "src": "dist/main.js", - "use": "@vercel/node" - } - ], - "routes": [ - { - "src": "/(.*)", - "dest": "dist/main.js", - "methods": ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"] - } - ] + "$schema": "https://openapi.vercel.sh/vercel.json", + "installCommand": "pnpm install --frozen-lockfile", + "buildCommand": "pnpm turbo run build --filter=@worksight/api", + "outputDirectory": "dist" } diff --git a/apps/docs/vercel.json b/apps/docs/vercel.json index 1d6f65e..3327b5e 100644 --- a/apps/docs/vercel.json +++ b/apps/docs/vercel.json @@ -1,10 +1,7 @@ { - "version": 2, - "installCommand": "pnpm install --frozen-lockfile", - "buildCommand": "pnpm --filter @worksight/docs build", - "outputDirectory": ".vitepress/dist", + "$schema": "https://openapi.vercel.sh/vercel.json", "framework": "vitepress", - "build": { - "env": {} - } + "installCommand": "pnpm install --frozen-lockfile", + "buildCommand": "pnpm turbo run build --filter=@worksight/docs", + "outputDirectory": ".vitepress/dist" } diff --git a/apps/web/vercel.json b/apps/web/vercel.json index ce91016..b760636 100644 --- a/apps/web/vercel.json +++ b/apps/web/vercel.json @@ -1,16 +1,8 @@ { - "version": 2, - "installCommand": "pnpm install --frozen-lockfile", - "buildCommand": "pnpm --filter @worksight/web build", - "outputDirectory": ".next", + "$schema": "https://openapi.vercel.sh/vercel.json", "framework": "nextjs", - "env": { - "NEXT_PUBLIC_APP_NAME": "WorkSight", - "NEXT_PUBLIC_APP_DESCRIPTION": "Employee Well-being Analytics Platform", - "NEXT_PUBLIC_SUPABASE_URL": "https://ontaynsmofmfvzypfhra.supabase.co", - "NEXT_PUBLIC_SUPABASE_ANON_KEY": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im9udGF5bnNtb2ZtZnZ6eXBmaHJhIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQxNTE4NDksImV4cCI6MjA2OTcyNzg0OX0.5x1_4JpVZPtesadh0TI6-eVArLCv-Pnukju1VDNIj14", - "NEXT_PUBLIC_APP_URL": "https://worksight.vercel.app" - }, + "installCommand": "pnpm install --frozen-lockfile", + "buildCommand": "pnpm turbo run build --filter=@worksight/web", "build": { "env": { "NEXT_TELEMETRY_DISABLED": "1" diff --git a/doc/DEPLOYMENT.md b/doc/DEPLOYMENT.md index 0b422a1..039acd9 100644 --- a/doc/DEPLOYMENT.md +++ b/doc/DEPLOYMENT.md @@ -1,36 +1,92 @@ # ๐Ÿš€ WorkSight Deployment Guide -## Quick Deploy to Vercel +WorkSight is a **Turborepo + pnpm workspace** monorepo. There is no single +deploy artifact โ€” each app ships on the platform that fits it: + +| App | Package | Vercel project | Root Directory | Config source of truth | +| ----------- | ----------------- | ---------------- | -------------- | ----------------------- | +| `apps/web` | `@worksight/web` | `worksight` | `apps/web` | `apps/web/vercel.json` | +| `apps/api` | `@worksight/api` | `worksight-api` | `apps/api` | `apps/api/vercel.json` | +| `apps/docs` | `@worksight/docs` | `worksight-docs` | `apps/docs` | `apps/docs/vercel.json` | + +All three Vercel projects are connected to the same GitHub repository +(`4sightorg/worksight`) with production branch **`canary`**, share +`pnpm install --frozen-lockfile`, and have **Include source files outside of the +Root Directory** plus **skip unaffected projects** enabled. The API can +alternatively run under Docker (`docker-compose.yml` + `nginx/`). + +> โš ๏ธ **What repo config can and cannot do.** A `vercel.json` file only +> configures build/routing behavior. It **cannot** create Vercel projects, set a +> project's **Root Directory**, add environment variables to the dashboard, or +> link a Git repo. Those are dashboard/CLI actions โ€” they are called out +> explicitly under +> [Vercel dashboard setup](#vercel-dashboard-setup-one-time-per-project). + +## How Vercel resolves config in this monorepo + +Vercel reads **exactly one** `vercel.json` per project: the one located at the +project's **Root Directory** (a dashboard setting). It does **not** merge a root +`vercel.json` with a nested one. Consequences: + +- One Vercel project builds one output, so web, api, and docs need **separate** + projects. A single root `vercel.json` cannot govern all three. +- "Centralized" here means **uniform, per-app configs** committed next to each + app, all using the same workspace-level primitives โ€” not one shared file. +- Each project's Root Directory therefore points at its app, and that app's + `vercel.json` is the only file Vercel loads for it. + +Every app config uses the same primitives, so behavior is consistent: + +- Install: `pnpm install --frozen-lockfile` +- Build: `pnpm turbo run build --filter=@worksight/` (Turbo runs the build + script; its `dependsOn: ["^build"]` graph builds workspace dependencies + such as `@worksight/common` and `@worksight/assets` first). +- Output: framework default for Next.js; explicit for docs (`.vitepress/dist`) + and api (`dist`). + +Secrets and environment values live in the **dashboard**, not in `vercel.json`. + +## Vercel dashboard setup (one-time, per project) + +These steps **must** be done in the Vercel dashboard or CLI โ€” no repo file can +perform them. + +### Web project (`@worksight/web`) + +1. Import the `4sightorg/worksight` repo as a new Vercel project. +2. **Root Directory โ†’ `apps/web`**, so Vercel loads `apps/web/vercel.json`. +3. Leave **"Include source files outside of the Root Directory in the Build + Step"** enabled so the shared `packages/*` and the workspace lockfile are + available. +4. Framework Preset / Install / Build come from `apps/web/vercel.json`; do not + override them in the dashboard. +5. Add environment variables per environment (see + [Environment Variables](#environment-variables)). Nothing sensitive is + committed to `vercel.json`. + +### Docs project (`@worksight/docs`) โ€” optional on Vercel + +1. Create a **separate** Vercel project from the same repo. +2. **Root Directory โ†’ `apps/docs`** so Vercel loads `apps/docs/vercel.json`. +3. Keep "Include source files outside of the Root Directory" enabled. + +Docs are otherwise published to GitHub Pages; the Vercel path is optional. + +### API project (`@worksight/api`) + +`apps/api/vercel.json` now uses zero-config build settings (`pnpm --filter` +build into `dist`) instead of the legacy `builds`/`routes` block, which silently +disabled Vercel's install and build steps. + +**This is still not a functioning serverless API.** `main.ts` calls +`app.listen()` rather than exporting a handler, so a Vercel deployment produces +no invocable function. Wiring it properly requires adding a serverless entry +(e.g. `api/index.ts` exporting the bootstrapped Nest app). Until then, deploy +the API with Docker: -### One-Click Deploy - -[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/4sightorg/worksight) - -### Manual Deployment - -1. **Install Vercel CLI** - - ```bash - pnpm add -g vercel - ``` - -2. **Login to Vercel** - - ```bash - vercel login - ``` - -3. **Deploy Preview** - - ```bash - pnpm run deploy:preview - ``` - -4. **Deploy Production** - - ```bash - pnpm run deploy - ``` +```bash +docker compose up -d --build +``` ## Environment Variables @@ -59,13 +115,19 @@ NEXT_PUBLIC_IS_OFFLINE="true" ## Vercel Configuration -The `vercel.json` file includes: +`apps/web/vercel.json` (loaded by the `worksight` project) declares: + +- `framework: nextjs` โ€” output directory left to the framework default +- `installCommand: pnpm install --frozen-lockfile` +- `buildCommand: pnpm turbo run build --filter=@worksight/web` +- `NEXT_TELEMETRY_DISABLED=1` for the build step + +`apps/api/vercel.json` and `apps/docs/vercel.json` mirror the same shape with +their own filter and output directory. No environment values are committed โ€” +they are set per environment in the dashboard. -- **Optimized builds** with Next.js -- **Security headers** for production -- **API route configuration** -- **Redirects and rewrites** -- **CORS headers** for API endpoints +Security headers, redirects, and CORS are **not** currently configured in +`vercel.json`; add them here if/when needed rather than assuming they exist. ## Code Quality Checks diff --git a/docs/handoffs/2026-07-25-centralize-deployments.md b/docs/handoffs/2026-07-25-centralize-deployments.md index a7deca4..a5564e9 100644 --- a/docs/handoffs/2026-07-25-centralize-deployments.md +++ b/docs/handoffs/2026-07-25-centralize-deployments.md @@ -1,24 +1,61 @@ # HANDOFF โ€” Centralize deployments (#20) -**Status:** Planned -**Branch:** `feat/mvp-deploy` (after stabilize #15) +**Status:** In progress (repo-side config done) +**Branch:** `feat/vercel-monorepo-config-20` **Issue(s):** #20 **Last updated:** 2026-07-25 ## Bottom line -One primary deploy path for web + api + docs; root env matrix; CI path filters; demote split vercel.json drift. + +Three Vercel projects (`worksight`, `worksight-api`, `worksight-docs`), one +uniform per-app `vercel.json` each, all using the same pnpm workspace install +and filtered build. Dashboard settings (Root Directory, production branch +`canary`, skip-unaffected deploys) were applied via the Vercel API and are +documented here. + +## What changed (repo-side) + +- `apps/web/vercel.json`: `framework: nextjs`, `pnpm install --frozen-lockfile`, + `pnpm --filter @worksight/web build`, telemetry off. No `outputDirectory` + (Next.js preset default), and the previously committed `NEXT_PUBLIC_*` values + โ€” including the Supabase anon key โ€” removed in favor of dashboard env vars. +- `apps/docs/vercel.json`: same shape, output `.vitepress/dist`. +- `apps/api/vercel.json`: replaced the legacy `builds`/`routes` block (which + disabled Vercel's install/build steps entirely) with zero-config build + settings; output `dist`. +- `doc/DEPLOYMENT.md` + `README.md`: per-project table with actual Root + Directory values, dashboard steps, and an honest note that the API has no + serverless handler yet. + +## Dashboard state (applied via Vercel API) + +- Root Directory: `apps/web` / `apps/api` / `apps/docs` respectively. +- "Include source files outside of the Root Directory" enabled (workspace + `packages/*` + lockfile). +- Skip deploys for unaffected projects enabled. +- Production branch `canary`. +- Env vars remain dashboard-managed per environment. + +## Remaining + +- API needs a serverless entry (`main.ts` calls `app.listen()`), or stays on + Docker. +- API env matrix is Docker-side only. ## Current state -- `apps/web/vercel.json`, `apps/api/vercel.json` + +- `apps/web/vercel.json`, `apps/api/vercel.json`, `apps/docs/vercel.json` - Root `docker-compose.yml` + `nginx/` + `doc/DEPLOYMENT.md` ## Hook points + - `docker-compose.yml`, `nginx/` - Root `.github/workflows` - Root `.env.example` - `doc/DEPLOYMENT.md`, README ## How to verify + ```bash docker compose config pnpm --filter @worksight/web build @@ -26,6 +63,7 @@ pnpm --filter @worksight/api build ``` ## Done means -- [ ] One documented SoT deploy path -- [ ] Env matrix covers web+api -- [ ] DEPLOYMENT.md matches reality + +- [x] One documented deploy path per app (uniform per-app `vercel.json`) +- [x] DEPLOYMENT.md matches reality (per-app targets + dashboard steps) +- [ ] Env matrix covers web+api (web done in config; api env still Docker-side)