Skip to content

Commit bd96fb5

Browse files
Edwin ChanEdwin Chan
authored andcommitted
Add problem set submissions
1 parent 7a28c28 commit bd96fb5

17 files changed

Lines changed: 868 additions & 24 deletions

DBSMO/Projects/dbsmo/00 Start Here.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ This is the starting index for the [[dbsmo]] codebase knowledge base, generated
2929
- [[Risks and Pitfalls]] - fragile or confusing areas to avoid breaking.
3030
- [[Glossary]] - project-specific terms and abbreviations.
3131
- [[Attempt Review]] - saved submission review UI, authorization, data flow, and entry points.
32+
- [[Submissions]] - per-set recent submission directory, friends/name filters, pagination, and answer privacy.
3233
- [[Performance Analytics]] - shared Mastery Index, component metrics, validation, and change guidance.
3334
- [[Asymptote and Multiple Choice]] - diagram sandbox, variable choices, image-backed options, authoring/import flow, and deploy constraints.
3435
- [[Entry Points]] - now includes the permission-aware `/admin` panel and its grouped staff routes.
@@ -42,7 +43,7 @@ This is the starting index for the [[dbsmo]] codebase knowledge base, generated
4243
- Main UI routes live under `app/`; API handlers live under `app/api/`.
4344
- Current import notes include optional same-name image ZIPs for JSON imports, per-problem image uploads in the problem maker, tolerant JSON editor drafts, and explicit all-file batch dry-run/publish/upload actions with compressed/actual-expanded archive limits (sources: `lib/import/json-import.ts`, `lib/import/image-zip.ts`, `lib/import/zip-dry-run.ts`, `app/admin/create/page-client.tsx`, `app/admin/import/json-zip-import-panel.tsx`).
4445
- Current class/community notes include authored tasks, a mastery heatmap, problem-set writeups with image uploads/voting/deletion, and class announcements pinned on dashboards (sources: `app/users/[username]/page.tsx`, `app/problem-sets/[slug]/writeups/page.tsx`, `app/writeups/page.tsx`, `app/classes/announcement-composer.tsx`, `app/dashboard/page.tsx`, `prisma/schema.prisma`).
45-
- Saved submissions have an owner/staff-gated [[Attempt Review]] with links from submit results, solved-set locks, set/dashboard history, student detail, and per-set analytics (sources: `app/attempts/[id]/page.tsx`, `app/problem-sets/[slug]/answer-grid.tsx`, `app/dashboard/page.tsx`).
46+
- Saved submissions have a perfect-solve/staff-gated [[Attempt Review]] plus a redacted per-set [[Submissions]] directory with 20-row pagination, friends/name filters, and score/verdict visibility (sources: `app/attempts/[id]/page.tsx`, `app/problem-sets/[slug]/submissions/page.tsx`, `app/problem-sets/[slug]/answer-grid.tsx`, `app/dashboard/page.tsx`).
4647
- Cross-set student metrics use the shared evidence-aware [[Performance Analytics]] model; Mastery Index combines proficiency, breadth, and a consistency floor while keeping best-set average/mastery rate visible (sources: `lib/analytics.ts`, `app/leaderboard/page.tsx`).
4748
- Authoring and imports support sandboxed Asymptote-to-PNG diagrams plus `MULTIPLE_CHOICE` problems with two to 20 LaTeX/image-capable choices; see [[Asymptote and Multiple Choice]] (sources: `lib/asymptote.ts`, `lib/problem-set-authoring.ts`, `lib/import/json-import.ts`, `app/admin/problem-authoring-controls.tsx`).
4849

DBSMO/Projects/dbsmo/Architecture.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
---
22
date: 2026-06-26
3-
updated: 2026-08-04
3+
updated: 2026-08-05
44
type: architecture
55
tags: [project, architecture, system-design, dbsmo]
66
ai-first: true
77
project: "[[dbsmo]]"
88
confidence: high
9-
scanned-commit: f7e0c74
9+
scanned-commit: working-tree-2026-08-05
1010
---
1111

1212
## For future Claude
@@ -62,6 +62,8 @@ The answer grid is client-side and posts to `/api/submit`. It autosaves draft an
6262

6363
Submission is persisted in `app/api/submit/route.ts`: it reads bounded JSON, validates through `lib/submission.ts`, checks visibility, grades through `gradeAnswer(...)`, and creates the `Attempt`/`Response` records in a serializable transaction with bounded retries. Perfect-score locking and attempt numbering are decided inside that transaction so concurrent submissions cannot bypass them (sources: `app/api/submit/route.ts`, `lib/submission.ts`, `lib/grading.ts`).
6464

65+
The set header links to `/problem-sets/[slug]/submissions`. That server-rendered directory queries only the current 20-row page, orders by submission time, supports friend IDs from `Friendship` and a bounded display-name search, and keeps raw `Response` data out of the list. Verdict and score are visible to authenticated viewers; the submitter can review their own attempt, while other answer reviews require a perfect attempt for the same visible set or `admin:analytics` (sources: `app/problem-sets/[slug]/page.tsx`, `app/problem-sets/[slug]/submissions/page.tsx`, `app/attempts/[id]/page.tsx`, `lib/submissions.ts`, `prisma/schema.prisma`).
66+
6567
## Writeup Flow
6668

6769
Problem-set writeups are a separate readable/community surface at `/problem-sets/[slug]/writeups`, linked from the set header next to bookmarks. The server page requires auth, verifies set visibility for students, loads writeups with authors/images/votes, and sorts by newest or top score (source: `app/problem-sets/[slug]/writeups/page.tsx`). The sidebar `/writeups` directory lists latest/top writeups across visible sets and supports problem-set-focused search (source: `app/writeups/page.tsx`).

DBSMO/Projects/dbsmo/Attempt Review.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
---
22
date: 2026-07-19
3-
updated: 2026-07-19
3+
updated: 2026-08-05
44
type: feature
55
tags: [project, architecture, attempts, grading, ui, dbsmo]
66
ai-first: true
77
project: "[[dbsmo]]"
88
confidence: high
9-
scanned-commit: 271402e
9+
scanned-commit: working-tree-2026-08-05
1010
---
1111

1212
## Purpose
@@ -15,8 +15,8 @@ scanned-commit: 271402e
1515

1616
## Authorization
1717

18-
- The current user can review an attempt when `Attempt.userId` matches their database user ID.
19-
- Staff with `admin:analytics` can review another user's attempt. This currently covers Admin, Teacher, and Analyst according to `lib/permissions.ts`.
18+
- The submitter can review their own attempt; reviewing another user's attempt requires a perfect attempt for the same problem set.
19+
- Staff with `admin:analytics` can review any attempt. This currently covers Admin, Teacher, and Analyst according to `lib/permissions.ts`.
2020
- Unknown and unauthorized attempt IDs both call `notFound()` so the route does not disclose whether another student's submission exists.
2121
- `proxy.ts` includes `/attempts/:path*` as the broad signed-in boundary, but the page query remains authoritative (sources: `app/attempts/[id]/page.tsx`, `proxy.ts`, `lib/permissions.ts`).
2222

@@ -36,12 +36,13 @@ Sources: `app/attempts/[id]/page.tsx`, `lib/attempt-review.ts`, `app/problem-set
3636

3737
- Immediate submit result and solved-set lock: `app/problem-sets/[slug]/answer-grid.tsx`.
3838
- Five most recent attempts on a set: `app/problem-sets/[slug]/page.tsx`.
39+
- Twenty-row recent submissions directory with all/friends scope and name search: `app/problem-sets/[slug]/submissions/page.tsx` and `lib/submissions.ts`.
3940
- Student dashboard history: `app/dashboard/page.tsx`.
4041
- Staff student history: `app/admin/students/[id]/page.tsx`.
4142
- Per-set recent attempts: `app/admin/sets/[id]/analytics/page.tsx`.
4243

4344
## Testing
4445

45-
Pure behavior is covered by `tests/attempt-review.test.ts`; solved-lock review-link output is covered by `tests/answer-grid.test.ts`. The 2026-07-19 Chrome QA used an isolated local Postgres database and verified immediate review navigation, correct/incorrect/skipped rows, row expansion, accepted-answer math, light/dark rendering, set-history discovery, absence of horizontal overflow, and cross-student 404 behavior.
46+
Pure behavior is covered by `tests/attempt-review.test.ts` and `tests/submissions.test.ts`; solved-lock review-link output is covered by `tests/answer-grid.test.ts`. The submissions list deliberately does not load `Response` data; detailed review remains gated by the perfect-solve/staff rule.
4647

4748
Related: [[Components]], [[Data and Storage]], [[Entry Points]], [[Common Tasks]], [[Risks and Pitfalls]].

DBSMO/Projects/dbsmo/Common Tasks.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
---
22
date: 2026-06-26
3-
updated: 2026-08-04
3+
updated: 2026-08-05
44
type: common-tasks
55
tags: [project, architecture, maintenance, dbsmo]
66
ai-first: true
77
project: "[[dbsmo]]"
88
confidence: high
9-
scanned-commit: f7e0c74
9+
scanned-commit: working-tree-2026-08-05
1010
---
1111

1212
## For future Claude
@@ -43,7 +43,7 @@ For multiple-choice changes, also update `Problem.options` in `prisma/schema.pri
4343

4444
## Change Attempt Review
4545

46-
Start with [[Attempt Review]]. The server page and exact owner/staff authorization live in `app/attempts/[id]/page.tsx`; summary/status helpers and unit tests live in `lib/attempt-review.ts` and `tests/attempt-review.test.ts`. Entry links are spread across `app/problem-sets/[slug]/answer-grid.tsx`, `app/problem-sets/[slug]/page.tsx`, `app/dashboard/page.tsx`, `app/admin/students/[id]/page.tsx`, and `app/admin/sets/[id]/analytics/page.tsx`. Keep `/attempts/:path*` in `proxy.ts`, but do not rely on middleware for the per-attempt ownership check.
46+
Start with [[Attempt Review]]. The server page and exact perfect-solve/staff authorization live in `app/attempts/[id]/page.tsx`; summary/status helpers and unit tests live in `lib/attempt-review.ts`, `lib/submissions.ts`, and `tests/attempt-review.test.ts`/`tests/submissions.test.ts`. The set submission index is `app/problem-sets/[slug]/submissions/page.tsx`, linked beside the theme control in `app/problem-sets/[slug]/page.tsx`; it owns pagination, friend filtering, name search, and redacted list selection. Keep `/attempts/:path*` and `/problem-sets/:path*` in `proxy.ts`, but do not rely on middleware for the per-attempt answer check.
4747

4848
## Change LaTeX Statement Support
4949

DBSMO/Projects/dbsmo/Components.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
---
22
date: 2026-06-26
3-
updated: 2026-08-04
3+
updated: 2026-08-05
44
type: components
55
tags: [project, architecture, components, ui, dbsmo]
66
ai-first: true
77
project: "[[dbsmo]]"
88
confidence: high
9-
scanned-commit: f7e0c74
9+
scanned-commit: working-tree-2026-08-05
1010
---
1111

1212
## For future Claude
@@ -35,6 +35,7 @@ This note maps important [[dbsmo]] UI/components to their source files and usage
3535
- `ProblemSetPage` in `app/problem-sets/[slug]/page.tsx`: route page that loads a set by slug, chooses inline-statement vs PDF/file layout, and exposes the current user's five most recent saved attempt reviews.
3636
- `AnswerGrid` in `app/problem-sets/[slug]/answer-grid.tsx`: client answer form, autosave, review-later state, submit-to-`/api/submit`, result display, direct saved-review links, missed-topic next action, and feedback report dialog. When `ProblemSetPage` detects the set tag `Tests`, it passes the test layout so answer-only/PDF sets render as a 20×3 test answer sheet for 60 underlying `Problem` rows.
3737
- `AttemptReviewPage` in `app/attempts/[id]/page.tsx`: server-rendered [[Attempt Review]] with a submission identity/verdict summary and expandable question-result rows. It renders statements/assets and accepted answers through `LatexStatement`, and uses `lib/attempt-review.ts` for status, percentage, answer-list, and duration helpers.
38+
- `ProblemSetSubmissionsPage` in `app/problem-sets/[slug]/submissions/page.tsx`: server-rendered 20-row recent-submission table with all/friends scope, bounded name search, score/verdict rows, responsive mobile cards, and answer-review links gated by a perfect set solve or `admin:analytics`. `lib/submissions.ts` holds the page and visibility helpers.
3839
- `BookmarkButton` in `app/problem-sets/[slug]/bookmark-button.tsx`: client bookmark toggle backed by `/api/problem-sets/[id]/bookmark`.
3940
- Writeup header link in `app/problem-sets/[slug]/page.tsx`: icon link next to `BookmarkButton` that opens `/problem-sets/[slug]/writeups`.
4041
- `WriteupsPage` and `WriteupsClient` in `app/problem-sets/[slug]/writeups/`: server/client pair for set writeups. The server page handles auth, set visibility, sorting, and initial data; the client component handles the composer, image selection, optimistic voting, confirm-delete controls, and feed cards rendered with `LatexStatement`.

DBSMO/Projects/dbsmo/Data and Storage.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ tags: [project, architecture, data, storage, prisma, dbsmo]
66
ai-first: true
77
project: "[[dbsmo]]"
88
confidence: high
9-
scanned-commit: f7e0c74
9+
scanned-commit: working-tree-2026-08-05
1010
---
1111

1212
## For future Claude
@@ -53,7 +53,9 @@ Deployment docs currently use `npx prisma db push` and `npx prisma generate`, no
5353
5. Grades each answer with `gradeAnswer(...)`.
5454
6. Creates one `Attempt` and many `Response` records in a transaction.
5555

56-
Saved attempts are read by `/attempts/[id]` for [[Attempt Review]]. The page joins `Attempt.user`, `Attempt.problemSet` assets/file, and each `Response.problem`, then sorts responses by `Problem.number`. It exposes raw/normalized answers, correctness, points, accepted answers, grader notes, and explanations only to the attempt owner or a user with `admin:analytics`; unauthorized IDs resolve through `notFound()` (sources: `app/attempts/[id]/page.tsx`, `lib/attempt-review.ts`, `lib/permissions.ts`). 7. Returns attempt number, score, percentage, and per-problem result summary.
56+
Saved attempts are read by `/attempts/[id]` for [[Attempt Review]]. The page joins `Attempt.user`, `Attempt.problemSet` assets/file, and each `Response.problem`, then sorts responses by `Problem.number`. It exposes raw/normalized answers, correctness, points, accepted answers, grader notes, and explanations only to a viewer with a perfect attempt for that set or a user with `admin:analytics`; unauthorized IDs resolve through `notFound()` (sources: `app/attempts/[id]/page.tsx`, `lib/attempt-review.ts`, `lib/permissions.ts`, `lib/submissions.ts`). It returns attempt number, score, percentage, and per-problem result summary.
57+
58+
`/problem-sets/[slug]/submissions` is a redacted attempt index. It queries at most 20 rows per page, filters by all/friends scope and display name, and selects only attempt summary fields plus display-safe user identity. It never selects `Response` rows. `lib/submissions.ts` centralizes the page-size, verdict, percentage, and answer-visibility rules. The set is still visible to students only through `isVisibleToStudent(...)` (sources: `app/problem-sets/[slug]/submissions/page.tsx`, `lib/submissions.ts`, `lib/visibility.ts`).
5759

5860
Sources: `app/api/submit/route.ts`, `lib/grading.ts`, `prisma/schema.prisma`.
5961

DBSMO/Projects/dbsmo/Entry Points.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
---
22
date: 2026-06-26
3-
updated: 2026-08-04
3+
updated: 2026-08-05
44
type: entry-points
55
tags: [project, architecture, routes, apis, dbsmo]
66
ai-first: true
77
project: "[[dbsmo]]"
88
confidence: high
9-
scanned-commit: f7e0c74
9+
scanned-commit: working-tree-2026-08-05
1010
---
1111

1212
## For future Claude
@@ -49,7 +49,8 @@ Deployment flow is documented in `SETUP.md`: install dependencies, run `npx pris
4949

5050
- `/problem-sets` - browse/filter/sort problem sets with recommendations, assignments/bookmarks/practice views, media/status/category filters, search, and pagination (source: `app/problem-sets/page.tsx`).
5151
- `/problem-sets/[slug]` - set detail and answer entry, with inline statements or PDF fallback and file/video/solution display (source: `app/problem-sets/[slug]/page.tsx`).
52-
- `/attempts/[id]` - saved [[Attempt Review]] for the attempt owner or staff with `admin:analytics`; unauthorized and unknown IDs both return 404 (source: `app/attempts/[id]/page.tsx`).
52+
- `/attempts/[id]` - saved [[Attempt Review]] for the attempt owner, for a viewer who has solved the set perfectly, or for staff with `admin:analytics`; unauthorized and unknown IDs both return 404 (source: `app/attempts/[id]/page.tsx`, `lib/submissions.ts`).
53+
- `/problem-sets/[slug]/submissions` - authenticated recent-submission directory for a visible set. It shows 20 newest attempts per page, supports all/friends scope and bounded name search, exposes verdict/score to signed-in viewers, and links to answer review only after a perfect solve or for analytics staff (source: `app/problem-sets/[slug]/submissions/page.tsx`, `lib/submissions.ts`).
5354
- `/problem-sets/[slug]/writeups` - set writeup feed/composer with latest/top sorting, image attachments, and voting (sources: `app/problem-sets/[slug]/writeups/page.tsx`, `app/problem-sets/[slug]/writeups/writeups-client.tsx`).
5455
- `/writeups` - global writeups directory from the sidebar with latest/top views and problem-set search (source: `app/writeups/page.tsx`).
5556
- `/practice` - practice-mode UI backed by tags/next/submit APIs (source: `app/practice/page.tsx`).

DBSMO/Projects/dbsmo/Risks and Pitfalls.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
---
22
date: 2026-06-26
3-
updated: 2026-08-04
3+
updated: 2026-08-05
44
type: risks
55
tags: [project, architecture, risks, dbsmo]
66
ai-first: true
77
project: "[[dbsmo]]"
88
confidence: high
9-
scanned-commit: f7e0c74
9+
scanned-commit: working-tree-2026-08-05
1010
---
1111

1212
## For future Claude
@@ -51,7 +51,7 @@ Multiple-choice images are normal problem-set assets embedded in `Problem.option
5151

5252
## Attempt Reviews Expose Answer Keys
5353

54-
`/attempts/[id]` intentionally shows accepted answers and explanations after submission. Its database join therefore handles assessment-sensitive data. Preserve both checks in `app/attempts/[id]/page.tsx`: ordinary users must own the `Attempt`, and non-owners must have `admin:analytics`. Keep unauthorized IDs on the same `notFound()` path as missing IDs, and do not move answer keys into a client API without an equivalent exact authorization boundary (sources: `app/attempts/[id]/page.tsx`, `lib/permissions.ts`, [[Attempt Review]]).
54+
`/attempts/[id]` intentionally shows accepted answers and explanations after submission. Its database join therefore handles assessment-sensitive data. Preserve the check in `app/attempts/[id]/page.tsx`: the submitter may review their own attempt, while another viewer must have a perfect attempt for the same visible set or `admin:analytics`. The submissions index must remain redacted and must not select `Response` rows. Keep unauthorized IDs on the same `notFound()` path as missing IDs, and do not move answer keys into a client API without an equivalent exact authorization boundary (sources: `app/attempts/[id]/page.tsx`, `app/problem-sets/[slug]/submissions/page.tsx`, `lib/submissions.ts`, `lib/permissions.ts`, [[Attempt Review]]).
5555

5656
Writeups intentionally remain accessible even when submissions are locked or the user has not submitted. Do not reuse submission-lock logic to hide `/problem-sets/[slug]/writeups`; only normal auth and set visibility should gate that page (sources: `app/problem-sets/[slug]/writeups/page.tsx`, `app/api/problem-sets/[id]/writeups/route.ts`).
5757

0 commit comments

Comments
 (0)