This guide is a practical, hands-on companion for the CSE 110 Team 09 private
handoff video and for any future maintainer picking up WatchTower. It explains
how to access, run, change, test, and deploy the project. For the product
overview and full reference, start at the root README.md; for
the documentation map, see docs/README.md.
Prerequisites: Node.js 18+ (CI runs Node 24) and npm.
Clone the repo
git clone https://github.com/cse110-sp26-group09/Watchtower-Course-Project.git
cd Watchtower-Course-Project
Install dependencies
npm install
Create your environment file
cp .env.example .env
Fill in env vars if needed. All are optional for a basic local run. Set
CLERK_PUBLISHABLE_KEY for real sign-in, the SUPABASE_* vars for
persistence, and the GMAIL_* vars for alert emails. With none of these the
server runs in-memory with header-trust auth, which is enough for local
development and tests.
Start the server
npm start
This runs npm run config:clerk (generates src/frontend/auth/clerk-config.js)
then boots src/backend/server.js on port 3000.
Open the local URLs
| URL | Description |
|---|---|
http://localhost:3000/ |
Redirects to the landing page |
http://localhost:3000/landing/ |
Public landing page |
http://localhost:3000/dashboard |
Dashboard (requires Clerk sign-in) |
http://localhost:3000/demo/ |
Monitored demo app that sends events |
http://localhost:3000/dashboard-demo/ |
Static dashboard preview (no sign-in) |
.github/ # Issue/PR templates, Dependabot config, and CI workflows
archive/ # Historical Prototype 1 & 2 code, kept for project history only
docs/ # Product, architecture, ADRs, process, research, sprint docs (+ this guide)
scripts/ # Build/startup helpers (e.g. generate-clerk-config.js)
src/
├── backend/ # Node.js HTTP server, event store, mailer, alert logic
├── frontend/ # dashboard/, landing/, auth/, demo/, dashboard-demo/, shared assets/
├── sdk/ # Browser SDK (watchtower.js) that monitored apps embed
└── shared/ # Cross-cutting utilities (event-utils.js)
tests/ # unit/ (Jest) and e2e/ (Playwright)
See src/README.md for the served routes and a deeper source
breakdown.
| Command | What it does |
|---|---|
npm start |
Generates the Clerk config, then runs src/backend/server.js. |
npm run test:unit |
Jest unit tests for the src/backend pure modules (no server needed). |
npm run test:e2e |
Playwright end-to-end tests against a running server. |
npm run docs:js |
Generates JSDoc API docs into docs/api/ (gitignored). |
.github/workflows/ci.yml)
runs on every push and pull request to main: repo-structure checks,
HTML/CSS/JS validation, unit tests, a JSDoc generation check, a dependency
audit, and the Playwright e2e suite (CI starts the server in the background
before running e2e).npm start
with CLERK_PUBLISHABLE_KEY, the SUPABASE_* vars, and any alert vars set
under Render → Environment./api/events endpoint. It does not run the backend or database.A safe, demo-friendly change for the handoff video, for example editing a piece of
copy text on the landing page (src/frontend/landing/index.html) or a dashboard
card label (src/frontend/dashboard/index.html):
git checkout -b demo/small-copy-change.Run the app and verify visually:
npm start # open http://localhost:3000/landing/
Run the unit tests to confirm nothing broke:
npm run test:unit
External test app ──► WatchTower SDK ──POST /api/events──► Node.js backend
│
▼
Supabase / Postgres
│
▼
WatchTower dashboard (per user)
A monitored app embeds the SDK, which batches events to POST /api/events. The
backend normalizes and stores them in Supabase (or in-memory when Supabase is not
configured), and the Clerk-authenticated dashboard reads back only the signed-in
user’s events.
app_users (Supabase) holds one row per Clerk user, keyed by
clerk_user_id. The dashboard upserts it via POST /api/users/sync.prototype3_events.user_id scopes telemetry: dashboard reads only return
rows whose user_id matches the signed-in Clerk user.DEFAULT_INGEST_OWNER_USER_ID is a temporary, demo-only mapping. The
external test app has no Clerk session, so its otherwise-anonymous events would
store with user_id = NULL and never appear on a dashboard. Setting this env
var attributes those events to one demo owner so they show up during a live
demo.See docs/architecture/auth-workflow.md for the
full flow.
npm run config:clerk
(or just npm start, which runs it first). It writes
src/frontend/auth/clerk-config.js from CLERK_PUBLISHABLE_KEY. The file is
gitignored; set the key in .env or in Render → Environment.SUPABASE_URL / key, the server falls
back to in-memory storage; events are lost on restart but everything else
works. The startup log prints which store is active.200 but don’t appear. The external app ingests
without a Clerk session, so events store with user_id = NULL. Set
DEFAULT_INGEST_OWNER_USER_ID (Render env) to the demo owner’s Clerk id so they
land on that owner’s dashboard.npm start)
in one terminal and run npm run test:e2e in another, or set BASE_URL. CI
starts the server automatically..env or a generated
clerk-config.js that contains a real key. Only .env.example and
clerk-config.example.js carry placeholder values.npm start + local URLs)npm run test:unit, npm run test:e2e, npm run docs:js)DEFAULT_INGEST_OWNER_USER_ID with a proper project/app key model for
multi-tenant ingestion.sub claim).