5.9 KiB
Doris Schoolhouse
Desktop-first local web app for school intake, recordings, D2L sync, and Paperless linkage.
Purpose
This app gives John a fast local UI to:
- upload assignment turn-ins
- upload class recordings
- confirm suggested metadata
- track assignment status through grading
- sync classes/assignments/grades/comments from D2L
- archive submissions/transcripts/summaries in Paperless
Source vs runtime
- Repo source:
home/doris-schoolhouse - Expected live NOMAD runtime:
/opt/doris-schoolhouse
Do not run production from an agent workspace.
Stack
- FastAPI
- Jinja2 templates
- shared Postgres
- Pangolin network
- existing Paperless and n8n school workflows
- container build now includes Python deps +
ffmpegfor recording conversion
Current state
This is an implementation scaffold with:
Current local persistence
Until the full shared-Postgres integration is wired, the scaffold uses JSON state files for fast local iteration:
- default state dir:
/data/state - default upload temp dir:
/data/uploads
For local host-side testing, override with env vars such as:
export SCHOOLHOUSE_STATE_DIR=/tmp/doris-schoolhouse-state
export UPLOAD_TMP_DIR=/tmp/doris-schoolhouse-uploads
Production target remains shared Postgres plus Paperless/n8n integration.
SCHOOLHOUSE_STORAGE_BACKEND=auto prefers Postgres when psycopg and a PostgreSQL DSN are available, and falls back to JSON state for local iteration.
- route stubs
- templates
- schema draft
- compose/env examples
- D2L / Paperless integration placeholders
It is not deployed yet.
Layout
home/doris-schoolhouse/
├── .env.example
├── docker-compose.yaml
├── requirements.txt
└── app/
├── main.py
├── config.py
├── models.py
├── db/schema.sql
├── routes/
├── services/
├── static/
└── templates/
Environment and integration helpers
Useful helpers now included:
bin/check-env.sh
bin/apply-postgres-schema.sh
bin/test-assignment-handoff.sh <file> <class_name> [assignment_name]
bin/test-recording-handoff.sh <file> <class_name>
These are safe prep helpers. The handoff scripts are dry-run previews; they print the exact curl commands rather than firing them automatically.
Helper scripts
Local iteration helpers:
bin/bootstrap-local.sh
bin/run-local.sh
bin/process-recording.sh <recording_id>
These default to the JSON backend and /tmp paths unless you override the env vars.
Bootstrap local state quickly
For local iteration without live Postgres:
cd /home/fizzlepoof/repos/truenas-stacks/home/doris-schoolhouse
export SCHOOLHOUSE_STORAGE_BACKEND=json
export SCHOOLHOUSE_STATE_DIR=/tmp/doris-schoolhouse-state
export UPLOAD_TMP_DIR=/tmp/doris-schoolhouse-uploads
PYTHONPATH=. python3 app/scripts/bootstrap_state.py
That seeds local state from the latest D2L snapshot.
Recording worker helper
There is now a local worker entrypoint for WAV → MP3 processing:
cd /home/fizzlepoof/repos/truenas-stacks/home/doris-schoolhouse
export SCHOOLHOUSE_STORAGE_BACKEND=json
export SCHOOLHOUSE_STATE_DIR=/tmp/doris-schoolhouse-state
export UPLOAD_TMP_DIR=/tmp/doris-schoolhouse-uploads
PYTHONPATH=. python3 app/scripts/process_recording.py <recording_id>
If ffmpeg is not installed, the worker records a clean blocked result with the exact conversion command it wanted to run.
Local validation
cd /home/fizzlepoof/repos/truenas-stacks/home/doris-schoolhouse
python3 -m py_compile app/main.py app/config.py app/models.py app/routes/*.py app/services/*.py
python3 - <<'PY'
import yaml
from pathlib import Path
print(yaml.safe_load(Path('docker-compose.yaml').read_text())['services'].keys())
PY
Container build
The source now includes a Dockerfile so the app can run with its own dependencies instead of relying on the host.
That image includes:
- Python dependencies from
requirements.txt ffmpegcurlfor healthchecks
So even if the host is missing ffmpeg, the containerized runtime can still do WAV → MP3 conversion.
Future deploy shape
Expected live deploy flow on NOMAD:
sudo mkdir -p /opt/doris-schoolhouse/data
sudo rsync -a --delete --exclude '.env' --exclude 'data/' /home/fizzlepoof/repos/truenas-stacks/home/doris-schoolhouse/ /opt/doris-schoolhouse/
cd /opt/doris-schoolhouse
sudo cp .env.nomad.example .env
docker compose --env-file .env config
docker compose --env-file .env up -d --build
Not doing that yet. No live deployment should happen without explicit rollout work.
Live integration notes
Current verified live behavior:
https://n8n.paccoco.com/webhook/school/intake/uploadaccepts Doris Schoolhouse multipart assignment uploads and returned a successful live smoke-test response on 2026-05-15.https://n8n.paccoco.com/webhook/class/uploadnow succeeds in live smoke testing after upstream workflow and LiteLLM fixes on 2026-05-15.- Direct Whisper testing against
http://10.5.1.16:8786/v1/audio/transcriptionssucceeded with a tiny MP3. - Direct LiteLLM testing against
http://10.5.1.6:4000/v1/chat/completionsnow succeeds for modelmediumafter the PD route fix.
The app now captures webhook HTTP failures as structured responses instead of crashing blindly.
NOMAD-specific deployment notes
On NOMAD, Schoolhouse should run as a standalone service from /opt/doris-schoolhouse.
Unlike PD stacks, this host does not currently use the PD Docker external networks for Pangolin or shared databases. The practical deploy model here is:
- publish host port
8091 - point Pangolin/Newt at that host port
- reach shared Postgres on PD over
10.5.1.6:5432
Use .env.nomad.example as the starting point for the live runtime.
Deployment references
DEPLOYMENT.md— clean NOMAD rollout notes.env.nomad.example— compose-oriented runtime example for NOMAD