# PedsHub — Admin Guide ## Deployment ```bash # Start everything docker compose up -d # Rebuild after code changes (restart alone won't pick up changes) docker compose build --no-cache backend celery frontend docker compose up -d backend celery frontend --force-recreate # View logs docker compose logs backend --tail=50 docker compose logs celery --tail=50 docker compose logs frontend --tail=50 ``` ## CLI Management Tool All commands run inside the backend container: ```bash docker compose exec backend python -m app.cli ``` ### User Management ```bash # List all users docker compose exec backend python -m app.cli list-users # Reset a user's password docker compose exec backend python -m app.cli reset-password user@example.com newpassword # Change user role (admin / moderator / user) docker compose exec backend python -m app.cli set-role user@example.com moderator # Force-verify a user's email (skip email confirmation) docker compose exec backend python -m app.cli verify-email user@example.com # Delete a user (interactive confirmation) docker compose exec backend python -m app.cli delete-user user@example.com # Export users to CSV docker compose exec backend python -m app.cli export-users > users.csv ``` ### Documents ```bash # List all documents with status docker compose exec backend python -m app.cli list-docs # Fix documents stuck in 'processing' (>30 min) docker compose exec backend python -m app.cli fix-stuck-docs # Requeue a specific document for processing docker compose exec backend python -m app.cli reprocess-doc 32 ``` **Why documents get stuck:** If the Celery worker restarts while processing a PDF, the task is lost and the document stays at "processing" forever. `fix-stuck-docs` resets these to "ready" so they can be reprocessed. ### Courses & Quizzes ```bash # List all courses docker compose exec backend python -m app.cli list-courses # List quizzes (active only) docker compose exec backend python -m app.cli list-quizzes # List all quizzes including deleted docker compose exec backend python -m app.cli list-quizzes --all ``` ### Maintenance ```bash # Platform statistics docker compose exec backend python -m app.cli stats # Clean up orphaned Redis keys (quiz progress with no expiry) docker compose exec backend python -m app.cli cleanup-redis ``` ## Database ### Direct Access ```bash docker compose exec postgres psql -U pedquiz -d pedquiz ``` ### Backups Automated daily backups run via the `db-backup` service (prodrigestivill/postgres-backup-local). Retention: 14 daily, 4 weekly, 6 monthly. Stored in `./backups/`. ```bash # Check backup status docker compose logs db-backup --tail=10 # List backups ls -la backups/ # Manual backup docker compose exec postgres pg_dump -U pedquiz pedquiz > manual-backup.sql # Restore from backup cat backups/daily/pedquiz-YYYYMMDD-HHMMSS.sql.gz | gunzip | \ docker compose exec -T postgres psql -U pedquiz -d pedquiz ``` ## User Roles | Role | Capabilities | |------|-------------| | `user` | Take quizzes, study flashcards, enroll in courses, create quizzes from question bank | | `moderator` | All user abilities + create courses, upload PDFs, manage documents | | `admin` | All moderator abilities + admin dashboard, user management, model config, system settings | ## Common Issues ### Document stuck in "processing" ```bash docker compose exec backend python -m app.cli fix-stuck-docs ``` Cause: Celery worker restarted mid-task. The fix resets status to "ready". ### DDL race condition on startup One or two backend workers may fail on startup with `Application startup failed`. This is normal — multiple uvicorn workers race to run ALTER TABLE migrations, and losers get a deadlock error. The surviving workers handle all traffic. Check with: ```bash docker compose logs backend --tail=10 | grep "startup complete" ``` ### Celery task not running ```bash # Check Celery is connected docker compose logs celery --tail=5 # Check if tasks are registered docker compose exec celery celery -A app.tasks inspect registered # Check active tasks (don't restart if tasks are running!) docker compose exec celery celery -A app.tasks inspect active ``` ### Password reset without email ```bash docker compose exec backend python -m app.cli reset-password user@example.com newpassword ``` ### User can't log in (unverified email) ```bash docker compose exec backend python -m app.cli verify-email user@example.com ``` ## Environment Key settings in `backend/.env`: | Variable | Purpose | |----------|---------| | `APP_URL` | Base URL for email links (e.g. `https://pedshub.com`) | | `SECRET_KEY` | JWT signing key — change in production | | `MAIL_FROM` | Sender email for verification/reset emails | | `LITELLM_API_BASE` | LiteLLM proxy URL for AI features | | `LITELLM_API_KEY` | API key for LiteLLM proxy | | `TURNSTILE_SITE_KEY` / `TURNSTILE_SECRET_KEY` | Cloudflare Turnstile bot protection | | `BBB_SERVER_URL` / `BBB_SECRET` | BigBlueButton integration for live sessions | ## Security Notes - Passwords are hashed with **bcrypt** (one-way, irreversible) - Registration checks passwords against **Have I Been Pwned** breach database (warns, doesn't block) - Only the first 5 characters of the SHA-1 hash are sent to HIBP (k-anonymity) - JWT tokens auto-refresh via sliding expiration (12h age or <1h remaining) - Rate limiting on login (10 attempts per IP per 15 min) via Redis - Email verification required for new accounts