Skip to content

Commit 5e69e40

Browse files
authored
docs: align Node/pnpm versions & update devcontainer onboarding (#5150)
1 parent 51f5a1e commit 5e69e40

9 files changed

Lines changed: 79 additions & 32 deletions

File tree

.agents/skills/klicker-environment-doctor/SKILL.md

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,32 @@ lsof -nP -iTCP:5432 -sTCP:LISTEN # repeat for 6379 6380 6381 7077 8888 80 443
5555

5656
`Bind for :::5432 failed: port is already allocated` means another stack holds the port — stop it or don't start the colliding service. Worktrees get **parallel compose projects** (project name = directory name) but fight over the same host ports; only one stack variant runs per machine.
5757

58-
## Check 6 — infra bring-up (headless-safe)
58+
## Check 6 — infra bring-up / server status (headless-safe)
59+
60+
Depending on your environment path:
61+
62+
### Path A: Inside Devcontainer
63+
64+
The container manages infra services and app servers automatically in the background. Check logs and process status:
65+
66+
```bash
67+
pgrep -f "turbo run dev" >/dev/null && echo "Dev servers running" || echo "Dev servers NOT running"
68+
tail -n 50 /tmp/dev.log # inspect server startup logs
69+
```
70+
71+
If servers are down, restart them: `bash .devcontainer/post-start.sh`.
72+
73+
### Path B: Host-based Setup
74+
75+
Manually boot the compose infrastructure:
5976

6077
```bash
6178
docker compose config --quiet # resolves WITHOUT secrets (verified)
6279
docker compose up -d postgres redis_exec redis_assessment redis_cache mailhog hatchet
6380
docker compose ps # everything Started/healthy?
6481
```
6582

66-
Config-derived continuation for app work: `.github/scripts/wait-for-infra.sh`, then `./util/_create_hatchet_token.sh`, then `pnpm run prisma:push`. Traefik path (`*.klicker.com`) additionally needs `/etc/hosts` entries, mkcert certs (`util/_create_ssl_certificates.sh`), and the `reverse_proxy_<os>` service.
83+
Continuation for app work: `.github/scripts/wait-for-infra.sh`, then `./util/_create_hatchet_token.sh`, then `pnpm run --filter @klicker-uzh/prisma prisma:push`. Traefik path (`*.klicker.com`) additionally needs `/etc/hosts` entries, mkcert certs (`util/_create_ssl_certificates.sh`), and the `reverse_proxy_<os>` service.
6784

6885
## Check 7 — Hatchet and workers (config-derived)
6986

.agents/skills/klicker-frontend-ui/SKILL.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ Conventions (design system, Tailwind v4, Apollo, i18n, CSP): [docs/frontend-conv
1717
- Every new interactive element gets `data-cy` (design-system prop form: `data={{ cy: '…' }}`); pick names consistent with the sibling elements.
1818
- Forms: Formik + Yup. Conditional classes: `twMerge`. Feature flags gate alone — never `flag && count > 0`.
1919
- No Next.js middleware for CSP/headers — that belongs at the proxy layer.
20-
3. **Verify in the browser — mandatory, not optional.** You are authorized to start the dev servers needed for this verification (and must clean up after with `./_down.sh`):
21-
- Bring-up per [docs/getting-started.md](../../../docs/getting-started.md) (localhost `dev:raw` path works without secrets); on failure → `klicker-environment-doctor`.
20+
3. **Verify in the browser — mandatory, not optional.** Depending on your environment path:
21+
- **Inside Devcontainer:** Dev servers auto-start in the background. No need to start/stop them. View logs via `tail -f /tmp/dev.log`.
22+
- **Host-based Setup:** You are authorized to start the dev servers needed for this verification, and must clean up after with `./_down.sh`. Bring-up per [docs/getting-started.md](../../../docs/getting-started.md) (localhost `dev:raw` path works without secrets).
23+
- On bring-up / server failure → `klicker-environment-doctor`.
2224
- Open the changed pages with `npx agent-browser` (never bare `agent-browser`), log in via **delegated** access with the AGENTS.md test credentials (not Edu-ID).
2325
- Capture before/after screenshots of every changed state (including error/empty states you touched); check both locales if strings changed.
2426
- Iterate on issues you see yourself; hand to the user for manual verification only after your own pass succeeds.

.devcontainer/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Dev container image for klicker-uzh (monorepo).
22
# glibc base (bookworm) for painless Prisma/esbuild/sharp native binaries — the
33
# prod images can stay Alpine, the dev image favors fewer surprises. (GOTCHAS #7)
4-
FROM node:20-bookworm-slim
4+
FROM node:24.16.0-bookworm-slim
55

66
ENV PNPM_HOME="/pnpm" \
77
PATH="/pnpm:$PATH" \
@@ -16,7 +16,7 @@ RUN apt-get update \
1616

1717
# Install pnpm with npm (not corepack — signature verification can fail on a
1818
# pinned Node). Mirror the repo's packageManager pin. (GOTCHAS #8)
19-
RUN npm install -g pnpm@10.15.0
19+
RUN npm install -g pnpm@11.5.0
2020

2121
# Keep the pnpm store inside the image, off the bind-mounted workspace. (GOTCHAS #9)
2222
RUN pnpm config set store-dir "$PNPM_HOME/.pnpm-store"

.devcontainer/README.md

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,12 @@ Hatchet, install + build + seed, `turbo dev`);
88
`:443` / `:5432` so many projects coexist with **zero host-port collisions**
99
(nothing is published on the host).
1010

11-
> **Scope:** the core apps — **backend, auth, frontend-pwa, frontend-manage,
12-
> frontend-control** (Phase 1) — plus **olat-api, response-api, and the two
13-
> Hatchet workers** (Phase 2 Tier 1). All run in the one `app` container; the
14-
> workers have no port/route. Still deferred: `lti` (Tier 2) and `chat`/LiteLLM
15-
> (Tier 3); `analytics`/`office-addin`/`docs` are skipped (no `dev` task / extra
16-
> toolchain). The legacy host-based stack (`docker-compose.yml`, `util/traefik`,
17-
> Infisical, `/etc/hosts` + mkcert `*.klicker.com`) is untouched.
11+
> **Scope:** all runnable apps — **backend, auth, frontend-pwa, frontend-manage,
12+
> frontend-control, olat-api, response-api, lti-service, chat**, and the **two
13+
> Hatchet workers**. All run in the one `app` container; the workers have no
14+
> port/route. Still skipped: `analytics` (Python), `office-addin`, and `docs`
15+
> (no `dev` task / extra toolchain). The legacy host-based stack (`docker-compose.yml`,
16+
> `util/traefik`, Infisical, `/etc/hosts` + mkcert `*.klicker.com`) is untouched.
1817
1918
## How to Run
2019

@@ -126,15 +125,15 @@ hatchet DB migrations finishing. If the API is down, check
126125

127126
## What's inside
128127

129-
| Service | Image | Purpose |
130-
| ----------------------------------- | ------------------------------------------- | ------------------------------------------------------ |
131-
| `app` | local `Dockerfile` (Node 20 + pnpm 10.15.0) | runs `turbo dev` for the core + Tier-1 apps + workers |
132-
| `postgres` | `postgres:15` | DB (klicker-prod + shadow/lti/qa/hatchet via init.sql) |
133-
| `redis_exec`/`_assessment`/`_cache` | `redis:7` | live-quiz exec / assessment / cache + pub/sub |
134-
| `mailhog` | `mailhog/mailhog` | dev SMTP sink |
135-
| `hatchet` | `hatchet-lite:v0.73.1` | workflow engine (gRPC :7077) |
136-
| `hatchet_token` | `hatchet-lite:v0.73.1` | one-shot: mint the client token |
137-
| `litellm` | `ghcr.io/berriai/litellm` | LLM proxy for chat (port 4000 intra-net) |
128+
| Service | Image | Purpose |
129+
| ----------------------------------- | ------------------------------------------ | ------------------------------------------------------ |
130+
| `app` | local `Dockerfile` (Node 24 + pnpm 11.5.0) | runs `turbo dev` for the core + Tier-1 apps + workers |
131+
| `postgres` | `postgres:15` | DB (klicker-prod + shadow/lti/qa/hatchet via init.sql) |
132+
| `redis_exec`/`_assessment`/`_cache` | `redis:7` | live-quiz exec / assessment / cache + pub/sub |
133+
| `mailhog` | `mailhog/mailhog` | dev SMTP sink |
134+
| `hatchet` | `hatchet-lite:v0.73.1` | workflow engine (gRPC :7077) |
135+
| `hatchet_token` | `hatchet-lite:v0.73.1` | one-shot: mint the client token |
136+
| `litellm` | `ghcr.io/berriai/litellm` | LLM proxy for chat (port 4000 intra-net) |
138137

139138
Environment lives in `devcontainer.env` (committed, dev-only). Lifecycle:
140139
`post-create.sh` (install + build packages + prisma reset/push/seed + token) then
@@ -145,7 +144,7 @@ Environment lives in `devcontainer.env` (committed, dev-only). Lifecycle:
145144
- `node_modules` is a named volume (pnpm hoists natives into the root
146145
`node_modules/.pnpm`, so one root volume covers the monorepo).
147146
- Reset the DB: `pnpm --filter @klicker-uzh/prisma exec prisma migrate reset --skip-seed --force`.
148-
- `response-api` + both workers run `tsx --watch --env-file=.env`; node 20 errors
147+
- `response-api` + both workers run `tsx --watch --env-file=.env`; node 24 errors
149148
if `.env` is missing, so `post-create` seeds an **empty** `.env` in each dir
150149
(the container env from `devcontainer.env` is what actually applies).
151150
- Tier 3 (`chat`) needs an upstream LLM key: set `UPSTREAM_OPENAI_API_KEY`.

.devcontainer/post-create.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ echo "[post-create] Seeding test data (lecturer/abcd, testuser1..50/abcdabcd)...
5858
retry 5 "prisma-data seed" pnpm --filter @klicker-uzh/prisma-data run seed:raw || exit 1
5959

6060
# response-api + both hatchet workers run `tsx --watch --env-file=.env`, and node
61-
# 20 HARD-ERRORS if .env is missing (it's --env-file, not --env-file-if-exists).
61+
# 24 HARD-ERRORS if .env is missing (it's --env-file, not --env-file-if-exists).
6262
# We keep no per-app .env in the container — every var comes from the inherited
6363
# container env (devcontainer.env). Seed an EMPTY .env in each dir so the flag
6464
# resolves; empty adds nothing, so the container env wins. (Copying .env.example

.tool-versions

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
node 20.19.4
2-
pnpm 9.8.0
1+
node 24.16.0
2+
pnpm 11.5.0

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ Prisma split-schema under `packages/prisma/src/prisma/schema/`. After editing a
123123

124124
### Self-contained devcontainer (recommended)
125125

126-
Clone-and-run via a self-contained devcontainer — no Infisical/Doppler, no EduID, no `/etc/hosts` edits. The container owns the whole stack (Node 20 + pnpm toolchain, Postgres, 3× Redis, MailHog, Hatchet) and runs **all core apps in ONE container** via `turbo dev`. Run pnpm/prisma/tests **inside the container**, never on the host.
126+
Clone-and-run via a self-contained devcontainer — no Infisical/Doppler, no EduID, no `/etc/hosts` edits. The container owns the whole stack (Node 24 + pnpm toolchain, Postgres, 3× Redis, MailHog, Hatchet) and runs **all core apps in ONE container** via `turbo dev`. Run pnpm/prisma/tests **inside the container**, never on the host.
127127

128128
```bash
129129
devpod up . # builds image, starts services, installs, builds, seeds, runs dev

docs/getting-started.md

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,42 @@ tags:
1414

1515
## Toolchain (verified 2026-07-07)
1616

17-
Pinned in root `package.json`: `volta.node = 24.16.0`, `volta.pnpm = 11.5.0`, `packageManager = pnpm@11.5.0`. Ignore the "Node.js 20" claim in [AGENTS.md](../AGENTS.md) — it is stale. `packages/word-cloud` pins `engines.node = 20` and prints a warning under Node 24; harmless today.
17+
Aligned to Node `24.16.0` and pnpm `11.5.0` across the entire workspace, including the self-contained devcontainer. Pinned in root `package.json`: `volta.node = 24.16.0`, `volta.pnpm = 11.5.0`, `packageManager = pnpm@11.5.0`.
1818

19-
## First-time setup (verified)
19+
## Onboarding Paths
20+
21+
You can set up the environment in two ways:
22+
23+
### Path A: Self-contained Devcontainer (Recommended)
24+
25+
Clone-and-run via a self-contained devcontainer — no Infisical, no external EduID, no `/etc/hosts` edits needed. The container runs all core apps via `turbo dev` and houses all dependencies (Postgres, Redis, MailHog, Hatchet).
26+
27+
1. **Start the container:**
28+
```bash
29+
devpod up . # builds image, starts services, installs, builds, seeds, runs dev
30+
devpod ssh klicker-uzh # shell inside the container
31+
```
32+
2. **Accessing the apps:**
33+
- **Mode 1 (Plain localhost - default):** Exposed directly on host ports: Student PWA at `http://localhost:3001`, Lecturer UI at `http://localhost:3002` (login: `lecturer`/`abcd`).
34+
- **Mode 2 (devrouter overlay):** Routes local traffic over HTTPS: `https://manage.klicker.localhost`. Requires:
35+
1. Edit `.devcontainer/devcontainer.json` to include the devrouter overlay:
36+
```json
37+
"dockerComposeFile": ["docker-compose.yml", "docker-compose.devrouter.yml"]
38+
```
39+
2. Start the devcontainer (`devpod up .`).
40+
3. Install `devrouter` on host and register the application routes:
41+
```bash
42+
for a in api auth pwa manage control olat-api response-api lti chat db; do dev app run "$a"; done
43+
```
44+
3. **Logs:** The dev servers auto-start inside the container. View logs via `tail -f /tmp/dev.log`.
45+
46+
### Path B: Host-based Setup (Legacy)
47+
48+
Runs all services on your host machine. Needs Traefik (`*.klicker.com` reverse proxy), mkcert, `/etc/hosts` configurations, and Infisical for secret injection.
2049

2150
```bash
22-
pnpm --version # must print 11.x — see lead paragraph
23-
pnpm install # ~20s cold; peer warnings in apps/docs + packages/prisma are pre-existing
51+
pnpm --version # must print 11.x
52+
pnpm install # ~20s cold; peer warnings are pre-existing
2453
pnpm run build # 21 turbo tasks, ~1.5min; needs NO secrets
2554
pnpm run check # typecheck — only passes AFTER build (generated artifacts)
2655
```

packages/word-cloud/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"test": "vitest run"
3636
},
3737
"engines": {
38-
"node": "=20"
38+
"node": "=24"
3939
},
4040
"volta": {
4141
"extends": "../../package.json"

0 commit comments

Comments
 (0)