Files
classroomio/DEV_SETUP_NOTES.md
T
Abdulmuizz Hamzat 5e2dcf71f4 docs: add dev setup guide and make package scripts cross-platform (Windows) (#664)
* chore: update README with environment setup instructions and demo account credentials

fix: replace rm -rf with rimraf in build scripts for cross-platform compatibility

fix: add shell option to pnpm command in db-setup script for Windows compatibility

chore: update package.json files to use rimraf instead of rm -rf for consistency

chore: add rimraf dependency to pnpm-lock.yaml

feat: add postinstall script to install lefthook git hooks in a cross-platform manner

* docs(qa): add QA test plan, flow checklists, and bug-report workflow

Add a repo-native QA execution layer on top of FEATURE_AUDIT.md (the
feature map). Test cases live in the repo; bugs live in GitHub Issues, so
there is no duplicate tracker to keep in sync.

QA system:
- FEATURE_AUDIT.md: the feature map - every feature, its user flow, and
  edge cases with file:line citations.
- qa/README.md: the workflow, severity/difficulty rubrics, label setup,
  and a static feature -> flow coverage map proving all 42 audited
  features have a test plan.
- qa/flows/01..13: per-flow happy-path checklists covering signup &
  onboarding, course authoring, people/invites/roles, student ->
  certificate, AI assistant & tutor, programs/attendance, community,
  org public site, media & import, org settings, public API/MCP,
  enterprise SSO/licensing, and billing & AI credits.
- .github/ISSUE_TEMPLATE/qa-bug.yml: a QA Bug template requiring
  severity, difficulty, area, repro steps, and a screen recording.

Dev tooling:
- package.json: add db:studio and docker:build scripts.
- packages/db: add db:studio (drizzle-kit studio); fix db:reset on
  Windows by spawning the pnpm.cmd shim with shell:true (Node's
  CVE-2024-27980 fix blocks spawning .cmd/.bat without a shell).

* chore: update QA bug template and README for clarity and improved workflow

* docs: enhance DEV_SETUP_NOTES and README for clarity on prerequisites and email setup
chore: update package.json scripts for cross-platform compatibility
feat: add cross-platform Prettier check script for pre-commit hook

* Remove QA documentation and flow files for ClassroomIO

- Deleted the entire QA README.md file which contained the QA process, bug filing guidelines, and feature coverage map.
- Removed all flow files (01 to 13) that detailed the QA testing processes for various features including admin signup, course authoring, people management, student learning, AI assistant, programs, community, org public site, media management, org settings, public API, enterprise SSO, billing, and AI credits.

* fix: update postinstall script
2026-06-15 17:40:06 +01:00

8.9 KiB

ClassroomIO — Local Dev Setup Guide

A practical guide to running classroomio locally for development, plus a troubleshooting reference for the errors you're likely to hit. Use it to set up a fresh machine or to onboard a new contributor.

Works on macOS, Linux, and Windows. Windows users: run the interactive commands in Git Bash (Unix commands like cp work there). The repo's package scripts are already cross-platform.


1. Prerequisites

Tool Version Required? Notes
Node.js 20.x (.nvmrc = v20.19.3) Required nvm install && nvm use
pnpm 10.x Required The package scripts call pnpm directly (e.g. build:clean runs pnpm run build) — npm/yarn are not supported substitutes. corepack enable then corepack prepare pnpm@latest --activate, or npm i -g pnpm
Docker (Desktop) latest Required Runs Postgres + Redis (and optionally MinIO). No local install of those needed.
Git latest Required Windows: includes Git Bash
ffmpeg / ffprobe latest Optional Only for media/thumbnail background jobs

2. Setup steps

Step 1 — Install dependencies

pnpm i

Step 2 — Create the .env files

Each app/package reads its own .env. Copy each .env.example to .env and fill the values below (host ports). The secret values are placeholders — generate each one with openssl rand -hex 32 rather than copying the example text. The two PRIVATE_SERVER_KEY values must match, so generate it once and paste the same value into both files.

apps/api/.env

DATABASE_URL="postgresql://postgres:postgres@localhost:5432/classroomio"
REDIS_URL="redis://localhost:6379"
PUBLIC_SERVER_URL="http://localhost:3002"
TRUSTED_ORIGINS="http://localhost:5173"        # the dashboard dev origin
BETTER_AUTH_SECRET="<generate-with-openssl-rand-hex-32>"
AUTH_BEARER_TOKEN="<generate-with-openssl-rand-hex-32>"
PRIVATE_SERVER_KEY="<generate-with-openssl-rand-hex-32>"   # generate once; use the SAME value in the dashboard

apps/dashboard/.env

PUBLIC_SERVER_URL="http://localhost:3002"
PRIVATE_SERVER_URL="http://localhost:3002"      # used by the SSR auth proxy — required for login
PRIVATE_SERVER_KEY="<generate-with-openssl-rand-hex-32>"   # must match the API (paste the value generated above)
PUBLIC_IS_SELFHOSTED=true

apps/jobs/.env — only if you'll run the background workers (pnpm api:dev starts them). Simplest: copy the API env, which already has REDIS_URL + DATABASE_URL.

cp apps/api/.env apps/jobs/.env

packages/db/.env — used by the DB setup scripts (Step 4). Created there.

Why so many? The dashboard calls the API through a server-side proxy (/api/auth/*), so it needs PRIVATE_SERVER_URL. The API's better-auth needs BETTER_AUTH_SECRET (to sign sessions) and TRUSTED_ORIGINS (to trust the dashboard origin). Server-to-server data calls use the shared PRIVATE_SERVER_KEY.

Step 3 — Start infrastructure (Postgres + Redis)

docker compose -f docker/docker-compose.yaml up -d postgres redis

(Optional — object storage for uploads: docker compose -f docker/docker-compose.yaml --profile minio up -d minio minio-init.)

Step 4 — Set up + seed the database

cp packages/db/.env.example packages/db/.env     # contains DATABASE_URL for the db scripts
pnpm --filter @cio/db db:setup:seed              # creates schema + demo data

Step 5 — Build the shared packages once

pnpm build

The dashboard/api import workspace libs (@cio/ui, @cio/api, @cio/db, …) from their dist/, which only exists after a build. (If @cio/jobs-worker fails here on ffmpegProbeLuma, that's a known branch bug — see Known issues; it doesn't block dashboard/api.)

Step 6 — Run the app (two terminals)

pnpm api:dev          # API (port 3002) + background workers
pnpm dashboard:dev    # dashboard UI (port 5173)

Don't use pnpm dev — it tries to start the whole monorepo (~20 services) and currently trips a turbo concurrency limit. The two scoped commands above are the day-to-day workflow.

Step 7 — Log in

Open http://localhost:5173/login → admin@test.com / 123456.

Email (optional)

Email is off by default and the app runs fine without it. You only need it to test auth emails (verify/reset) and notifications.

To enable, set the SMTP vars in apps/api/.env (auth-flow emails) and apps/jobs/.env (all other emails) — both can point at the same server:

SMTP_HOST=  SMTP_PORT=  SMTP_USER=  SMTP_SENDER=  SMTP_PASSWORD=

Any SMTP provider works (Zoho ZeptoMail, Resend, Gmail SMTP, or Mailtrap for throwaway testing). See the inline notes in apps/api/.env.example for which emails each process sends.

Cost: most providers have a free tier for low volume; sustained/high volume is paid. For local dev a free sandbox (e.g. Mailtrap) or a provider's free tier is enough — developing costs nothing.


3. Ports

Service URL / Port Notes
API http://localhost:3002 backend (API_PORT default)
Dashboard http://localhost:5173 Vite dev server
Postgres localhost:5432 Docker container cio-postgres
Redis localhost:6379 Docker container cio-redis
MinIO 9000 / console 9001 only if started (optional)
jobs-worker (none) background worker, no HTTP port

4. Demo accounts

Seeded accounts use password 123456 (verified against the seed's bcrypt hashes):

  • admin@test.com / 123456 (admin — "Elon Gates")
  • enterprise@test.com, early-adopter@test.com, and the *-student@test.com accounts — also 123456

test@test.com's seed hash doesn't match common passwords — use admin@test.com.


5. Troubleshooting

Symptom Cause Fix
no such service: db-init db-init was removed; the api container now runs DB setup Don't reference db-init. For host dev use db:setup:seed (Step 4).
DATABASE_URL or PRIVATE_DATABASE_URL ... required packages/db/.env missing (db scripts read their own dir) cp packages/db/.env.example packages/db/.env
password authentication failed for user "postgres" localhost:5432 is another project's Postgres, not classroomio's Stop the other container / free port 5432, then recreate: docker compose -f docker/docker-compose.yaml up -d postgres
Failed to resolve entry for package "@cio/*" shared packages not built (dist/ missing) pnpm build, then re-run the dev commands
'rm'/'cp' is not recognized or spawn EINVAL (Windows) Unix command / .cmd spawn in a script Already fixed in-repo (rimraf, Node copy, shell:true). Run pnpm i to get latest.
invalid task configuration … N persistent tasks … concurrency pnpm dev starts the whole monorepo past turbo's cap Use scoped pnpm api:dev + pnpm dashboard:dev instead
ZodError … REDIS_URL ... expected string, received undefined apps/jobs/.env missing REDIS_URL cp apps/api/.env apps/jobs/.env and set REDIS_URL=redis://localhost:6379
API upstream not configured (502) on login dashboard SSR proxy has no upstream Set PRIVATE_SERVER_URL=http://localhost:3002 in apps/dashboard/.env, restart dashboard
Login Invalid email or password wrong demo password Use admin@test.com / 123456
Login still fails after upstream fix API auth env empty Fill BETTER_AUTH_SECRET, TRUSTED_ORIGINS=http://localhost:5173, PUBLIC_SERVER_URL in apps/api/.env, restart API
Changed a .env but nothing changed env is read at process start Restart the affected *:dev server

After editing any .env, restart the relevant dev server.


6. Known issues (not setup problems)

  • ffmpegProbeLuma not exported — branch bug (commit 78ab13f54): apps/jobs/src/processors/media/generate-thumbnail.ts imports ffmpegProbeLuma but apps/jobs/src/utils/ffmpeg.ts doesn't export it. Crashes the two media workers only; API / dashboard / emails / maintenance are fine. For the thumbnail-feature owner.
  • ffmpeg/ffprobe not installed — media jobs need these binaries on PATH (or set FFMPEG_PATH / FFPROBE_PATH). Other workers are unaffected.
  • pnpm dev concurrency — full-stack run needs a turbo --concurrency bump; intentionally not changed. Use the scoped workflow.

7. Windows notes

  • Use Git Bash for interactive commands (cp, rm, etc.).
  • The repo's package scripts were made cross-platform (rimraf instead of rm -rf, a Node postinstall, a Node file-copy, and shell:true when scripts spawn pnpm), so pnpm i / pnpm build work in cmd.exe/PowerShell too.