Skip to content
Closed
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
38 changes: 23 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/<app>` 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

Expand Down
18 changes: 4 additions & 14 deletions apps/api/vercel.json
Original file line number Diff line number Diff line change
@@ -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"
}
11 changes: 4 additions & 7 deletions apps/docs/vercel.json
Original file line number Diff line number Diff line change
@@ -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"
}
14 changes: 3 additions & 11 deletions apps/web/vercel.json
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
134 changes: 98 additions & 36 deletions doc/DEPLOYMENT.md
Original file line number Diff line number Diff line change
@@ -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/<app>` (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

Expand Down Expand Up @@ -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

Expand Down
52 changes: 45 additions & 7 deletions docs/handoffs/2026-07-25-centralize-deployments.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,69 @@
# 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
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)
Loading