Skip to content

Rebuild courses from selected processing window#157

Merged
srkirkland merged 8 commits into
masterfrom
srk/term-update-logic
May 18, 2026
Merged

Rebuild courses from selected processing window#157
srkirkland merged 8 commits into
masterfrom
srk/term-update-logic

Conversation

@srkirkland
Copy link
Copy Markdown
Member

@srkirkland srkirkland commented May 15, 2026

Summary

  • add SQL/backend course rebuild from an admin-selected two-year processing window
  • add the React admin UI for choosing the academic year span and rebuilding courses
  • combine course rebuild with the annual submissions reset and remove the old Manage Submissions page
  • normalize course-number lookup behavior across course/request flows

Validation

  • dotnet build src/tacos.mvc/tacos.mvc.csproj
  • dotnet test Test/Test.csproj --no-restore
  • npm --prefix src/tacos.mvc run build -- --mode production
  • npx -y react-doctor@latest . --verbose --diff
  • applied EF migrations and rollback-tested the rebuild proc against tacos-test

Summary by CodeRabbit

  • New Features

    • Course number normalization (whitespace-insensitive) and improved matching across views.
    • Admin UI to preview academic-term windows and trigger course-list rebuilds.
    • Server-side course-rebuild workflow with options to preserve referenced courses or reset submissions.
  • Improvements

    • Hardened cross-listing parsing and normalization.
    • Validation and ordering of rebuild term windows.
  • Documentation

    • Added comprehensive course data domain documentation.
  • Tests

    • Expanded tests for course-number behavior and rebuild validation/execution.
  • Style

    • New admin/terms UI styles.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 15, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3054e249-1b87-4e46-8bc8-1228c5febdff

📥 Commits

Reviewing files that changed from the base of the PR and between 213c49e and 9bc6794.

📒 Files selected for processing (1)
  • src/tacos.core/Migrations/20260515231740_CourseRebuildResetsSubmissions.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/tacos.core/Migrations/20260515231740_CourseRebuildResetsSubmissions.cs

📝 Walkthrough

Walkthrough

Adds domain documentation and a normalization utility, applies normalized course-key lookup across controllers and tests, implements a validated CourseRebuild service + SQL gateway with DTOs and tests, registers DI, provides an admin React UI, and adds EF migrations that create/harden and modify the rebuild stored procedures.

Changes

Course Rebuild Feature

Layer / File(s) Summary
Domain documentation & normalization
CONTEXT.md, src/tacos.core/Resources/CourseNumberKey.cs, src/tacos.mvc/Extensions/CourseNumberQueryExtensions.cs
Adds canonical domain docs and introduces CourseNumberKey.Normalize() plus MatchingCourseNumber() query extensions used for normalized lookups.
Controllers & tests: apply normalization
src/tacos.mvc/Controllers/CoursesController.cs, src/tacos.mvc/Controllers/RequestsController.cs, Test/Controllers/RequestsControllerTests.cs
Controllers now normalize incoming course identifiers and use MatchingCourseNumber(...) for lookups; tests updated/added to assert normalization ("ECS 188""ECS188") and invalid-course-number validation.
CourseRebuild service, models & tests
src/tacos.mvc/Models/CourseRebuildModels.cs, src/tacos.mvc/Services/CourseRebuildService.cs, Test/Services/CourseRebuildServiceTests.cs, src/tacos.mvc/Startup.cs
Adds ICourseRebuildService/ICourseRebuildSqlGateway, CourseProcessingWindow validation for six-term windows, SQL gateway calling stored procedures, DTO models, unit tests covering grouping/ordering/validation, and DI registrations.
System controller, frontend and styling
src/tacos.mvc/Controllers/SystemController.cs, src/tacos.mvc/Views/System/ManageCourseRebuild.cshtml, src/tacos.mvc/ClientApp/pages/ManageCourseRebuild.tsx, src/tacos.mvc/ClientApp/css/site.scss, src/tacos.mvc/ClientApp/index.tsx, src/tacos.mvc/Views/System/Index.cshtml
Replaces prior submissions endpoints with rebuild endpoints (options + rebuild POST), adds ManageCourseRebuild view and React page to preview spans & trigger rebuild, CSS for term-preview UI, and wires module import.
EF migrations & stored procedures
multiple src/tacos.core/Migrations/* files
Adds migrations that create/alter udf_ParseCrossListedCourseNumbers, usp_GetCourseRebuildAcademicYearSpanOptions, and usp_RebuildCoursesFromProcessingWindow; subsequent migrations harden parsing, inject request-reset behavior, and preserve courses referenced by requests. Designer snapshots included.

Sequence Diagram(s)

sequenceDiagram
  participant Admin
  participant UI as React UI
  participant SystemCtrl as SystemController
  participant Service as CourseRebuildService
  participant Gateway as CourseRebuildSqlGateway
  participant DB as SQL Server
  
  Admin->>UI: Load page
  UI->>SystemCtrl: GET CourseRebuildOptions
  SystemCtrl->>Service: GetAcademicYearSpanOptionsAsync()
  Service->>Gateway: GetAcademicYearSpanTermRowsAsync()
  Gateway->>DB: EXEC usp_GetCourseRebuildAcademicYearSpanOptions
  DB-->>Gateway: Term rows
  Gateway-->>Service: rows
  Service-->>SystemCtrl: AcademicYearSpanOptionModel[]
  SystemCtrl-->>UI: JSON options
  
  Admin->>UI: Select span, confirm rebuild
  UI->>SystemCtrl: POST RebuildCourses({ academicTermCodes })
  SystemCtrl->>Service: RebuildCoursesAsync(termCodes)
  Service->>Service: CourseProcessingWindow.Validate(termCodes)
  alt Validation fails
    Service-->>SystemCtrl: CourseRebuildValidationException
    SystemCtrl-->>UI: HTTP 400
  else
    Service->>Gateway: RebuildCoursesAsync(termCodes)
    Gateway->>DB: EXEC usp_RebuildCoursesFromProcessingWindow (TVP)
    DB-->>Gateway: Success
    Gateway-->>Service: Complete
    Service-->>SystemCtrl: CourseRebuildResultModel
    SystemCtrl-->>UI: JSON result
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • ucdavis/tacos#143: Overlaps RequestsControllerTests changes for normalized/spaced course-number handling.
  • ucdavis/tacos#153: Touches RequestsController logic and may overlap controller/test behavior changes here.

Suggested reviewers

  • sprucely
  • jSylvestre

"🐰
I hopped through docs and normalized keys,
Rebuilt the lists and fixed the old ties,
Spans checked, procs run, UI lights the way,
Admins click confirm — data's fresh today!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.03% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly summarizes the main feature: a course rebuild operation scoped to an admin-selected processing window, which aligns with the primary objective and the bulk of changes (migrations, service layer, UI, and controller updates for this feature).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch srk/term-update-logic

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (1)
src/tacos.core/Migrations/20260515231740_CourseRebuildResetsSubmissions.cs (1)

15-80: 🏗️ Heavy lift

Prefer full procedure definitions over string-surgery patching in migrations.

These CHARINDEX/STUFF edits are fragile to minor definition drift and can hard-fail deployment (50009/50010). Emitting canonical CREATE OR ALTER PROCEDURE text per migration is more deterministic.

Also applies to: 92-133

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tacos.core/Migrations/20260515231740_CourseRebuildResetsSubmissions.cs`
around lines 15 - 80, The migration is doing fragile string-surgery on the
stored proc using `@Definition`, CHARINDEX, STUFF and sp_executesql for
dbo.usp_RebuildCoursesFromProcessingWindow; replace that logic with an explicit
canonical CREATE OR ALTER PROCEDURE statement containing the full desired
procedure body and execute that (still via sp_executesql) instead of editing
OBJECT_DEFINITION text, and apply the same replacement for the other similar
block around lines 92-133 so the migration deterministically deploys the
complete procedure text rather than patching via `@Definition/CHARINDEX/STUFF`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/tacos.core/Migrations/20260515222222_CourseRebuildFromProcessingWindow.cs`:
- Around line 563-567: The update is truncating CrossListingsString to 50 chars
which can drop members; change the assignment in the migration so
NewCourses.[CrossListingsString] receives the full/200-char-supported value from
CrossListingGroups.[CrossListingsString] (e.g., replace the LEFT(..., 50) usage
with the full value or LEFT(..., 200)) in the UPDATE that touches NewCourses
(refer to the UPDATE statement in CourseRebuildFromProcessingWindow migration
that sets [IsCrossListed], [CrossListingsString], [AverageEnrollment]).

In `@src/tacos.core/Migrations/20260515231740_CourseRebuildResetsSubmissions.cs`:
- Around line 111-125: The rollback guard currently compares
Requests.[CourseNumber] to `#NewCourses`.[Number] directly, which can misfire when
values differ only by spacing or case; update the WHERE NOT EXISTS clause to
normalize both sides (trim surrounding whitespace and use a consistent case)
before comparing — e.g., apply RTRIM/LTRIM (or TRIM) and a case-normalizer like
UPPER (or LOWER) to NewCourses.[Number] and Requests.[CourseNumber] so the NOT
EXISTS check uses the normalized values when deciding whether to THROW the 50007
error about referenced courses.

In `@src/tacos.mvc/ClientApp/pages/ManageCourseRebuild.tsx`:
- Line 150: The alert div in ManageCourseRebuild.tsx currently always uses
role="status" (polite); change it so when the rendered alert is an error
(alert.type includes "alert-error") it uses role="alert" (assertive) to ensure
immediate announcement. Locate the JSX with the div that references alert.type
and replace the fixed role with a conditional expression that selects "alert" if
alert.type contains "alert-error" and "status" otherwise, preserving the
existing classes and behavior.

In `@src/tacos.mvc/Controllers/CoursesController.cs`:
- Around line 30-35: The Details action currently calls
CourseNumberKey.Normalize(id) on raw route input which can throw for
null/invalid IDs; mirror the guard used in Get by validating id first (e.g.,
check for null/empty/invalid format) or wrap CourseNumberKey.Normalize(id) in a
try/catch and return a BadRequest/NotFound instead of letting an exception
bubble. Locate the Details method and adjust input handling around
CourseNumberKey.Normalize (or reuse the same validation helper used by Get) so
bad IDs produce a 400/404 response rather than a 500.

In `@src/tacos.mvc/Controllers/RequestsController.cs`:
- Around line 189-192: Extract course-number normalization and validation into a
single guarded helper method (e.g., TryGetCourseByNormalizedNumber or
ValidateAndFindCourse) and use it from Save, Recalculate, and Submit instead of
calling CourseNumberKey.Normalize inline; the helper should call
CourseNumberKey.Normalize, treat empty/null/invalid results as a BadRequest
result, and return either a BadRequest IActionResult or the matched course
fetched via _context.Courses.MatchingCourseNumber(...).FirstOrDefaultAsync so
callers can short-circuit on invalid input and rely on a single
normalization/guard path.

In `@src/tacos.mvc/Controllers/SystemController.cs`:
- Around line 205-216: The DbException catch in CourseRebuildOptions is
returning ex.Message to clients; change it to log the full exception (use the
controller's ILogger or existing logging helper) and return a generic BadRequest
result with a non-sensitive message like "An error occurred while retrieving
options" (do the same for the DbException handler in RebuildCourses).
Specifically, inside CourseRebuildOptions and RebuildCourses catch (DbException
ex) blocks, replace direct return of ex.Message with logger.LogError(ex,
"...context...") and return BadRequest("A database error occurred while
processing your request.") or similar generic text while keeping domain
exceptions (e.g., CourseRebuildValidationException) unchanged.

In `@src/tacos.mvc/Extensions/CourseNumberQueryExtensions.cs`:
- Around line 14-15: Change the ad-hoc Replace(" ", "") normalization to remove
all Unicode whitespace so DB rows with tabs/newlines still match the normalized
input: update the predicates and ordering expressions that reference c.Number
(the Where/OrderBy occurrences using Replace(" ", "").ToUpper()) to strip all
whitespace (e.g. use Regex.Replace(c.Number, "\\s+", "") or
string.Concat(c.Number.Where(ch => !char.IsWhiteSpace(ch))) and then ToUpper())
so they match CourseNumberKey.Normalize; apply this same change to every
occurrence (the Where/OrderBy uses around the comparisons, including the ones
flagged at the three locations).

---

Nitpick comments:
In `@src/tacos.core/Migrations/20260515231740_CourseRebuildResetsSubmissions.cs`:
- Around line 15-80: The migration is doing fragile string-surgery on the stored
proc using `@Definition`, CHARINDEX, STUFF and sp_executesql for
dbo.usp_RebuildCoursesFromProcessingWindow; replace that logic with an explicit
canonical CREATE OR ALTER PROCEDURE statement containing the full desired
procedure body and execute that (still via sp_executesql) instead of editing
OBJECT_DEFINITION text, and apply the same replacement for the other similar
block around lines 92-133 so the migration deterministically deploys the
complete procedure text rather than patching via `@Definition/CHARINDEX/STUFF`.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a6ce6ea1-8f89-49e1-bfbe-b8f205b5def4

📥 Commits

Reviewing files that changed from the base of the PR and between 27f15c6 and 41b0007.

📒 Files selected for processing (25)
  • CONTEXT.md
  • Test/Controllers/RequestsControllerTests.cs
  • Test/Services/CourseRebuildServiceTests.cs
  • src/tacos.core/Migrations/20260515222222_CourseRebuildFromProcessingWindow.Designer.cs
  • src/tacos.core/Migrations/20260515222222_CourseRebuildFromProcessingWindow.cs
  • src/tacos.core/Migrations/20260515231110_HardenCrossListingParser.Designer.cs
  • src/tacos.core/Migrations/20260515231110_HardenCrossListingParser.cs
  • src/tacos.core/Migrations/20260515231740_CourseRebuildResetsSubmissions.Designer.cs
  • src/tacos.core/Migrations/20260515231740_CourseRebuildResetsSubmissions.cs
  • src/tacos.core/Migrations/20260515233434_CourseRebuildPreservesReferencedCourses.Designer.cs
  • src/tacos.core/Migrations/20260515233434_CourseRebuildPreservesReferencedCourses.cs
  • src/tacos.core/Resources/CourseNumberKey.cs
  • src/tacos.mvc/ClientApp/css/site.scss
  • src/tacos.mvc/ClientApp/index.tsx
  • src/tacos.mvc/ClientApp/pages/ManageCourseRebuild.tsx
  • src/tacos.mvc/Controllers/CoursesController.cs
  • src/tacos.mvc/Controllers/RequestsController.cs
  • src/tacos.mvc/Controllers/SystemController.cs
  • src/tacos.mvc/Extensions/CourseNumberQueryExtensions.cs
  • src/tacos.mvc/Models/CourseRebuildModels.cs
  • src/tacos.mvc/Services/CourseRebuildService.cs
  • src/tacos.mvc/Startup.cs
  • src/tacos.mvc/Views/System/Index.cshtml
  • src/tacos.mvc/Views/System/ManageCourseRebuild.cshtml
  • src/tacos.mvc/Views/System/ManageSubmissions.cshtml
💤 Files with no reviewable changes (1)
  • src/tacos.mvc/Views/System/ManageSubmissions.cshtml

Comment thread src/tacos.core/Migrations/20260515231740_CourseRebuildResetsSubmissions.cs Outdated
Comment thread src/tacos.mvc/ClientApp/pages/ManageCourseRebuild.tsx Outdated
Comment thread src/tacos.mvc/Controllers/CoursesController.cs
Comment thread src/tacos.mvc/Controllers/RequestsController.cs Outdated
Comment thread src/tacos.mvc/Controllers/SystemController.cs
Comment thread src/tacos.mvc/Extensions/CourseNumberQueryExtensions.cs Outdated
Refine the course rebuild process to better manage associated requests, either resetting submission status or preventing rebuilds when they would remove active requests.

Improve consistency in course number normalization and validation across the application, adding early rejection for invalid inputs.

Expand course matching logic to tolerate more whitespace characters in numbers. Also, increase cross-listing string length.

Enhance error reporting and accessibility for user alerts.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/tacos.core/Migrations/20260515231740_CourseRebuildResetsSubmissions.cs`:
- Line 33: The SQL equality expressions in the migration (comparing
NewCourses.[Number] and Requests.[CourseNumber]) only strip spaces; update them
to also strip tabs, newlines and carriage returns to match the application-level
MatchingCourseNumber logic. Replace occurrences of REPLACE(..., N' ', N'') with
a chain that removes NCHAR(9), NCHAR(10) and NCHAR(13) (for example nested
REPLACE calls around the existing LTRIM(RTRIM(...)) and UPPER calls) so the
comparisons in the migration class CourseRebuildResetsSubmissions and its SQL
fragments treat \t, \n, \r the same as spaces; this will align behavior with
CourseNumberQueryExtensions.cs and fix both up and down migration mismatches.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3f608557-00ba-4344-94ab-2188fdc00b64

📥 Commits

Reviewing files that changed from the base of the PR and between 41b0007 and 213c49e.

📒 Files selected for processing (8)
  • Test/Controllers/RequestsControllerTests.cs
  • src/tacos.core/Migrations/20260515222222_CourseRebuildFromProcessingWindow.cs
  • src/tacos.core/Migrations/20260515231740_CourseRebuildResetsSubmissions.cs
  • src/tacos.mvc/ClientApp/pages/ManageCourseRebuild.tsx
  • src/tacos.mvc/Controllers/CoursesController.cs
  • src/tacos.mvc/Controllers/RequestsController.cs
  • src/tacos.mvc/Controllers/SystemController.cs
  • src/tacos.mvc/Extensions/CourseNumberQueryExtensions.cs
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/tacos.mvc/Extensions/CourseNumberQueryExtensions.cs
  • src/tacos.mvc/Controllers/CoursesController.cs
  • src/tacos.mvc/ClientApp/pages/ManageCourseRebuild.tsx
  • src/tacos.mvc/Controllers/SystemController.cs
  • src/tacos.core/Migrations/20260515222222_CourseRebuildFromProcessingWindow.cs

Comment thread src/tacos.core/Migrations/20260515231740_CourseRebuildResetsSubmissions.cs Outdated
@srkirkland srkirkland merged commit f0bba36 into master May 18, 2026
3 checks passed
@srkirkland srkirkland deleted the srk/term-update-logic branch May 18, 2026 16:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant