# PR 3 — File Attachments Student + Parent Side — Final Review **VERDICT: PASS** ## Branch `feature/file-attachments-views` branched from `f02f0a1` (dev at the time of PR 2 merge). One feature commit lands the entire PR 3. ## Scope ### New files (4) | File | Purpose | |---|---| | `client/src/pages/student/Resources.tsx` | Student course resources — read-only mirror of teacher Resources, 4 tabs (Syllabus / Test Papers / Homework Sheets / Past Exam Papers) with download + inline preview | | `client/src/pages/student/Homework.tsx` | Student homework — read-only list with Submit / View Detail / Marked Script surfacing; status tabs (To Do / Submitted / Graded / Overdue) | | `client/src/pages/student/Tests.tsx` | Student tests — same shape with `test_date` + `duration_minutes` fields and marked-script surfacing | | `client/src/pages/parent/Resources.tsx` | Per-child resources viewer with child switcher; reads /users/children then mirrors student Resources | ### Modified (6) | File | Purpose | |---|---| | `client/src/App.tsx` | Routes for /homework, /tests, /resources (student) and /parent-resources | | `client/src/components/Nav.tsx` | Nav entries: student gets Homework / Tests / Course Resources; parent gets Course Resources | | `client/src/pages/dashboard/StudentDashboard.tsx` | Plan §6.4 callout: "N marked scripts available" when student has any returned submission, links to /assignments | | `client/src/pages/student/Assignments.tsx` | "View Marked Script" button on completed tab when `submission.status === 'returned'`; inline modal with iframe (PDF) / img (image) / Open + Download actions; `status` field added to `AssignmentSubmission` type | | `client/src/pages/parent/AcademicProgress.tsx` | Plan §7.1: "Marked Scripts" section above the bento stats; lists the teacher's returned marked scripts for the selected child with Preview + Download | | `client/src/store/assignments.ts` | `AssignmentSubmission.status` + `attachments[]` types added so the marked-script modal can match by submission id | | `server/src/controllers/attachments.controller.js` | Plan §7.3 RBAC widening: privileged readers (admin / principal / systems_admin) see all marked scripts; parents see marked scripts and submissions for their own children via a JOIN on `parent_students`; `parent` role added to `UPLOAD_ROLES` per PR 1 code-review follow-up | ## Verification (orchestrator) - `npm install` on both server and client (fresh worktree) - `cd server && npm run db:init` clean (PR 1 + PR 2 schema already in place, idempotent) - `cd client && npm run build` — production build green: ``` ✓ built in 14.95s PWA v0.19.8 precache 19 entries (5057.21 KiB) files generated dist/sw.js dist/workbox-*.js ``` 5,057 KiB precache (+49 KiB vs PR 2). - Server boot detached via `Start-Process node`; `/api/health` → 200. - Smoke (PowerShell `Invoke-RestMethod`): - `POST /api/auth/login` (teacher + student) → JWT - `GET /api/attachments?parent_kind=subject` as teacher → 200, `[]` - `GET /api/attachments?parent_kind=marked_script` as teacher → 200, `[]` - `GET /api/assignments/my/submissions` as student → 200, `[]` Server is healthy on `http://localhost:3001`. ## Out of scope (deferred) These are tracked from PR 1 / PR 2 code-review notes and aren't blocking: - HMAC-signed `/api/uploads` (replaces the open static mount — security) - Magic-byte MIME sniff on upload (defense in depth) - Soft-delete cleanup service for orphaned files on disk - Offline-write protection in `client/src/store/api.ts` to skip `/attachments` on the network-down POST path - `attachments.uploaded_at` vs the `created_at` column convention (sync engine merge code falls back to `created_at`; consider renaming or adding `updated_at`) - Bulk ZIP download of all course materials - "Download my submission" round-trip (still uses base64 in Zustand state; v1 follows the marked-script pattern but the data path needs server-side join work that's a hardening pass) ## Next step The orchestrator takes this back to the user with: "PR 3 is green on `feature/file-attachments-views`. Ready to merge to `dev` and push." VERDICT: PASS