200 lines
5.8 KiB
Markdown
200 lines
5.8 KiB
Markdown
# 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 + `ffmpeg` for recording conversion
|
|
|
|
## Current state
|
|
|
|
The app is live on NOMAD at `/opt/doris-schoolhouse` and uses shared Postgres in production.
|
|
|
|
For local iteration, the source tree still supports a JSON-backed mode:
|
|
|
|
- default state dir: `/data/state`
|
|
- default upload temp dir: `/data/uploads`
|
|
|
|
For local host-side testing, override with env vars such as:
|
|
|
|
```bash
|
|
export SCHOOLHOUSE_STATE_DIR=/tmp/doris-schoolhouse-state
|
|
export UPLOAD_TMP_DIR=/tmp/doris-schoolhouse-uploads
|
|
```
|
|
|
|
Production runtime uses 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.
|
|
|
|
Repo contents still include:
|
|
- route handlers and templates
|
|
- schema/bootstrap helpers
|
|
- compose/env examples
|
|
- D2L / Paperless / n8n integration code
|
|
|
|
## Layout
|
|
|
|
```text
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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`
|
|
- `ffmpeg`
|
|
- `curl` for healthchecks
|
|
|
|
So even if the host is missing `ffmpeg`, the containerized runtime can still do WAV → MP3 conversion.
|
|
|
|
## Deploy shape
|
|
|
|
Expected live deploy flow on NOMAD:
|
|
|
|
```bash
|
|
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
|
|
```
|
|
|
|
That flow is the reference for refreshing the live runtime from repo source.
|
|
|
|
|
|
## Live integration notes
|
|
|
|
Current verified live behavior:
|
|
- `https://n8n.paccoco.com/webhook/school/intake/upload` accepts Doris Schoolhouse multipart assignment uploads and returned a successful live smoke-test response on 2026-05-15.
|
|
- `https://n8n.paccoco.com/webhook/class/upload` now 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/transcriptions` succeeded with a tiny MP3.
|
|
- Direct LiteLLM testing against `http://10.5.1.6:4000/v1/chat/completions` now succeeds for model `medium` after 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
|