# Zettai Process Tracker — Deployment Guide

Full guide to install, migrate, seed, run, and update **Zettai Process Tracker (ZPT)** — Node.js API + static web UI on PostgreSQL.

| Item | Detail |
|------|--------|
| App entry | `server/` (Express + Prisma) |
| UI | Served from `server/web` at `/` (`js/`, `css/`, `assets/`) |
| Env | Single repo-root `.env` (never `server/.env`) |
| Default port | `4000` |
| ORM / migrations | Prisma (`server/prisma`) |

Related: product requirements in [README.md](./README.md), backup notes in [docs/BACKUP_MIGRATE.md](./docs/BACKUP_MIGRATE.md), acceptance checklist in [docs/ACCEPTANCE.md](./docs/ACCEPTANCE.md).

---

## Table of contents

1. [Prerequisites](#1-prerequisites)
2. [Repository layout](#2-repository-layout)
3. [Environment variables](#3-environment-variables)
4. [PostgreSQL setup](#4-postgresql-setup)
5. [Fresh install (end-to-end)](#5-fresh-install-end-to-end)
6. [Database migrations](#6-database-migrations)
7. [Initial seeding](#7-initial-seeding)
8. [Run the application](#8-run-the-application)
9. [Production deployment](#9-production-deployment)
10. [Updating an existing deployment](#10-updating-an-existing-deployment)
11. [Optional maintenance scripts](#11-optional-maintenance-scripts)
12. [Demo accounts (after seed)](#12-demo-accounts-after-seed)
13. [Backup & restore](#13-backup--restore)
14. [Health checks & verification](#14-health-checks--verification)
15. [Troubleshooting](#15-troubleshooting)
16. [Security checklist](#16-security-checklist)

---

## 1. Prerequisites

| Requirement | Notes |
|-------------|--------|
| **Node.js** | `>= 18` (LTS recommended) |
| **npm** | Bundled with Node |
| **PostgreSQL** | 14+ recommended |
| **Git** | To clone / pull the repo |
| **Disk** | Room for DB data + `UPLOAD_DIR` (attachments / evidence) |

Optional tools:

- `psql`, `pg_dump`, `pg_restore` (for DB admin / backups)
- A reverse proxy (nginx / Caddy) and process manager (systemd / PM2) for production

---

## 2. Repository layout

```
zs-tracker/
├── .env / .env.example     # Single env file (repo root only)
├── package.json            # Thin scripts → server/ (no app dependencies)
├── scripts/
│   ├── pg-init.sh          # Local user-space Postgres init
│   ├── pg-start.sh
│   └── pg-stop.sh
├── docs/
└── server/                 # The application
    ├── package.json        # Real dependencies + Prisma scripts
    ├── prisma/
    │   ├── schema.prisma
    │   ├── migrations/
    │   └── seed.ts
    ├── src/                # Express API
    ├── web/                # Product UI (index.html, js/, css/, assets/)
    └── uploads/            # Default file storage (created at runtime)
```

Root npm scripts (run from repo root):

| Script | Action |
|--------|--------|
| `npm run pg:init` | Init local user-space Postgres + create DB |
| `npm run pg:start` | Start local Postgres |
| `npm run pg:stop` | Stop local Postgres |
| `npm run migrate` | `prisma migrate deploy` |
| `npm run seed` | Run seed script |
| `npm run dev` | Dev API + UI (nodemon) |
| `npm run build` | Compile TypeScript → `server/dist` |
| `npm run start` | Run compiled server |
| `npm test` | Vitest |

---

## 3. Environment variables

Copy the example file and edit values:

```bash
cp .env.example .env
```

The server loads **repo-root** `.env` only (`server/src/config.ts`). Do not create `server/.env`.

### Required / important variables

| Variable | Required | Description | Example |
|----------|----------|-------------|---------|
| `DATABASE_URL` | **Yes** | PostgreSQL connection string | `postgresql://zpt:SECRET@127.0.0.1:5432/zpt` |
| `JWT_SECRET` | **Yes** (prod) | Signing secret for auth tokens — use a long random string | (generate with `openssl rand -hex 32`) |
| `JWT_EXPIRES_IN` | No | Token lifetime | `7d` |
| `PORT` | No | HTTP listen port | `4000` |
| `NODE_ENV` | No | `development` or `production` | `production` |
| `UPLOAD_DIR` | No | Attachment storage (relative to `server/` cwd when starting from server) | `./uploads` |
| `CORS_ORIGIN` | No | Allowed browser origin | `https://tracker.example.com` |

### Local-dev helper vars (used by `scripts/pg-*.sh`)

| Variable | Default | Description |
|----------|---------|-------------|
| `PGHOST` | `127.0.0.1` | Host |
| `PGPORT` | `5433` | Local user-space Postgres port |
| `PGUSER` | `zpt` | DB user |
| `PGPASSWORD` | `zpt_dev_secret` | DB password |
| `PGDATABASE` | `zpt` | Database name |

**Never commit `.env`.** Keep secrets out of git.

---

## 4. PostgreSQL setup

Choose **one** of the options below.

### Option A — Local user-space Postgres (dev / demo laptop)

This repo can run PostgreSQL 14 binaries under `.tools/` without a system service.

1. Ensure Postgres binaries exist under `.tools/pgsql-root` (see team notes / README if you need to extract packages).
2. Initialize cluster + database (idempotent-ish):

```bash
# From repo root
npm run pg:init
# equivalent: ./scripts/pg-init.sh
```

3. Start / stop:

```bash
npm run pg:start
npm run pg:stop
```

Default URL (matches `.env.example`):

```text
postgresql://zpt:zpt_dev_secret@127.0.0.1:5433/zpt
```

### Option B — System or managed PostgreSQL (recommended for production)

Create a role and database (as a Postgres superuser):

```bash
sudo -u postgres psql <<'SQL'
CREATE USER zpt WITH PASSWORD 'REPLACE_WITH_STRONG_PASSWORD';
CREATE DATABASE zpt OWNER zpt;
GRANT ALL PRIVILEGES ON DATABASE zpt TO zpt;
SQL
```

Set `DATABASE_URL` in `.env`, for example:

```env
DATABASE_URL=postgresql://zpt:REPLACE_WITH_STRONG_PASSWORD@127.0.0.1:5432/zpt
```

For cloud Postgres (RDS, Cloud SQL, Neon, etc.), use the provider connection string and ensure the app host can reach the DB (firewall / SSL as required).

---

## 5. Fresh install (end-to-end)

Run from the **repository root** unless noted.

```bash
# 1) Clone and enter
git clone <YOUR_REPO_URL> zs-tracker
cd zs-tracker

# 2) Environment
cp .env.example .env
# Edit .env: DATABASE_URL, JWT_SECRET, CORS_ORIGIN, NODE_ENV, PORT

# 3) PostgreSQL must be running and reachable (Option A or B above)
npm run pg:start          # only if using Option A local Postgres

# 4) Install Node dependencies
npm --prefix server install

# 5) Generate Prisma client + apply all migrations
npm --prefix server run db:generate
npm run migrate
# equivalent: npm --prefix server run migrate
#             → prisma migrate deploy

# 6) Initial seed (loads demo employees, projects, tasks, bugs, …)
npm run seed
# equivalent: npm --prefix server run seed

# Or migrate + seed in one step (from server/):
# npm --prefix server run db:setup

# 7) Start
# Development:
npm run dev

# Production (build then start):
npm run build
NODE_ENV=production npm run start
```

Open:

- App: `http://localhost:4000` (or your `PORT` / public URL)
- Health: `http://localhost:4000/api/health`

---

## 6. Database migrations

Migrations live in `server/prisma/migrations/`. Prisma tracks applied versions in the `_prisma_migrations` table.

### Apply pending migrations (staging / production)

Safe for existing databases — applies only new migrations:

```bash
# From repo root
npm run migrate

# Or from server/
cd server
npx prisma migrate deploy
```

Always run this **after** deploying new code that includes new migration folders, and **before** (or as part of) restarting the app.

### Local schema development (developers only)

Creates a new migration from schema changes:

```bash
cd server
npm run migrate:dev
# → prisma migrate dev
```

Do **not** use `migrate:dev` on production — it is interactive and may reset data.

### Other Prisma helpers

```bash
cd server

# Regenerate @prisma/client after schema pull / install
npm run db:generate

# Push schema without migration history (prototyping only — avoid in prod)
npm run db:push
```

### Current migration history (as of this doc)

| Migration folder | Purpose |
|------------------|---------|
| `20261016100530_init` | Initial schema |
| `20261020100000_project_delivery_rules` | Project delivery rule fields |

New migrations appear under `server/prisma/migrations/` as the product evolves — always deploy them with `migrate deploy`.

---

## 7. Initial seeding

### What seed does

`server/prisma/seed.ts`:

1. **Deletes** existing app data (employees, projects, tasks, bugs, timesheets, leave, notifications, timers, attachments metadata, etc.)
2. Inserts demo users, projects (ZPT, PORTAL), tasks/subtasks, bugs, timesheets, leave, holidays, notifications
3. Ensures Done-stage internal status **Released** exists on projects

Password for all seeded users: `Password123!`

### Commands

```bash
# From repo root
npm run seed

# From server/
cd server
npm run seed
# → tsx prisma/seed.ts

# Or via Prisma seed hook (if configured)
npx prisma db seed
```

### Combined migrate + seed

```bash
cd server
npm run db:setup
# → prisma migrate deploy && tsx prisma/seed.ts
```

### Warnings

| Environment | Guidance |
|-------------|----------|
| **Fresh install / demo** | Seed is appropriate |
| **Production with real data** | **Do not** re-run seed — it wipes tables |
| **Need empty schema only** | Run `migrate` without `seed`, then create users via the UI / SQL |

### Demo reset via API (non-production)

When `NODE_ENV` is **not** `production`, Super Admin can reset demo data:

- UI: Configuration / settings reset (if enabled), or
- API:

```bash
curl -X POST http://localhost:4000/api/admin/reset-demo \
  -H "Authorization: Bearer $TOKEN"
```

Disabled in production.

---

## 8. Run the application

### Development

```bash
# Postgres up + .env configured + migrate/seed done
npm run pg:start    # if using local user-space Postgres
npm run dev         # nodemon — restarts on server/src changes
```

Working directory for `npm run start` / `dev` is effectively `server/` (via `npm --prefix server`). `UPLOAD_DIR=./uploads` resolves to `server/uploads`.

### Production (compiled)

```bash
cd /path/to/zs-tracker
npm --prefix server install --omit=dev   # or full install if you build on the host
npm --prefix server run db:generate
npm run migrate
# npm run seed   # ONLY on first empty DB / demo — never on live data

npm run build
NODE_ENV=production npm run start
```

Ensure `.env` has `NODE_ENV=production`, a strong `JWT_SECRET`, correct `DATABASE_URL`, and `CORS_ORIGIN` matching the public site URL.

---

## 9. Production deployment

Suggested pattern (VM or container):

1. **Provision** Node 18+, PostgreSQL, reverse proxy (TLS).
2. **Deploy code** (git pull or artifact) to e.g. `/opt/zs-tracker`.
3. **Configure** `/opt/zs-tracker/.env` (secrets not in git).
4. **Install & migrate:**

```bash
cd /opt/zs-tracker
npm --prefix server ci
npm --prefix server run db:generate
npm run migrate
```

5. **Seed once** on a brand-new empty database only:

```bash
npm run seed
```

6. **Build & run** under a process manager.

### Example systemd unit

`/etc/systemd/system/zpt.service`:

```ini
[Unit]
Description=Zettai Process Tracker
After=network.target postgresql.service

[Service]
Type=simple
User=zpt
WorkingDirectory=/opt/zs-tracker/server
EnvironmentFile=/opt/zs-tracker/.env
ExecStart=/usr/bin/node dist/index.js
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
```

```bash
sudo systemctl daemon-reload
sudo systemctl enable --now zpt
sudo systemctl status zpt
```

Build before enabling:

```bash
cd /opt/zs-tracker && npm run build
```

### Reverse proxy (nginx sketch)

```nginx
server {
  listen 443 ssl http2;
  server_name tracker.example.com;

  # ssl_certificate ...;
  # ssl_certificate_key ...;

  client_max_body_size 50M;   # attachments / evidence

  location / {
    proxy_pass http://127.0.0.1:4000;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
}
```

Set `CORS_ORIGIN=https://tracker.example.com` (same origin is safest if UI is served by the app).

### Uploads directory

- Default: `server/uploads`
- Persist this directory across deploys (bind mount / volume)
- Include it in backups with the database
- Ensure the process user can write to it

---

## 10. Updating an existing deployment

```bash
cd /opt/zs-tracker

# 1) Backup DB + uploads first (see §13)

# 2) Pull / unpack new release
git pull   # or copy artifact

# 3) Dependencies + Prisma client
npm --prefix server ci
npm --prefix server run db:generate

# 4) Apply new migrations (non-destructive for data)
npm run migrate

# 5) Rebuild & restart
npm run build
sudo systemctl restart zpt
# or: pm2 restart zpt
```

**Do not** run `npm run seed` on update unless you intentionally want to wipe and reload demo data.

After schema changes that add statuses (e.g. Released), you may run the ensure script in §11 if seed is not re-run.

---

## 11. Optional maintenance scripts

### Ensure “Released” internal status on all projects

Safe to re-run. Adds Done → **Released** where missing:

```bash
cd server
npx tsx scripts/ensure-released-status.ts
```

Requires a working `DATABASE_URL` (and Postgres up).

### Extra test bugs (dev)

```bash
cd server
npx tsx scripts/seed-test-bugs.ts
```

Use only in non-production / test DBs.

---

## 12. Demo accounts (after seed)

All seeded users share password: **`Password123!`**

| Email | Name | Role |
|-------|------|------|
| `gowtham@zettai.demo` | Gowtham | Super Admin |
| `priya@zettai.demo` | Priya | Project Admin |
| `arun@zettai.demo` | Arun | BA |
| `karthik@zettai.demo` | Karthik | Developer |
| `nisha@zettai.demo` | Nisha | Tester / QA |
| `meena@zettai.demo` | Meena | Developer |
| `vikram@zettai.demo` | Vikram | Developer (inactive) |

Seeded sample data includes projects **ZPT** and **PORTAL**, tasks, bugs, timesheets, leave, and holidays.

**Production:** change or disable demo passwords immediately, or skip seed and provision real employees.

---

## 13. Backup & restore

### Database

```bash
# Load DATABASE_URL from .env, then:
export $(grep -v '^#' .env | xargs)   # careful on shared shells

pg_dump "$DATABASE_URL" -Fc -f "zpt-$(date +%Y%m%d).dump"
```

Restore:

```bash
pg_restore -d "$DATABASE_URL" --clean --if-exists zpt-YYYYMMDD.dump
```

### Uploads

```bash
tar -czf "zpt-uploads-$(date +%Y%m%d).tar.gz" -C server uploads
```

Restore by extracting into `server/uploads` (or your `UPLOAD_DIR`).

See also [docs/BACKUP_MIGRATE.md](./docs/BACKUP_MIGRATE.md).

---

## 14. Health checks & verification

```bash
# API up
curl -sS http://localhost:4000/api/health

# Login smoke test (demo Super Admin after seed)
curl -sS -X POST http://localhost:4000/api/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"email":"gowtham@zettai.demo","password":"Password123!"}'
```

Manual UI checks:

1. Open `/` → login screen  
2. Sign in → apps grid (Dashboards, Project, Timesheets, Time Off, Employees)  
3. Projects / Tasks / Bugs load  
4. Create an attachment on a task → file appears under `UPLOAD_DIR`

---

## 15. Troubleshooting

| Symptom | Likely cause | Fix |
|---------|--------------|-----|
| `Missing required env var: DATABASE_URL` | No `.env` or wrong path | Create root `.env` from `.env.example` |
| `Can't reach database server` | Postgres down / wrong host/port | `npm run pg:start` or start system Postgres; verify `DATABASE_URL` |
| `P1001` / connection refused on `5433` | Local PG not started | `npm run pg:init` then `npm run pg:start` |
| Migration errors on deploy | DB out of sync / partial apply | Inspect `_prisma_migrations`; restore backup; fix forward with new migration (avoid editing old ones in prod) |
| Seed fails mid-run | Constraint / connection | Fix error, re-run seed (it wipes then reloads) |
| Uploads 500 / ENOENT | Missing upload dir permissions | `mkdir -p server/uploads && chown` app user |
| Login works but CORS errors | Wrong `CORS_ORIGIN` | Match browser origin exactly (scheme + host + port) |
| Old UI/JS after deploy | Browser cache | Hard refresh; UI uses `?v=` cache-bust on assets |

---

## 16. Security checklist

- [ ] Strong unique `JWT_SECRET` in production  
- [ ] Strong DB password; DB not exposed publicly without TLS / allowlists  
- [ ] `NODE_ENV=production` (disables demo reset API)  
- [ ] Do **not** leave demo passwords on internet-facing installs  
- [ ] Do **not** re-seed production  
- [ ] TLS at reverse proxy  
- [ ] Restrict write access to `.env` and `UPLOAD_DIR`  
- [ ] Regular `pg_dump` + uploads backups  
- [ ] Keep Node and PostgreSQL patched  

---

## Quick reference card

```bash
# --- First time ---
cp .env.example .env          # edit secrets
npm run pg:init && npm run pg:start   # local PG only
npm --prefix server install
npm --prefix server run db:generate
npm run migrate
npm run seed
npm run dev                   # or: npm run build && npm run start

# --- Every release ---
npm --prefix server ci
npm --prefix server run db:generate
npm run migrate               # never seed on live data
npm run build
# restart process manager
```

---

*Internal deployment doc for Zettai Process Tracker. For product behaviour and RBAC, see [README.md](./README.md).*
