Files
Schulcloud-MCP/local-instance/env/shared.env
MechaCat02 a3aded110c Add a local Schulcloud instance modelled on the live target
A Docker Compose stack that runs the deployed images
(quay.io/schulcloudverbund/*, thr theme, tag 33.40 — the versions
schulcloud-thueringen.de reports) rather than a rebuild of main, so what we
develop against is the deployed artefact. It exists to produce the states we
can otherwise only observe read-only: log in as the teacher, grade, then read
it back the way the MCP server does.

Faithful where it matters and honest where it isn't:

- Feature flags in env/api.env are a replay of GET /api/v3/config/public from
  the live instance, not a hand-picked set; instance identity mirrors the thr
  group_vars from dof_app_deploy.
- The proxy is generated from the deployment's own ingress table
  (scripts/gen-proxy-conf.py) so the legacy-client / SPA / API path split
  matches production; getting it wrong tests a different application.
- Valkey runs in `single` mode so the JWT whitelist expires sessions the way
  production does, rather than the in-memory shortcut that hides it.
- No external OAuth / Schulportal login (excluded by request and not
  reproducible locally), no BigBlueButton; each divergence is marked at the
  line it affects. Everything binds to 127.0.0.1 and uses the upstream dev
  credentials, which are public.

Profiles keep the heavy pieces opt-in: `tools` adds Etherpad/H5P/tldraw/
Collabora, `av` adds ClamAV, `preview` adds thumbnailing.

seed.sh loads the upstream demo school (the same call the deployment's init job
makes) and registers MinIO as the legacy storage provider, which has no seed
data on purpose. The demo data already contains the grading states that are
hard to obtain from the real account — a feedback-only grade and a 100% one —
which is what surfaced the past-due submitted-text scrape gap.

One config finding baked in: file-storage and h5p validate a token's
issuer/audience against JWT_DOMAIN (default "localhost"), while the API stamps
SC_DOMAIN; without keeping them equal, the homework page's file lookups 401.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-13 14:17:30 +02:00

47 lines
1.8 KiB
Bash

# Shared by every Schulcloud app in the stack.
# Everything in this directory is local-only and deliberately non-secret.
NODE_ENV=production
NO_COLOR=true
TZ=Europe/Berlin
# --- identity of this instance -------------------------------------------
# Mirrors dof_app_deploy/ansible/group_vars/thr/instance_cfg.yml so the local
# instance looks and behaves like schulcloud-thueringen.de.
SC_THEME=thr
SC_SHORTNAME=thr
SC_TITLE=Thüringer Schulcloud
SC_PRODUCTNAME=Thüringer Schulcloud
SC_NAV_TITLE=Thüringer Schulcloud
SC_CONTACT_EMAIL=schulcloud-support@thillm.de
ACCESSIBILITY_REPORT_EMAIL=institut@thillm.de
# The single origin the browser talks to (the nginx in ./proxy).
SC_DOMAIN=localhost:4400
HOST=http://localhost:4400
# The API stamps SC_DOMAIN into every JWT as both issuer and audience. The
# satellite services (file-storage, h5p) validate iss/aud against JWT_DOMAIN,
# which defaults to a bare "localhost" — so without this they reject every
# token the API issued and the homework page's file lookups 401. Keep the two
# in lockstep.
JWT_DOMAIN=localhost:4400
PUBLIC_BACKEND_URL=http://localhost:4400/api
CTL_TOOLS_BACKEND_URL=http://localhost:4400/api
# --- infrastructure ------------------------------------------------------
DB_URL=mongodb://mongo:27017/schulcloud
DB_ENSURE_INDEXES=true
RABBITMQ_URI=amqp://guest:guest@rabbitmq:5672
# The JWT whitelist. `single` reproduces production: every authenticated
# request re-sets a Valkey key with a JWT_TIMEOUT_SECONDS TTL, and losing that
# key logs the session out. `in-memory` would hide that behaviour entirely,
# which is exactly the behaviour this instance exists to test.
SESSION_VALKEY__MODE=single
SESSION_VALKEY__URI=redis://valkey:6379
JWT_TIMEOUT_SECONDS=7200
JWT_SHOW_TIMEOUT_WARNING_SECONDS=3600
AES_KEY=randomStringWithAtLeast16Chars;
S3_KEY=abcdefghijklmnop