CSC/ECE 517 Spring 2026 - E2612. Course-based reports
E2612: Course-Based Reports
Design Document
| Project | E2612 — Course-based Reports |
|---|---|
| Mentor | Ed Gehringer |
| Authors | Mihir Kamat, Ravi Goparaju |
| Status | Pre-implementation |
| Last Updated | April 2026 |
1. Overview
Expertiza currently surfaces course-level student performance data through two separate reports — a 360-degree assessment report and an aggregated teammate review report — each with their own access points and presentation formats. This fragmentation makes it difficult for instructors and TAs to get a coherent picture of how students are doing across a course.
This project consolidates both into a single unified table, accessible from the Courses list page. The table displays every enrolled student alongside their grades, topics, and teammate scores for every assignment in the course, with instructor-controlled column visibility to keep the view manageable. The implementation targets Expertiza's reimplemented React/TypeScript frontend. The legacy Rails views serve only as a reference for the underlying data model; no legacy code will be reused.
2. Requirements
The following requirements were established through the project specification and mentor meetings with Professor Ed Gehringer.
Display
- All relevant data must appear in a single unified table view, without pagination or splitting across multiple components.
- Students are placed along the vertical axis (rows); assignments are represented as grouped sub-column sets along the horizontal axis.
- Assignment column groups must be ordered chronologically by due date, earliest to latest.
Interactivity
- Each column must support click-to-sort, toggling between ascending and descending order with a visible directional indicator.
- Individual column types (e.g., Peer Grade, Topic) must be togglable via checkboxes, hiding or showing that field across all assignments at once.
- A grouped master checkbox must be able to toggle all sub-columns of a related type simultaneously (e.g., a single "Teammate Scores" checkbox covers both received and given scores).
Column Exclusion (highest priority rule)
- If an assignment does not structurally support a given column type (e.g., a non-topic assignment has no topic), that column must be excluded entirely from that assignment's group — it must not appear as an empty or placeholder cell.
- This rule overrides checkbox visibility settings.
- Assignments that do support a column type but simply have no data yet remain visible with an empty cell and stay toggleable.
- The report must be reachable via a button in each course row on the Courses list page.
3. Access Point and Routing
The report is triggered by the brown table/report icon in the Actions column of the Courses list. Rather than expanding inline, the view opens at a dedicated route:
/courses/:courseId/class_assignment_overview
A dedicated route is warranted because the table will be wide and data-heavy, and embedding it inline would compromise readability. The entry point icon should follow the same conventions used by other action icons in the course row, consistent with Course.tsx patterns.
4. Table Design
4.1 Layout
The table is structured as a student-by-assignment matrix. Each row represents one enrolled student; each assignment contributes a group of sub-columns spanning the horizontal axis. A class averages row is pinned at the top or bottom of the table and displays the mean value for every numeric field.
To the right of all assignment groups, a set of course-level aggregate columns summarizes each student's performance across the full course.
4.2 Per-Assignment Sub-Columns
Assignment groups appear in ascending chronological order by each assignment's last due date. Where two assignments share the same last due date, creation date serves as a tiebreaker.
Each assignment group may contain the following sub-columns, depending on what the assignment structurally supports and which toggles the instructor has enabled:
| Sub-column | Data Source | Notes |
|---|---|---|
| Topic | Assignment topic signup records | Only rendered if the assignment has topics enabled |
| Peer Grade | Weighted average of reviews received | May require stubbing the AssignmentTeam mixin if not yet implemented |
| Instructor Grade | grade_for_submission on the Teams table | Only populated if the instructor entered grades within Expertiza |
| Avg. Teammate Score (Received) | Composite score received from teammates | Applicable to team assignments only |
| Avg. Teammate Score (Given) | Composite score the student gave to teammates | Lower priority; include if feasible |
| Author Feedback | Author feedback score records | Toggleable; used by some instructors |
The column exclusion rule (Requirement 7) is enforced at column generation time, not at render time. The backend response must distinguish between two distinct cases:
- supported: false — the column does not exist for this assignment and must not be created, regardless of checkbox state
- supported: true, value: null — the column exists but has no data yet; render as an empty cell
4.3 Course-Level Aggregate Columns
Aggregate columns appear once per student at the far right of the table. They reflect only the field types currently toggled on — hiding a field type also removes its corresponding aggregate.
Teammate score aggregates are averaged per assignment rather than per individual review, so that larger projects with more teammates do not carry disproportionate weight.
| Aggregate Column | Calculation Method |
|---|---|
| Overall Avg. Peer Grade | Mean across all peer-reviewed assignments |
| Overall Avg. Instructor Grade | Mean across assignments where a grade was entered |
| Overall Avg. Teammate Score (Received) | Mean per assignment (not per review) |
| Overall Avg. Teammate Score (Given) | Mean per assignment (if included) |
| Overall Avg. Author Feedback | Mean across applicable assignments |
5. Column Visibility and Sorting
5.1 Checkbox Controls
A control panel above the table exposes one checkbox per sub-column type. Toggling a checkbox hides or shows that field type across every assignment simultaneously. When a field type is hidden, its corresponding aggregate column is hidden as well. A grouped master checkbox covers logically related fields (e.g., one checkbox for both teammate score columns).
The exclusion rule takes priority over all checkbox state. A checkbox cannot surface a column that the assignment does not support.
5.2 Row Sorting
Any column header can be clicked to sort all student rows by that column's values. A second click reverses the direction. The sort state is indicated by a caret in the column header. The class averages row does not participate in sorting and remains pinned at all times.
6. Data Model
6.1 Frontend Row Type
Each row in the table corresponds to one student. Assignment data is stored in a map keyed by assignment ID, with each entry holding whichever sub-column values are applicable:
type StudentAssignmentOverviewRow = {
studentId: number;
studentName: string;
studentFullName: string;
assignments: {
[assignmentId: string]: {
topic?: string | null;
peerGrade?: number | null;
instructorGrade?: number | null;
avgTeammateScores?: number | null;
receivedScores?: number | null;
givenScores?: number | null;
authorFeedback?: string | null;
};
};
};
6.2 Backend API
The API approach — a single consolidated endpoint versus multiple targeted requests with frontend aggregation — is an open question to be resolved with the mentor (see Section 9). Regardless of approach, the data made available to the frontend must include all enrolled students, all assignments ordered by last due date, per-student-assignment metric values, and per-assignment metadata indicating which column types are structurally supported.
6.3 Data Sources
| Data Point | Source |
|---|---|
| Instructor grade | grade_for_submission on the Teams table |
| Peer grade | Calculated via mixin on AssignmentTeam (stub if needed) |
| Teammate review scores | Existing teammate review records |
| Assignment ordering | Last due date from assignment deadline records |
| Topic selection | Topic signup / assignment topic records |
| Author feedback | Author feedback score records |
7. Implementation Plan
Phase 1 — Foundation
Add the route /courses/:courseId/class_assignment_overview and wire the entry point button in the course row, following conventions in Course.tsx and CourseAssignments.tsx. Before writing any UI code, define the complete type surface in frontend/src/types/courseAssignmentOverview.ts, covering StudentAssignmentOverviewRow, column group definitions, and the supported metadata shape.
Phase 2 — Service and Transform Layer
Create frontend/src/services/courseAssignmentOverviewService.ts, modeled on the pattern in gradesService.ts. This service is responsible for fetching raw API data and transforming it into three outputs consumed by the table component: rows, assignmentColumnGroups, and supportedColumnKindsByAssignment. Isolating this logic from the React component makes it independently testable, which matters because the column exclusion rule is the most failure-prone part of the system.
Phase 3 — Table Rendering
Render the table using the shared Table.tsx rather than a custom HTML table. Table.tsx already provides click-to-sort headers, Bootstrap rendering, column visibility support, and a TanStack Table core that natively supports grouped column headers via table.getHeaderGroups() and colSpan. The grouped assignment header structure maps directly onto TanStack's header group model.
Column exclusion must be enforced during column generation, not at render time. For each assignment–metric pair: if the assignment does not support the metric, do not create the column; if it does, create the column and then apply checkbox visibility state. This ordering ensures that supported: false always wins over any checkbox setting.
Phase 4 — Checkbox Toolbar
Build the visibility control panel using FormCheckBoxGroup.tsx (Formik-based) or Bootstrap Form.Check for simpler local state. The checkbox model is keyed on metric type, not on individual columns. Table.tsx currently initializes columnVisibility into internal state once; for live checkbox-driven toggles, the component should be lightly extended to keep external visibility state in sync rather than remounting the table on each change. A "Show All / Hide All" convenience control is a worthwhile addition.
Phase 5 — Validation
Before any styling work, validate the transform logic against edge cases: a topic-based assignment with topic data, a topic-based assignment with no topic selected yet, a non-topic assignment (column must be absent entirely), an assignment with author feedback supported but no data, and a student with partial data across assignments. These are the cases most likely to produce subtle rendering bugs.
Phase 6 — UX Refinements
After correctness is confirmed: add horizontal scroll affordance for wide tables, tooltip truncation for long feedback text, and consider pinning the student identity column as a fixed first column to aid orientation on wide viewports.
8. Reuse Decisions
| Component | Decision | Rationale |
|---|---|---|
| Table.tsx | Reuse directly | Provides sort, visibility, and grouped headers out of the box |
| gradesService.ts pattern | Reuse pattern | Consistent service/transform separation |
| FormCheckBoxGroup.tsx | Reuse | Matches existing form patterns in the codebase |
| Course.tsx routing conventions | Reuse | Consistent navigation entry point |
| ReviewTableau.tsx transform pattern | Adapt, do not copy | Useful reference for dynamic column generation |
| ViewScores.tsx data shape | Do not reuse | Data model is too simple for this use case |
| Legacy Rails report views | Do not reuse | Clean reimplementation only |
9. Out of Scope
The following are not part of this implementation: meta-review columns (deprecated in Expertiza), LLM-based review scores (not yet available in the new system), pagination, and per-assignment field customization (toggles are global by field type, not per assignment).
10. Open Questions
| Question | Owner |
|---|---|
| Is the AssignmentTeam peer grade mixin implemented in the new system, or does it need to be stubbed? | Team to investigate |
| Single consolidated API endpoint vs. multiple requests with frontend aggregation? | Confirm with mentor |
| Should Avg. Teammate Score (Given) be default-visible or treated as a stretch goal? | Confirm with mentor |
| Should author feedback be shown or hidden by default on first load? | Confirm with mentor |
| Should the class averages row be pinned at the top or bottom? | Confirm with mentor |
| Should aggregate columns reflect only currently-visible field types? | Confirm with mentor |