Central Station / YPM-FEATURE-STUDENT-PRACTICE-DOCUMENTS

Student practice documents vs official assignments

features/student-practice-documents.md · Updated 2026-05-24
GET /api/tickets/YPM-FEATURE-STUDENT-PRACTICE-DOCUMENTS

Summary

Make assignment-type practice docs and teacher-issued assignments explicit, separate flows

6Questions 0Links 0Comments 1PRs
Open questions 6 items
  1. 1 Should practice documents be visible to teachers at all by default, or only if the student submits/shares them?
  2. 2 If visible, where should they live: a "Practice" tab on the class view, the student details popout, or an AssignmentType detail page?
  3. 3 Can a practice document be attached to an official Assignment later, or should students copy/derive a new assigned document from it?
  4. 4 Does class access to AssignmentTypes need a hard schema relation now (`ClassAssignmentType`), or can org-wide AssignmentType visibility plus enrolled-class filtering carry v1?
  5. 5 How should legacy restored documents from PR #114 be labeled in the UI until they are backfilled/classified?
  6. 6 Are Daily Pages practice-by-default, official-assignment-by-default, or both depending on how the teacher launches them?
Spec body Markdown
# Student practice documents vs official assignments

Define and support two student document creation modes: self-guided practice documents created from an AssignmentType, and official teacher-issued assignment documents created from an Assignment.

## Current status

The compatibility fix is live: `yawp-2.0` PR #114 merged on 2026-05-09 (`d96987f0566b7a56593f90ff9df73d4f31da07fc`) and restored teacher class views by including both assignment-linked documents and legacy class-linked documents through a shared class-view query helper. Production investigation found 2,479 active legacy class-linked documents across 64 classes that were hidden by the assignment-only query, plus 10 documents that matched both paths for the same class and 0 class mismatches. The helper de-duplicates overlapping documents and preserves the new assignment path.

This spec is the forward-looking product work. The hotfix keeps existing teachers whole; this spec decides how students intentionally create practice/scratch documents without turning those documents into accidental official assignments.

## Problem

The assignments-unification refactor correctly split the old overloaded `StudentCourse` concept into:

- **AssignmentType** — the reusable writing experience/template.
- **Assignment** — a teacher-issued instance tied to a class.
- **Document** — the student's actual writing.

But the UI and teacher visibility model still blur two separate user intents:

1. A student wants to browse available writing experiences and start a practice/scratch document.
2. A teacher has assigned official work to a class and expects to track, grade, and release it.

This became visible after the May 2026 missing-documents incident. Existing documents were not deleted; legacy class-visible documents had lost their live `Document.classId` query path and did not have `assignmentId`, so teacher class views could not find them until the compatibility fix restored legacy visibility. That incident is a signal that the product needs an explicit place for unassigned/practice documents instead of treating them as accidental edge cases.

Related product context from Kevin/Brian emails:

- Kevin's teacher dashboard proposal treats AssignmentTypes as "like student courses from earlier versions" and proposes a teacher-facing choice between starting a new document and creating a new assignment.
- Brian wants to see and approve student-facing workflow changes before pilot rollout.
- The PM repo should remain the source of truth: when prototypes teach us something, the spec gets updated before engineering ships the behavior.

## Goals

- Preserve student freedom to create documents from an AssignmentType without a teacher-issued Assignment.
- Make official assignment work clearly distinct from practice/scratch work in both student and teacher UI.
- Keep teacher grading queues focused on official assigned work by default.
- Give teachers and students clear language for what each document mode means.
- Ensure future dashboard/class-view work knows whether it is showing assigned work, practice work, or both.
- Prevent future "missing documents" confusion by giving unassigned documents an intentional home.

## Non-goals

- Forcing every student document to have an Assignment.
- Letting practice documents automatically enter grading queues.
- Building teacher-created AssignmentTypes v1. That may come later; for now AssignmentTypes remain primarily admin-managed / org-managed.
- Designing the full daily-pages workflow here. Daily pages remains its own spec, but it should reuse the document-mode distinction.
- Replacing the PR #114 legacy visibility compatibility fix. That fix stays as a safety net while the product model becomes explicit.

## Domain notes

### Core model

- **AssignmentType** answers: what writing experience is this? Examples: Thesis-Driven Essay, Welcome to YAWP, Daily Pages, AP History DBQ.
- **Class-enabled AssignmentType** answers: can this class/student access this writing experience for self-guided work?
- **Assignment** answers: has a teacher officially assigned this work to a class, with prompt/due date/grading context?
- **Document** answers: what did this student write?

### Document modes

**Official assignment document**

- Created from an `Assignment`.
- Has `Document.assignmentId`.
- Has `Document.assignmentTypeId` through the Assignment's type.
- Belongs in teacher class views, grading queues, released-grade flows, and assignment dashboards.
- Student sees it under "Assignments" or equivalent teacher-issued work.

**Practice / scratch document**

- Created from an `AssignmentType` directly.
- Has `Document.assignmentTypeId`.
- Has `Document.assignmentId = null`.
- Student-owned and self-guided.
- Does not appear in teacher grading queues by default.
- May later be attached/submitted to an Assignment if we deliberately design that transition.

The important rule: `assignmentId = null` is not inherently bad data. It can represent an intentional practice document. The product problem is whether the UI clearly explains that state.

### Class access

Current code still allows assignment-type starts without an Assignment. Students can create these from the AssignmentType page. The future model should not remove that ability; it should gate which AssignmentTypes a student may browse/start based on class/org visibility.

This likely needs a replacement for the old `ClassStudentCourse` idea, e.g. `ClassAssignmentType`, but the exact schema is an engineering decision. See [assignment-type-visibility](assignment-type-visibility.md) for org-level sharing and picker behavior.

## UX sketch

### Student home

The student should see two separate areas:

```
+--------------------------------------------------+
| Assigned Work                                    |
+--------------------------------------------------+
| Macbeth Essay             Due May 12   [Start]   |
| Thesis Essay Revision     Due May 15   [Open]    |
+--------------------------------------------------+

+--------------------------------------------------+
| Practice                                         |
+--------------------------------------------------+
| Thesis-Driven Essay                  [New Draft] |
| Welcome to YAWP                       [New Draft]|
| Daily Pages                           [New Draft]|
+--------------------------------------------------+
```

Labels should avoid implying that practice drafts are invisible bugs. Suggested language:

- Assigned Work
- Practice
- Start assigned work
- New practice draft

### AssignmentType detail page

If a student opens an AssignmentType directly, the primary action is "New practice draft", not "New assignment" or just "New".

The page should show existing practice documents for that type separately from official assigned documents using that type.

### Teacher class view

Teacher class views should default to official work:

```
Assignments | Students | Practice
```

The exact tab structure depends on [course-view](course-view.md), but the distinction should hold:

- Assignment/status counts use official assignment documents only.
- Practice documents, if surfaced, are in a clearly labeled secondary area and not mixed into "Submitted" / "To grade" unless deliberately submitted.
- Legacy/no-assignment docs restored by PR #114 should eventually live in the practice/legacy area or be backfilled into official assignments where there is an obvious mapping.

### Teacher AssignmentType view

Kevin's proposed teacher flow has the right shape:

- From an AssignmentType, teacher can create a new practice/document-style item for themselves if needed.
- More importantly, teacher can create an official Assignment from that type and assign it to one or more classes.

Button language needs to be explicit:

- "Create assignment" = official class work.
- "New practice draft" or "New sample document" = not official class work.

## Data model implications

No immediate destructive migration.

Near-term:

- Keep `Document.assignmentTypeId` required.
- Keep `Document.assignmentId` optional.
- Treat null `assignmentId` as a first-class practice/scratch state.
- Add query helpers that name the distinction explicitly, e.g. `officialAssignmentDocumentWhere` and `practiceDocumentWhere`, rather than ad hoc `assignmentId: null` filters scattered through routes.

Likely follow-up schema work:

- Add a class/org visibility relation for AssignmentTypes, such as `ClassAssignmentType`.
- Consider a `Document.mode` enum only if query semantics remain ambiguous after the visibility relation. Do not add this unless it removes real ambiguity; `assignmentId` may be enough.
- Consider an "attach practice document to assignment" transition later. That requires product decisions about prompt compatibility, submissions, grading history, and whether a teacher can pull a student's practice draft into official work.

Legacy handling:

- PR #114 restored teacher visibility by including `DocumentClassForensic.oldClassId` in class views.
- Long-term, those legacy documents should be classified: either backfilled into real Assignments when a safe mapping exists, or displayed as practice/legacy documents for the class.
- `DocumentClassForensic` should remain audit data, not the permanent primary visibility model.

## File paths in `yawp-2.0` likely to change

- `services/web-app/app/domain/documents.server.ts` — make creation intent explicit: assignment-backed vs practice/scratch.
- `services/web-app/app/routes/app.assignments.$assignmentId.start/route.ts` — official assignment start path; should continue requiring a real Assignment.
- `services/web-app/app/routes/app.assignment-types.$id/route.tsx` — practice-document start path; relabel and scope clearly.
- `services/web-app/app/routes/app._index/route.tsx` — student home: separate assigned work from practice options.
- `services/web-app/app/routes/app.my-classes.$classId/route.tsx` — teacher class view: distinguish official assignment docs from practice/legacy docs.
- `services/web-app/app/routes/app.my-classes.$classId/class-document-where.server.ts` — compatibility helper from PR #114; should eventually narrow to legacy/practice handling or be retired after backfill.
- `services/web-app/app/services/released-grades.server.ts` — released-grade queries should stay official-assignment-scoped unless practice grading is explicitly added.
- `packages/prisma/schema.prisma` — possible `ClassAssignmentType` relation; possible later `Document.mode` only if needed.
- `packages/prisma/scripts/assignments-unification-postcheck.ts` — add a postcheck that active legacy/no-assignment docs have an intentional visibility home.

## Open questions

- [ ] Should practice documents be visible to teachers at all by default, or only if the student submits/shares them?
- [ ] If visible, where should they live: a "Practice" tab on the class view, the student details popout, or an AssignmentType detail page?
- [ ] Can a practice document be attached to an official Assignment later, or should students copy/derive a new assigned document from it?
- [ ] Does class access to AssignmentTypes need a hard schema relation now (`ClassAssignmentType`), or can org-wide AssignmentType visibility plus enrolled-class filtering carry v1?
- [ ] How should legacy restored documents from PR #114 be labeled in the UI until they are backfilled/classified?
- [ ] Are Daily Pages practice-by-default, official-assignment-by-default, or both depending on how the teacher launches them?

## Edge cases

- Student belongs to multiple classes and creates a practice document. It should not silently pick the first class and become teacher-visible without the student's or teacher's intent.
- Student leaves a class. Official assignment documents should retain assignment history; practice docs should remain student-owned unless we add class-scoped practice visibility.
- Teacher deletes or archives an Assignment. Existing official documents may become unassigned if `onDelete: SetNull` fires; those documents must not disappear. They should become legacy/practice/unassigned with a clear label.
- Teacher creates an AssignmentType but has not assigned it. It can appear in the teacher's library/picker but should not create class work until an Assignment exists.
- Practice document is submitted. Product needs to decide whether submission creates an official assignment link, creates a teacher-visible ad-hoc submission, or is blocked until the document is attached to an Assignment.
- Released grades should not accidentally include practice documents just because they share an AssignmentType.
- Paste alerts on practice documents may still matter for student safety/integrity but should not imply an assignment needs grading.

## Test plan

Unit / integration:

- Assignment start creates a Document with `assignmentId` and `assignmentTypeId`.
- AssignmentType start creates a Document with `assignmentTypeId` and null `assignmentId`.
- Student home query returns assigned work and practice options in separate buckets.
- Teacher class view official assignment counts exclude practice documents by default.
- If a practice/legacy area is added, class view shows no duplicate documents when a legacy doc matches both compatibility and assignment paths.
- Released grades service excludes practice documents unless a future explicit practice-grading feature opts them in.

E2E:

- Student starts an official Assignment and sees it under assigned work.
- Student starts a practice document from an AssignmentType and sees it under practice/drafts, not assigned work.
- Teacher sees official assignment documents in class workflow.
- Teacher does not see a student's private practice draft in grading queues by default.
- Legacy restored document remains reachable after PR #114 compatibility logic.

Manual QA:

- Walk the student dashboard with assignments enabled: language makes clear which actions are assigned vs practice.
- Walk a teacher class view after students create both document types.
- Confirm Brian can review the flow before any broad student-facing rollout, consistent with the PM workflow agreement.

## Rollout

Feature flag required for any visible UI changes. The compatibility fix from PR #114 is already live and should remain independent.

Suggested rollout:

1. Design/QA in preview with seeded students who have both official assignment docs and practice docs.
2. Internal demo to Brian before student-facing pilot.
3. Pilot with one selected school/class after Brian approval.
4. Expand only after teachers confirm the distinction is understandable.

## Engineering handoff checklist

A spec is `ready-for-engineering` only when all of these are true. Mark them off in the spec itself before flipping status.

- [x] Domain context covered
- [x] File paths in `yawp-2.0` listed
- [x] Data model implications spelled out, including backward-compat plan
- [x] UX sketch in prose
- [x] Edge cases enumerated
- [x] Test plan written
- [ ] Rollout plan decided
Repo sync Metadata
{
  "url": "https://github.com/The-Connell-School/yawp-2.0/pull/114",
  "repo": "The-Connell-School/yawp-2.0",
  "draft": false,
  "state": "MERGED",
  "title": "Fix teacher class view for legacy documents",
  "branch": "codex/hotfix-teacher-documents",
  "checks": {
    "total": 7,
    "failing": 2,
    "pending": 0,
    "successful": 5
  },
  "number": 114,
  "syncedAt": "2026-05-26T21:38:23.522Z",
  "mergeable": "UNKNOWN"
}