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>
This commit is contained in:
MechaCat02
2026-09-13 14:17:30 +02:00
parent 290b352b07
commit a3aded110c
16 changed files with 1598 additions and 0 deletions

95
local-instance/env/api.env vendored Normal file
View File

@@ -0,0 +1,95 @@
# The schulcloud-server API app (apps/server.app).
#
# The FEATURE_* block below is not hand-picked: it is a replay of
# GET /api/v3/config/public from the live schulcloud-thueringen.de, so the local
# instance exposes the same surface to students that the real one does.
# Regenerate with ./scripts/sync-feature-flags.sh.
PORT=3030
# Internal service addresses (compose DNS), not the browser-facing origin.
API_HOST=http://api:3030/api
FILES_STORAGE__SERVICE_BASE_URL=http://file-storage:4444
LICENSE_SUMMARY_URL=http://api:3030/api/licenses/summary
ROOM_MEMBER_INFO_URL=http://api:3030/api/rooms/member-info
ALERT_STATUS_URL=https://status.schulcloud-thueringen.de/
CALENDAR_SERVICE_ENABLED=false
NEST_LOG_LEVEL=info
# Etherpad (see ../etherpad/APIKEY.txt)
ETHERPAD__URI=http://etherpad:9001/api/1
ETHERPAD__PAD_URI=http://localhost:4400/etherpad/p
ETHERPAD__API_KEY=381d67e6347d235ac9446da3ea10a82efd6f8ae09fa2e90efeda80f82feeb4fd
# tldraw + admin API
TLDRAW__WEBSOCKET_URL=ws://localhost:4400/tldraw-server
TLDRAW_ADMIN_API_CLIENT__BASE_URL=http://tldraw-server:3349
TLDRAW_ADMIN_API_CLIENT__API_KEY=tldraw-admin-key
ADMIN_API__ALLOWED_API_KEYS=thisisasupersecureapikeythatisabsolutelysave
# Teacher/student visibility, as configured for thr.
TEACHER_STUDENT_VISIBILITY__IS_CONFIGURABLE=false
TEACHER_STUDENT_VISIBILITY__IS_ENABLED_BY_DEFAULT=true
TEACHER_STUDENT_VISIBILITY__IS_VISIBLE=false
# --- feature flags, mirrored from the live instance ----------------------
FEATURE_ADMINISTRATE_ROOMS_ENABLED=true
FEATURE_AI_TUTOR_ENABLED=false
FEATURE_ALLOW_INSECURE_LDAP_URL_ENABLED=false
FEATURE_BOARD_LAYOUT_ENABLED=true
FEATURE_BOARD_READERS_CAN_EDIT_TOGGLE=true
FEATURE_COLUMN_BOARD_COLLABORATIVE_TEXT_EDITOR_ENABLED=true
FEATURE_COLUMN_BOARD_COLLABORA_ENABLED=true
FEATURE_COLUMN_BOARD_ENABLED=true
FEATURE_COLUMN_BOARD_EXTERNAL_TOOLS_ENABLED=true
FEATURE_COLUMN_BOARD_FILE_FOLDER_ENABLED=true
FEATURE_COLUMN_BOARD_H5P_ENABLED=true
FEATURE_COLUMN_BOARD_LINK_ELEMENT_ENABLED=true
FEATURE_COLUMN_BOARD_SHARE=true
FEATURE_COLUMN_BOARD_SOCKET_ENABLED=true
# local override (live: true) — needs infrastructure we do not run
FEATURE_COLUMN_BOARD_VIDEOCONFERENCE_ENABLED=false
FEATURE_COMMON_CARTRIDGE_COURSE_EXPORT_ENABLED=false
FEATURE_COMMON_CARTRIDGE_COURSE_IMPORT_ENABLED=false
FEATURE_COMMON_CARTRIDGE_COURSE_IMPORT_MAX_FILE_SIZE=1073741824
# local override (live: true) — otherwise every seeded user hits a consent wall
FEATURE_CONSENT_NECESSARY=false
FEATURE_COPY_SERVICE_ENABLED=true
FEATURE_COURSE_SHARE=true
FEATURE_CTL_TOOLS_COPY_ENABLED=true
FEATURE_ENABLE_LDAP_SYNC_DURING_MIGRATION=false
FEATURE_EXTERNAL_PERSON_REGISTRATION_ENABLED=false
FEATURE_EXTERNAL_SYSTEM_LOGOUT_ENABLED=false
FEATURE_FWU_CONTENT_ENABLED=false
FEATURE_LESSON_SHARE=true
FEATURE_LOGIN_LINK_ENABLED=false
FEATURE_MEDIA_SHELF_ENABLED=true
FEATURE_NOTIFICATIONS_ENABLED=false
FEATURE_PREFERRED_CTL_TOOLS_ENABLED=true
FEATURE_ROOM_ADD_EXTERNAL_PERSONS_ENABLED=false
FEATURE_ROOM_COPY_ENABLED=true
FEATURE_ROOM_LINK_INVITATION_EXTERNAL_PERSONS_ENABLED=false
FEATURE_ROOM_REGISTER_EXTERNAL_PERSONS_ENABLED=false
FEATURE_ROOM_SHARE=true
FEATURE_SCHOOL_POLICY_ENABLED_NEW=true
FEATURE_SCHOOL_TERMS_OF_USE_ENABLED=true
FEATURE_SCHULCONNEX_COURSE_SYNC_ENABLED=false
FEATURE_SCHULCONNEX_MEDIA_LICENSE_ENABLED=false
FEATURE_SHOW_MIGRATION_WIZARD=false
FEATURE_SHOW_OUTDATED_USERS=false
FEATURE_TASK_SHARE=true
FEATURE_TEAMS_ENABLED=true
FEATURE_TEAM_CREATE_ROOM_ENABLED=true
FEATURE_TLDRAW_ENABLED=true
FEATURE_USER_LOGIN_MIGRATION_ENABLED=false
FEATURE_USER_MIGRATION_ENABLED=false
# local override (live: true) — needs infrastructure we do not run
FEATURE_VIDEOCONFERENCE_ENABLED=false
FEATURE_VIDIS_MEDIA_ACTIVATIONS_ENABLED=false
# --- required-but-unused endpoints ---------------------------------------
# The config classes validate these as present strings even when the feature
# is off, so they get a placeholder rather than a real service. Hydra is the
# OAuth2 provider behind external tool launches; we do not run it.
HYDRA_URI=http://hydra.invalid:4444

31
local-instance/env/client.env vendored Normal file
View File

@@ -0,0 +1,31 @@
# schulcloud-client, the legacy Express/Handlebars UI. Still serves "/" and
# large parts of the course view, so it is not optional.
PORT=3100
# HOST is what the client puts into redirects, so it must be the browser-facing
# origin (the proxy), not this container's own address.
HOST=http://localhost:4400
API_HOST=http://api:3030/api
PUBLIC_BACKEND_URL=http://localhost:4400/api
FILES_STORAGE__SERVICE_BASE_URL=http://file-storage:4444
ETHERPAD__PAD_URI=http://localhost:4400/etherpad/p
ETHERPAD__PAD_PATH=/etherpad/p
ETHERPAD__DOMAIN=localhost
FEATURE_ETHERPAD_ENABLED=true
SESSION_VALKEY__MODE=single
SESSION_VALKEY__URI=redis://valkey:6379
SESSION_COOKIE_SAME_SITE=lax
# The proxy terminates plain HTTP locally; without this the client marks the
# jwt cookie Secure and the browser silently drops it.
COOKIE__SECURE=false
COOKIE__SAME_SITE=lax
COOKIE__HTTP_ONLY=false
# Signs the session cookie. Local-only value; the app refuses to start without it.
COOKIE_SECRET=local-instance-cookie-secret-not-a-real-secret
LOG_LEVEL=info

11
local-instance/env/etherpad.env vendored Normal file
View File

@@ -0,0 +1,11 @@
# Etherpad, the collaborative text editor element on column boards.
# Settings taken from docs/topics/etherpad/Local setup.md.
REQUIRE_SESSION=true
PAD_OPTIONS_SHOW_CHAT=true
DISABLE_IP_LOGGING=true
DEFAULT_PAD_TEXT=Schreib etwas!
DB_TYPE=mongodb
DB_URL=mongodb://mongo:27017/etherpad
AUTHENTICATION_METHOD=apikey
TRUST_PROXY=true

30
local-instance/env/file-storage.env vendored Normal file
View File

@@ -0,0 +1,30 @@
# file-storage service (repo hpi-schul-cloud/file-storage), the /api/v3/file/* API.
FILES_STORAGE__SERVICE_BASE_URL=http://file-storage:4444
FILE_STORAGE_SERVICE_URL=http://file-storage:4444
AUTHORIZATION_API_URL=http://api:3030/api/v3
FILES_STORAGE_S3_ENDPOINT=http://minio:9000/
FILES_STORAGE_S3_BUCKET=schulcloud
FILES_STORAGE_S3_REGION=eu-central-1
FILES_STORAGE_S3_ACCESS_KEY_ID=miniouser
FILES_STORAGE_S3_SECRET_ACCESS_KEY=miniouser
# Antivirus. Off by default: ClamAV wants ~1.5 GB of RAM for its signature DB.
# Turn it on together with the `av` profile — with the scanner absent but the
# check enabled, every upload stays stuck in securityCheck.status=pending and
# can never be downloaded.
ENABLE_FILE_SECURITY_CHECK=false
ANTIVIRUS_SERVICE_HOSTNAME=clamav
ANTIVIRUS_SERVICE_PORT=3310
FILES_STORAGE_USE_STREAM_TO_ANTIVIRUS=false
PREVIEW_PRODUCER_INCOMING_REQUEST_TIMEOUT=10000
# Collabora must be reachable by the *browser*, so this one is a host URL.
COLLABORA_ONLINE_URL=http://localhost:9980
WOPI_URL=http://localhost:4400/api/v3/wopi/files
WOPI_POST_MESSAGE_ORIGIN=http://localhost:4400
FEATURE_COLUMN_BOARD_COLLABORA_ENABLED=true
LOGGER_LOG_LEVEL=info

18
local-instance/env/h5p.env vendored Normal file
View File

@@ -0,0 +1,18 @@
# h5p-server: the h5p-editor app plus the one-shot library-management job.
H5P_EDITOR__S3_ENDPOINT=http://minio:9000
H5P_EDITOR__S3_REGION=eu-central-1
H5P_EDITOR__S3_ACCESS_KEY_ID=miniouser
H5P_EDITOR__S3_SECRET_ACCESS_KEY=miniouser
H5P_EDITOR__S3_BUCKET_CONTENT=h5p-content-bucket
H5P_EDITOR__S3_BUCKET_LIBRARIES=h5p-library-bucket
H5P_EDITOR__LIBRARIES_S3_ACCESS_KEY_ID=miniouser
H5P_EDITOR__LIBRARIES_S3_SECRET_ACCESS_KEY=miniouser
# A short list keeps the one-off library install to a couple of minutes; the
# upstream default installs ~40 libraries and takes far longer.
H5P_EDITOR__LIBRARY_LIST=H5P.ArithmeticQuiz,H5P.Chart,H5P.MultiChoice,H5P.Blanks
API_HOST=http://api:3030/api
CORE_INCOMING_REQUEST_TIMEOUT_MS=8000
LOGGER_LOG_LEVEL=info

5
local-instance/env/jwt.env vendored Normal file
View File

@@ -0,0 +1,5 @@
# Development RSA keypair, copied verbatim from schulcloud-server/.env.development
# (upstream, public, committed in their repo). It exists so every local service
# validates the same tokens. NEVER use these keys anywhere reachable from outside.
JWT_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n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\n-----END RSA PRIVATE KEY-----\n"
JWT_PUBLIC_KEY="-----BEGIN RSA PUBLIC KEY-----\nMIICCgKCAgEA0/oW2sIZWvVt0AEgQ8PS80/udJzfWXu6t2QWjUcQA2THGvDSXXMH\n6YMMY2czyBgf6L7hHV/9p1Trfpe7YgxYhOoGsxhXG1keAYQ4+mdveaUAa3uiACdE\nodsB0OFjVUdgOHCyUIXFfhSsp2p2tmZeFi/bE2v/05kYO+ExgQuzUDbB8bCr1sc7\ngMS/2dC2iE/BVw/I0F14oZkZn0fshojg4qoaLbLVKB7Iw53IXF2878zXp81Jdnnv\nHdwVbGWqoII6sHZFQs8ob5S/WGMl4QnBHN98x0KmORUFyTv5kK4cdcC8LJ1HpoVW\nNC6js84iF9yFRhYXY2RHqh7BwaZZ4XZym/MetTdQTBDaSvhXe0A3WdahNG+DGrie\nhd6doWk98Adb49InaodH64ZRkurxiX61GEtzjMRq9EfGS5R/IfcWyPQbiir6ymKX\nfOUtywRjcm3FZzmT7j3c0UHzQVEH0NBfTMj+QKz5NILNP230j0DcjNImDbHHcVH1\nquSb6e0WXjKANTkf4gaTOw7jdQDFw0Ou3aEmwPg+Xk1cwCwSHOOmPSSssZwgjpzG\nodPO3vsMGfRYTwcGbzgdQFFj0qTmvgnM5MHtEy8qCyvM4OsAPnE0zQWn48p7PVdJ\nm6j0H/1BYgVw1KxecIVk/HryoTOkgS9lhLu8iEIyrpAlWascIK7Uw58CAwEAAQ==\n-----END RSA PUBLIC KEY-----\n"

10
local-instance/env/nuxt.env vendored Normal file
View File

@@ -0,0 +1,10 @@
# schulcloud-frontend (nuxt-client). The image is an nginx serving the built
# SPA; these values are substituted into its config template at container start
# (see nuxt-client/config/docker/nginx.conf.template).
PUBLIC_BACKEND_URL=http://localhost:4400/api
LEGACY_CLIENT_URL=http://client:3100
COLLABORA_OFFICE_URL=http://localhost:9980
LICENSE_SUMMARY_URL_FOR_CSP=http://localhost:4400
H5P_SCRIPT_SRC_URLS=http://localhost:4400
H5P_IMG_SRC_URLS=http://localhost:4400

46
local-instance/env/shared.env vendored Normal file
View File

@@ -0,0 +1,46 @@
# 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

17
local-instance/env/tldraw.env vendored Normal file
View File

@@ -0,0 +1,17 @@
# tldraw-server: the whiteboard element on column boards. Server + worker.
REDIS_URL=redis://valkey:6379
AUTHORIZATION_API_HOST=http://api:3030
S3_ACCESS_KEY=miniouser
S3_SECRET_KEY=miniouser
S3_BUCKET=ydocs
S3_ENDPOINT=minio
S3_PORT=9000
S3_SSL=false
FEATURE_TLDRAW_ENABLED=true
TLDRAW_WEBSOCKET_URL=ws://localhost:4400/tldraw-server
X_API_ALLOWED_KEYS=tldraw-admin-key
NOT_AUTHENTICATED_REDIRECT_URL=http://localhost:4400/login
LOGGER_LOG_LEVEL=info