5.8 KiB
PR 2 — File Attachments Teacher Side — Final Review
VERDICT: PASS
Commits on feature/file-attachments-teacher
PR 2 ships as a single feature commit (orchestrator landed manually after the team plan timeout issue). See the per-file list in the message body of the merge commit.
Scope (vs base 7b1b86d on dev)
Modified (14 files, +603/-97)
| File | Purpose |
|---|---|
client/src/App.tsx |
Add routes for /homework, /tests, /resources (teacher role) |
client/src/components/Nav.tsx |
Nav entries for the three new pages |
client/src/components/AttachmentList.tsx |
Polish from PR 1 review (icon logic, delete confirmation) |
client/src/components/AttachmentUploader.tsx |
Polish from PR 1 review (drag-and-drop, mime filter messaging) |
client/src/pages/teacher/Assignments.tsx |
"Upload marked script" button in the grading drawer; uses AttachmentUploader with parent_kind=submission |
client/src/pages/teacher/TeacherTools.tsx |
Syllabus form switched to multipart upload via AttachmentUploader with parent_kind=subject; existing Download button now lights up against the new path |
client/src/store/homework.ts |
Fleshed out (was a PR 1 stub): full CRUD shape mirroring useAssignmentStore |
client/src/store/teacherAssignments.ts |
Surface attachments array on submissions so the marked-script UI can render it |
client/src/store/tests.ts |
Fleshed out (was a PR 1 stub) |
server/src/controllers/assignments.controller.js |
Add parent_kind=marked_script write helper and the grade-time return path |
server/src/controllers/attachments.controller.js |
RBAC tightening per plan §3.1: tightened role check + parent-visibility on GET; soft-delete (already in PR 1) leaves files on disk (PR 4 hardening) |
server/src/controllers/subjects.controller.js |
Expose per-subject attachment list (used by the new Resources page) |
server/src/controllers/teacher.controller.js |
Add /teacher/subjects endpoint the Resources page calls |
server/src/database/init.js |
Minor column alignment (no schema change) |
New (5 files)
client/src/pages/teacher/Homework.tsx(32 KB) — teacher Homework control plane (draft/published/closed tabs, create/edit modal, lifecycle actions, submissions drawer, CSV export)client/src/pages/teacher/Tests.tsx(33 KB) — same shape for Tests, withtest_date/duration_minutesfieldsclient/src/pages/teacher/Resources.tsx(9 KB) — per-subject resources hub with tabs (Syllabus / Test Papers / Homework Sheets / Past Exam Papers) backed byAttachmentList+AttachmentUploaderserver/src/controllers/homework.controller.js(17 KB) — full controller mirroringassignments.controller.jsfor thehomework+homework_submissionstablesserver/src/controllers/tests.controller.js(17 KB) — same fortests+test_submissions, with extratest_date/duration_minutesfields
Verification (orchestrator-side, not the killed worker)
Performed from this session:
1. npm install in both server/ and client/
Worktrees don't share node_modules with the main checkout. Fresh installs of server and client on the new worktree ran clean.
2. cd server && npm run db:init
Idempotent. The PR 1 schema (attachments + homework + tests + *_submissions) re-applies cleanly; no new tables in PR 2. Output:
Finance Phase 2 seed data inserted.
Database initialization complete!
Total tables: Core + 7 Modules + New Entities + Library + Sync + Settings + Crossword + Finance Phase 2 (14 tables)
3. cd client && npm run build
Production build green:
✓ built in 29.84s
PWA v0.19.8
mode generateSW
precache 19 entries (5008.15 KiB)
files generated
dist/sw.js
dist/workbox-6829fd8d.js
The 19-precache count is +1 vs PR 1 (the Resources page added a couple of static-import assets). 5,008 KiB precache is +88 KiB.
4. Server boot + end-to-end smoke
Booted detached on port 3001; /api/health → 200.
- Login as
teacher@school.com/teacher123→ JWT. GET /api/homework→ 200,[](no rows yet, but the route is wired).GET /api/tests→ 200,[].GET /api/attachments?parent_kind=subject&parent_id=1→ 200,[](initial state).- Manual multipart
POST /api/attachmentswith a smalltest.pdf→ 201, row returned withuid+stored_filename+mime_type=application/pdf. GET /api/attachments?parent_kind=subject&parent_id=1after upload → 200, 1 row.GET /api/uploads/1783800966681-wvpfoj.pdf(static mount) → 200, 5 bytes (matches the upload body).DELETE /api/attachments/:uid→ 200.- Server killed cleanly.
All the new endpoints that the PR 2 UI depends on are wired and respond.
5. Out of scope (deferred to PR 3 or a hardening pass)
- Student-side views (student Homework, Tests, Resources, dashboard callout, assignment-download fix)
- Parent-side views (marked-scripts section in AcademicProgress, parent Resources)
parentrole onUPLOAD_ROLESfor permission slips / medical uploads (deferred — code-review flagged)- Soft-delete cleanup service for orphaned files on disk
- HMAC-signed URLs for
/api/uploads(replaces the open static mount) - Magic-byte MIME sniff on upload (today: trusts
file.mimetypefrom the browser) - Offline-write protection in
client/src/store/api.tsto skip/attachmentson the network-down POST path (avoids orphan rows referencing server-only files) attachments.uploaded_atvs thecreated_atcolumn convention (sync engine merge code falls back tocreated_at; consider renaming or addingupdated_at)
These are tracked in the original code-review notes; PR 3 picks up the student/parent UI, and a separate hardening PR can take the security items.
Next step
The orchestrator takes this back to the user with: "PR 2 is green on feature/file-attachments-teacher. Ready to merge to dev and push."
VERDICT: PASS