This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
# Start (production)
npm start
# Start (dev, auto-restarts on file change)
npm run dev
# As a systemd service (installed on this machine)
sudo systemctl start ap-python-server
sudo systemctl restart ap-python-server
sudo systemctl status ap-python-server
sudo journalctl -u ap-python-server -f # live logsThere are no automated tests. Verify behavior by running the server and hitting the endpoints directly.
The server will refuse to start without a .env file containing at minimum:
SESSION_SECRET=<hex string>
PORT=4000
NODE_ENV=production
DEFAULT_TEACHER_PASSWORD=SMCSChief
ALLOWED_ORIGINS=http://localhost:4000,http://127.0.0.1:4000,http://<server-ip>:4000
Critical: cookie.secure in the session config (server.js:178) is hardcoded to false — do not change it back to process.env.NODE_ENV === 'production'. The server runs HTTP only; secure: true silently drops session cookies and breaks all auth.
The entire backend is a single file: server.js (~3600 lines). database.js handles SQLite initialization only and is required once.
- SQLite via the
sqlite3package (callback-style, not promise-based) - DB file:
appython.dbin the project root — excluded from git; copy it manually when migrating machines - Schema is defined and migrated in
database.jsviaALTER TABLE ... ADD COLUMN IF NOT EXISTSguards
Key tables:
| Table | Purpose |
|---|---|
students |
Accounts with bcrypt-hashed passwords, login tracking, lockout |
assignments |
Title + markdown prompt + rubric + is_visible + tab_monitoring_enabled + max_submissions |
submissions |
Code, feedback, grade (stored as string e.g. "9/12"), execution output |
project_files |
Multi-file project support; one row per file per student per assignment |
drafts |
Auto-saved code (upsert on student_id + assignment_id) |
tab_violations |
Records when students navigate away during a monitored quiz |
settings |
Key/value store: claude_api_key, teacher_password (bcrypt hash), ai_model, teacher_network_access, etc. |
canvas_student_mapping |
Maps internal student IDs to Canvas LMS user IDs per course |
submission_adjustments |
Per-student overrides to max_submissions |
Two separate sessions share the same express-session / session-file-store:
- Teacher:
req.session.isTeacher === true— set on POST/api/teacher/login - Student:
req.session.studentId— set on POST/api/student/login
Teacher endpoints additionally enforce localhostOnly middleware unless teacher_network_access is '1' in the settings table. This flag is loaded into the module-level variable teacherNetworkAccessEnabled at startup and updated in-memory when toggled via the API.
- The Anthropic client is instantiated per-request via
getAnthropicClient(), which reads the API key from the DB each time. - Grading uses Claude tool use:
callGradingAI()forces the model to call thegrade_submissiontool, which returns structuredrubric_scores(array of sections with earned/possible points) +narrative_feedback.processGradingResult()sums the scores and appends the grade string. - AI tutor (
/api/chat) streams nothing — it returns a single response. It reads chat history from the DB for context and passes the student's current code and last console output in the system prompt. - The AI model used for both grading and tutoring is read from
settings.ai_modelat request time.
/api/run-code writes student code to a temp file and runs it with:
python3 -u solution.py(unbuffered output for real-time streaming)- 10-second execution timeout via
setTimeout+process.kill() - 50,000-character output cap
Interactive execution (input() support) uses Socket.io: the client connects via WebSocket, the server spawns the Python process and pipes stdout/stderr back over the socket, and stdin is fed in as the user types.
Static files in public/. No build step — plain HTML/CSS/JS served directly.
student.html— student coding interface (CodeMirror editor with Python mode, AI tutor chat, submit)pyteacher13.html— teacher dashboard (assignments, submissions, grades, settings, Canvas sync)index.html— landing page
The teacher dashboard can sync grades to Canvas. Config (API token + base URL) is stored in settings.canvas_config. The /api/canvas/* routes proxy requests to the Canvas REST API and handle the student name → Canvas user ID mapping via canvas_student_mapping.
When the API requires authentication that's hard to automate, it's safe to insert into the DB directly using a Node script run from the project root (where node_modules/sqlite3 is available):
const sqlite3 = require('sqlite3');
const db = new sqlite3.Database('appython.db');
db.run('INSERT INTO assignments ...', [...values], function(err) { ... });Run with node <script>.js from /home/student/Documents/PythonQuizAISite/.
- Systemd service file: needs to be created/updated for Python site (port 4000)
- Sessions stored in
./sessions/(file-based, 7-day TTL) - Logs written to
./logs/(combined, error, security — rotating at 10MB) - The
appython.dbdatabase is the single source of truth for all application state; back it up before making schema changes