Add Doris Schoolhouse and clean pending homelab changes
This commit is contained in:
204
home/doris-schoolhouse/README.md
Normal file
204
home/doris-schoolhouse/README.md
Normal file
@@ -0,0 +1,204 @@
|
||||
# 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
|
||||
|
||||
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:
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```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.
|
||||
|
||||
## Future 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
|
||||
```
|
||||
|
||||
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/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
|
||||
Reference in New Issue
Block a user