Files
classroomio/DEV_SETUP_NOTES.md
T

186 lines
8.9 KiB
Markdown
Raw Normal View History

# 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
```bash
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`**
```bash
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`**
```bash
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`.
```bash
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)
```bash
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
```bash
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
```bash
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)
```bash
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:
```bash
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`](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.