Many teachers never use topics or boards; their material sits in the course's file area, and the tools answered "0 files" for courses holding dozens of worksheets — 21 of 26 courses on the live account. Persönliche, Kurs-, Team- and Geteilte Dateien live in the legacy file store, not in files-storage, and its service is not in the public ingress. The only way in is the legacy client: HTML listings, and GET /files/signedurl for a pre-signed download. core/legacy-files.ts turns that into one path tree — /my, /courses/<course>, /teams/<team>, /shared — resolving names that contain "/", ids anywhere in a path, and wrong or ambiguous names with a message saying what is there. A listing that does not parse throws; it never reads as an empty folder. Some of the legacy client's GET routes write (GET /files/share/ mints a share token), so getFileManagerPage allows only the listing routes, by pattern. Signed URLs are fetched with no credentials and must be https. - MCP: fs_list, fs_tree, fs_find and fs_read; get_course lists course files. - CLI: schulcloud fs ls, tree, find and get, recursive and resumable. - API: /api/fs/list, tree, find and file. - Index: the crawl walks the file manager (INDEX_FILE_MANAGER, on by default), so search covers the text inside those files and sync mirrors them under <course>/Kurs-Dateien. The local instance gains a fixture for all four areas. It needed a loopback, so signed URLs open from the host, and a pre-created bucket, since MinIO does not implement PutBucketCors. 135 tests. Smoke 55/55 live; 57/57 and 55/55 on the local instance. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
84 lines
3.8 KiB
Plaintext
84 lines
3.8 KiB
Plaintext
# ---------------------------------------------------------------------------
|
|
# Schulcloud instance
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Base URL of the instance, no trailing slash.
|
|
TSC_URL=https://schulcloud-thueringen.de
|
|
|
|
# The value of the `jwt` cookie from a logged-in browser session.
|
|
# The 30-day `exp` is only a ceiling; the real limit is a 2-hour sliding session
|
|
# TTL that the built-in keepalive holds open. IMPORTANT: close the Schulportal
|
|
# window after copying this — an open tab shares the session and its auto-logout
|
|
# will revoke this token ~2h after login. See docs/AUTH.md.
|
|
TSC_JWT_COOKIE=
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# This MCP server
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Shared secret callers must present as `Authorization: Bearer <token>`.
|
|
# REQUIRED for the public deployment — without it the endpoint is open to
|
|
# anyone who finds the hostname. Generate one with:
|
|
# openssl rand -hex 32
|
|
MCP_AUTH_TOKEN=
|
|
|
|
# Listen address inside the container. Leave as-is when running behind Caddy.
|
|
PORT=8080
|
|
BIND_HOST=0.0.0.0
|
|
|
|
# Local Docker only: the loopback port docker-compose.override.yml publishes the
|
|
# container on. Default 8080; change it when that port is already taken.
|
|
# MCP_HOST_PORT=8080
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Index and file mirror (optional — without these the server runs live-only:
|
|
# search crawls on every call, and the CLI's /api surface is unavailable)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Postgres for crawl generations, full-text search and the file mirror index.
|
|
# On the Pi, point this at the existing instance with its own database and user.
|
|
DATABASE_URL=postgresql://schulcloud:schulcloud@postgres:5432/schulcloud
|
|
|
|
# Where mirrored file bytes are stored. Needs to be writable by the container.
|
|
# MIRROR_DIR=/data/mirror
|
|
|
|
# Files larger than this are indexed as metadata but not mirrored; they are
|
|
# still downloadable, proxied live. Default 64 MiB.
|
|
# MIRROR_MAX_BYTES=67108864
|
|
|
|
# Also index personal files ("Meine Dateien") and submitted / returned work,
|
|
# including teacher grade comments. This is what makes "what did the teacher
|
|
# say about X" searchable and lets what_changed report a re-grade. Costs roughly
|
|
# three extra requests per task on a full crawl, so it is off by default.
|
|
# INDEX_PERSONAL_FILES=false
|
|
|
|
# Also walk the file manager ("Dateien") when crawling: Kurs-Dateien for every
|
|
# course, plus Persönliche, Team- and Geteilte Dateien on a full crawl. Many
|
|
# teachers keep their material only there, so this is on by default. One page
|
|
# load per folder — about 160 on a 26-course account.
|
|
# INDEX_FILE_MANAGER=true
|
|
|
|
# How often to re-crawl on a timer, in ms. Default 21600000 (6h). 0 = on demand
|
|
# only. A re-crawl of unchanged content downloads nothing, because Schulcloud
|
|
# file records are immutable.
|
|
# CRAWL_INTERVAL_MS=21600000
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Limits (optional — sensible defaults are built in)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Largest file download_file will pull, in bytes. Default 25 MiB.
|
|
# Videos in Schulcloud routinely exceed this; they are not extractable anyway.
|
|
# MAX_DOWNLOAD_BYTES=26214400
|
|
|
|
# Characters of extracted text returned before truncation. Default 120000.
|
|
# MAX_EXTRACTED_CHARS=120000
|
|
|
|
# Per-request timeout against the Schulcloud API, in ms. Default 30000.
|
|
# REQUEST_TIMEOUT_MS=30000
|
|
|
|
# How often to call refresh-session to hold the session open, in ms. Default
|
|
# 1800000 (30 min). Must stay well under the instance's JWT_TIMEOUT_SECONDS —
|
|
# 7200s here, readable from GET /api/v3/config/public. Set to 0 to disable.
|
|
# KEEPALIVE_INTERVAL_MS=1800000
|