CLUE-550: auto-generate a class-wide Driving Question Board per unit - #2890
CLUE-550: auto-generate a class-wide Driving Question Board per unit#2890lbondaryk wants to merge 4 commits into
Conversation
Add a class-wide shared document (the Driving Question Board) that is auto-created once per (class, unit) when group documents are enabled. It is editable by every class member, appears in Sort Work under "No Group"/"No Name", and its title is authorable on the Document Settings page (default "Driving Question Board"). - New drivingQuestionBoard document type + unit-keyed synthetic storage uid - get-or-create on opening any lesson; always-on Sort Work listener so the single board shows under every lesson and filter scope - Edit opens it in the main workspace (read-only in Sort Work); also fixes the resources-pane Edit button to show for any document the current user can edit (own docs, the user's group doc, and the DQB) - Class-wide tile presence: a class-scoped activity channel (broadcaster + listener) so all editors see each other's tile focus, not just group-mates - Concurrent history manager + workspace title bar wired for the new type Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces a new class-wide “Driving Question Board” (DQB) document that is automatically created once per class per unit (when group documents are enabled), appears in Sort Work under “No Group” / “No Name”, supports class-wide tile-focus presence, and can have its title authored via Document Settings.
Changes:
- Adds a new
drivingQuestionBoarddocument type with unit-keyed synthetic storage uid, plus get-or-create/guarantee logic. - Extends Sort Work sorting/listening to always include the unit’s DQB across filter scopes and supports opening/editing it from the main workspace.
- Adds a class-scoped presence channel (broadcaster + listener) so DQB tile focus badges reflect all class members, not just group-mates.
Reviewed changes
Copilot reviewed 25 out of 25 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/models/stores/unit-configuration.ts | Adds a unit-level authored title field for the DQB. |
| src/models/stores/stores.ts | Adds dqbActivity store to hold class-wide DQB presence activity. |
| src/models/stores/sorted-documents.ts | Adds an always-on Firestore metadata listener for DQB docs and merges into Sort Work results. |
| src/models/stores/documents.ts | Uses concurrent history manager for DQB docs (like group docs). |
| src/models/stores/document-group.ts | Places DQB under “No Group” / “No Name” sections in Sort Work grouping. |
| src/models/stores/configuration-manager.ts | Exposes drivingQuestionBoardTitle from unit configuration. |
| src/models/stores/base-stores-types.ts | Extends base store typing to include dqbActivity. |
| src/models/stores/app-config-model.ts | Surfaces drivingQuestionBoardTitle via appConfig. |
| src/models/document/document.ts | Adds isDrivingQuestionBoard convenience view. |
| src/models/document/document-utils.ts | Uses authored DQB title for display; makes DQB accessible to all students. |
| src/models/document/document-types.ts | Adds new document type constant + enum membership + sortable/type helpers. |
| src/lib/logger-types.ts | Adds a log event for DQB creation. |
| src/lib/firebase.ts | Adds RTDB path helpers for class-scoped DQB activity presence. |
| src/lib/driving-question-board-activity-broadcaster.ts | New broadcaster for class-wide DQB tile-focus presence. |
| src/lib/db.ts | Implements DQB creation, get-or-create, metadata stamping, synthetic uid, and RTDB activity write helpers. |
| src/lib/db-types.ts | Extends DB document metadata types to include DQB. |
| src/lib/db-listeners/index.ts | Wires DQB activity listener/broadcaster into DB listeners lifecycle. |
| src/lib/db-listeners/db-driving-question-board-activity-listener.ts | New listener mirroring class-scoped RTDB presence into dqbActivity. |
| src/components/tiles/tile-activity-badges.tsx | Shows tile-focus badges for both group docs and the class-wide DQB. |
| src/components/document/sort-work-document-area.tsx | Shows Edit button when user can edit DQB or their group doc (not only owned docs). |
| src/components/document/document.tsx | Adds a DQB-specific title bar (authored title + styling hook). |
| src/components/document/document-workspace.tsx | Ensures the unit’s DQB exists when group documents are enabled. |
| src/clue/clue.scss | Styles the DQB title bar like other teal titlebars. |
| src/authoring/types.ts | Adds DQB title to authoring unit config type. |
| src/authoring/components/workspace/document-settings.tsx | Adds UI for authoring the DQB title with a default value. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // The class-wide Driving Question Board belongs to no group. | ||
| if (doc.type === DrivingQuestionBoardDocument) { | ||
| return `No ${groupTerm}`; | ||
| } |
There was a problem hiding this comment.
Good catch — fixed in e0c6383. sortGroupSectionLabels now sorts numeric group labels first (ascending) and places non-numeric labels like "No Group" last deterministically, instead of producing NaN sort keys.
| // The class-wide Driving Question Board belongs to no group. | ||
| if (doc.type === DrivingQuestionBoardDocument) { | ||
| return `No ${groupTerm}`; | ||
| } | ||
| if (doc.type === GroupDocument) { |
There was a problem hiding this comment.
Added in e0c6383 — new tests in document-group.test.ts assert the DQB lands under "No Group" (by Group) and "No Name" (by Name).
| // Ensures the unit's Driving Question Board exists (creating it on first open of any | ||
| // lesson). Does not open it as the primary document — access is only via Sort Work. | ||
| public async guaranteeDrivingQuestionBoard() { | ||
| await this.getOrCreateDrivingQuestionBoard(); | ||
| } |
There was a problem hiding this comment.
Agreed — fixed in e0c6383. guaranteeDrivingQuestionBoard() now only creates the document if missing (via the extracted findDrivingQuestionBoardMetadata()) and no longer opens it, so users don't start DQB content/history listeners on workspace mount. It still appears in Sort Work via the always-on Firestore metadata listener, and content/history load only when a user actually opens it.
- Reuse group document thumbnail styling (purple border + corner icon) for the Driving Question Board - Center the DQB workspace title across the full bar width - Make the content-drift check tolerant of an empty remote history: an empty chain has nothing to contradict the content, so surface the document instead of hard-failing it. Fixes the DQB being bricked when its first-session history uploads race the lazy metadata creation; the board self-heals on the next edit. Genuine corruption (a non-empty chain missing the saved id) still errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #2890 +/- ##
==========================================
- Coverage 86.06% 84.23% -1.83%
==========================================
Files 909 911 +2
Lines 52012 52226 +214
Branches 13719 13777 +58
==========================================
- Hits 44763 43995 -768
- Misses 7234 8214 +980
- Partials 15 17 +2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
- guaranteeDrivingQuestionBoard now creates-if-missing WITHOUT opening the
document, so users don't start DQB content/history listeners on workspace
mount unless they actually open it (it still appears in Sort Work via the
metadata listener). Extracted findDrivingQuestionBoardMetadata.
- Make sortGroupSectionLabels deterministic for non-numeric labels: numeric
group labels sort first ascending, "No Group" (NaN) goes last instead of
producing NaN sort keys.
- Add unit tests for DQB grouping ("No Group" by Group, "No Name" by Name).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Place the class-wide Driving Question Board in a dedicated "Whole Class" section in the by-group sort instead of the "No Group" bucket, and sort it ahead of the numbered groups. Also gitignore the local OSEMagnets demo copy (the real unit lives in the clue-curriculum repo). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
scytacki
left a comment
There was a problem hiding this comment.
Thanks for getting this feature working, Leslie. I did a detailed engineering review and found a number of issues that should be worked through before this can merge — they range from a blocking correctness regression to a larger design question about whether the Driving Question Board should be its own document type.
Full write-up, with code references and a triage summary:
https://gist.github.com/scytacki/01ae500953533bb955018583cab31729
Highlights:
- Blocking: the content-drift check was relaxed in a way that weakens a shared corruption guard used by group documents and the playback path, not just the DQB (#6). Separately, auto-creating on every unit launch widens an existing duplicate-document race, and the DQB has no primary-document pointer to recover, so users can silently end up in different boards (#1).
- Design decision: the DQB is introduced as a whole new document type that nearly duplicates the group document, producing a lot of parallel code (duplicate listeners/broadcaster, a separate Firestore query, and many two-type conditionals). It may be better modeled as a group/collaborative document with a class-wide scope (#3).
- Plus several follow-up/cleanup items (#2, #4, #5, #7), some pre-existing.
Because several of these involve architecture and shared infrastructure rather than local fixes, I'd suggest assigning the revision to a full-time developer who can review the write-up and work through the right solutions with me.
|
|
||
| # Local demo copy of OSEMagnets — the real unit lives in the clue-curriculum repo | ||
| src/public/demo/units/OSEMagnets/ |
There was a problem hiding this comment.
Rather than making an exception to one particular unit. It'd be better to have a folder that is always ignored perhaps drafts or tmp and then any local temporary units can be stored there.
|
Closing this in favor of the implementation that landed across #2922, #2923, #2928, #2940, and #2942. That series keeps the UX from this PR but takes a different approach underneath. Rather than adding a new document type, a class-wide document is described by a few independent properties — who it belongs to, where it is kept, what part of the curriculum it covers, whether several people can edit it at once, and which kind of document it is. A group document and a class-wide document end up being the same type differentiated by those properties, so adding another class-wide document later (a word wall, say) becomes a configuration change rather than new code. It also addresses the issues raised in review here: exactly one document per class per unit via the shared canonical-pointer mechanism, the authored title moved out of generic settings and into the unit's class-wide document declaration, and a single shared edit predicate in place of the inline logic in the Sort Work document area. One piece is deliberately not carried over. The group and class-wide presence channels are not yet unified, and the case where one user with multiple windows open overwrites their own presence is not yet fixed. Both are tracked as separate planned work. Until that lands, the activity indicators inside a class-wide document show only the members of the viewer's own group rather than the whole class — a partial picture, accepted for now. Thanks for the original — the UX here is what the replacement was built to match. |
Add a class-wide shared document (the Driving Question Board) that is auto-created once per class, per unit when group documents are enabled. It is editable by every class member, appears in Sort Work under "No Group"/"No Name", and its title is authorable on the Document Settings page (default "Driving Question Board").