Upgrade to LTS versions of .NET 10 and NodeJS 24#120
Conversation
…tion - Upgrade from .NET 8 to .NET 10 across all projects and packages - Centralize DbContext connection strings in Program.cs with fail-fast null validation, removing scattered OnConfiguring methods - Add Scrutor for convention-based service registration, replacing 30+ manual service registrations with namespace-based auto-discovery - Convert LibMan from global tool to local dotnet tool for consistent versioning across dev environments - Update Jenkins pipeline for net10.0 output paths and libman restore - Modernize routing from UseEndpoints to minimal API MapControllerRoute
- Upgrade Node.js from 20.19.4 to 24.13.0 LTS with security patches - Migrate 11 Vue files from Options API to Composition API with script setup - Replace this.$route/this.$router with useRoute()/useRouter() composables - Remove deprecated v-cloak directives across layout files - Update @tsconfig/node24 and @types/node to v24 compatible versions
- Remove unused using statements across C# codebase - Normalize TypeScript/Vue code style (quotes, trailing commas) - Make ApiController helper methods static - Update TypeScript target to ES2023 - Improve oxlint config and generic null checks
- Replace EndsWith(string) with EndsWith(char) and remove S6610 pragma suppressions across four Effort services - Convert App.vue to script setup, remove v-cloak directive
- Replace AutoMapper.Extensions.Microsoft.DependencyInjection with AutoMapper 14.0.0 (last MIT-licensed; DI extension folded into core) - Upgrade NLog 5.3→6.1 and add NLog.MailKit for mail target (now a separate package) - Major bumps: QuestPDF 2025.12.4, Scrutor 7.0, Razor.Templating.Core 3.0, Joonasw.SecurityHeaders 6.0 - Test infra: xunit 2.9.3, coverlet 6.0.4, SonarAnalyzer 10.19
- Microsoft.NET.Test.Sdk 18.0.1, xunit runner 3.1.5, JunitXml.TestLogger 8.0.0 - Remove System.Linq.Async (built into .NET 10), EntityFrameworkCore.Testing.Moq (unused), System.Security.Claims (built into .NET 10) - Add AutoMapper to test project for mapping tests
- Replace vuedraggable with vue-draggable-plus (unmaintained → active) - Replace manual event/keyboard/timer code with useKeyModifier, useEventListener, useTimeoutFn - Bump vue-router 5, vueuse 14, vitest 4, stylelint 17, glob 13, chokidar 5, cross-env 10
- @eslint/js now required as explicit dep (unbundled in v10) - eslint-plugin-security ^3→^4, eslint-plugin-html ^8.1.4 (minimum for ESLint 10 context.sourceCode API) - typescript-eslint ^8.56, eslint-plugin-vue ^10.8, vuejs-accessibility ^2.5 for ESLint 10 peer deps - Remove unused eslint-plugin-quasar (v0.17→v1 migration rules)
- oxfmt 0.35 replaces Prettier; lint-any.js simplified (no double-pass) - oxlint 1.29→1.50, tsgolint 0.8→0.14.1; config migrated to ignorePatterns - VS Code default formatter switched to oxc extension
- Make PermissionService/PhotoGalleryService stateless methods static (class-methods-use-this errors) - Reduce complexity in ViperFetch and lint-staged-dotnet by extracting helpers (complexity errors) - Add vitest/globals tsconfig to eliminate 40 redundant test imports - Apply auto-fixes: capitalized comments, prefer-const, !!x→Boolean(x), matcher improvements, no-loop-func suppressions
- Remove tsconfig noCheck to enforce type safety in tests - Fix EffortDbContext to use VIPER connection string (same DB) - Delete obsolete shims-vue.d.ts and remove auto-imported Vue macros
…arnings - Align @vitest/coverage-v8 with vitest 4 peer dependency - Fix Effort router import to match named export - Eliminate DEP0190 warnings in build scripts by passing command+args as single string to spawn with shell: true
- Change downloadFile from static to instance method call after ClosedXML replaced OpenXml on main - Update photo-gallery-store test mock to match instance method - Add non-null assertions to VPR-48 test files for strict TS - Fix self-referential type annotations in effort column tests
…injection - Remove parameterless constructors in CMS, LeftNavMenu, and SessionTimeoutService that resolved DbContexts via HttpHelper - Inject AAUDContext into DirectoryController and extract IndividualSearchResult.LookupEmailHost() to avoid inline context creation - Thread VIPERContext through AreaController, ApiSessionUpdateFilter, HomeController, and LayoutController for session timeout calls
…d MailKit to 4.15.0
- Vite ^7.1.11 → ^8.0.0 (4.2x faster production builds) - Enable experimental bundledDev mode for 8x faster dev page loads - Rename rollupOptions → rolldownOptions per migration guide - Remove rollup-plugin-visualizer and vite-plugin-vue-inspector (visualizer redundant with Codecov; inspector pending bundledDev compatibility fix upstream) - Remove hash-based proxy skip in ViteProxyHelpers.cs so bundledDev memory-served assets are forwarded to Vite in dev mode - Add @quasar/vite-plugin override for Vite 8 peer dep - Enable server.forwardConsole for browser→terminal log forwarding - Fix CTS router guard: check permissions !== undefined to prevent crash exposed by Rolldown's module initialization order
- Fix 8 VueApp errors: extract downloadFile from class, remove unused imports, suppress config default-export rules - Fix 33 wwwroot errors in site.js/qtable.js: var→let/const, void→undefined, isNaN→Number.isNaN, remove BOMs, unused params, optional catch binding, forEach→for...of - Fix remaining 18 wwwroot errors: extract wrapCsvValue from class, add .catch() to promise chain, fix param reassignment, suppress import/unambiguous for script files - Bump MailKit 4.15.0→4.15.1 to match MimeKit
…ethods - Make RoleBelongsToInstance, RoleTemplateBelongsToInstance, and PermissionBelongsToInstance static since they use no instance state - Replace foreach+if nesting with .Where()/.Select() across RAPS, CMS, CTS, Students, and shared components - Fix ViteProxy to correctly proxy /2/vue/assets/ paths - Add VueTableDefault unit tests and pre-filter skipColumns
- Use async APIs: RenderSectionAsync in layouts, ToListAsync/BeginTransactionAsync in services - Fix CS8604 nullability in ApiController sort helpers (null-forgiving after existing guard) - Fix CS8602 in LeftNav by removing unnecessary null-conditional operator - Specify DateTimeKind.Local for DateTime constructors in Offering and test setup - Suppress S3251 partial methods for EF scaffold files via scoped .editorconfig glob - Remove unused AssetHashRegex and dead constants from ViteProxyHelpers
- Replace throw new Exception with specific types (S112, 4 files) - Make GradYearClassLevel static with ImmutableArray (S1118/S3887/S2386) - Rename VwException → VwAaudExemption to avoid S2166 - Remove overlapping method signatures (S3427, 3 files) - Fix IndexOf > 0 → Contains, add [HttpGet], auto-properties - Merge duplicate test methods in ViteProxyHelpersTest (S4144)
- Modernize JS: strict equality, template literals, globalThis, named constants, destructuring, Object.hasOwn() guard - Extract populateErrorTarget helper to reduce nesting depth - Rename vueSetup.js → vue-setup.js for kebab-case compliance - Add oxlint-disable with reasons for intentional skips (max-params, prefer-await-to-then, new-cap, no-magic-numbers)
- Add process.exit(1) when oxfmt check fails in lint-any.js - Apply oxfmt formatting to 13 files that slipped through
- All 8 SPA entry files reduced to a single bootstrapSpa() call - bootstrapSpa guards against mounting on wrong path via VITE_VIPER_HOME - Jenkins pipeline updated to Node.js 24.14.0 - Updated README.md to reflect new versions
- Replace Moq/MockQueryable.Moq with NSubstitute/MockQueryable.NSubstitute across all 66 test files - Fix lint warnings: add missing await on async mock verifications, specify DateTimeKind.Local, remove unused variables - Use --artifacts-path in test runner for isolation from dev server - Fix EmailService.GetRequestContext to handle missing route data gracefully - Sort package.json scripts alphabetically and add clear-cache command
…appers - Eliminates runtime reflection and NU1903 vulnerability (GHSA-rvv3-g6hj-g44x) - Apache 2.0 licensed, no commercial license key required
…patterns - Add eslint-plugin-harlanzw with 10 Vue reactivity rules as warnings - Enable ESLint caching (--cache --cache-strategy content) for faster lint runs - Extract async onMounted callbacks into named functions across 15 components - Convert defineProps/defineEmits to type-based syntax and Pinia stores to setup API
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #120 +/- ##
===========================================
+ Coverage 26.31% 42.66% +16.34%
===========================================
Files 1027 802 -225
Lines 82761 48441 -34320
Branches 4560 4445 -115
===========================================
- Hits 21778 20665 -1113
+ Misses 60528 27285 -33243
- Partials 455 491 +36
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
…latest - Update EF Core 10.0.2→10.0.5, QuestPDF 2026.2.4, NLog, SonarAnalyzer, coverlet 8.0.1 - Update Vue 3.5.30, Quasar 2.18.7, @quasar/app-vite 2.5.2; drop vite override for @quasar/vite-plugin - Align CI workflow with Node.js 24 and .NET 10 - Refactor Mailpit script to auto-detect latest GitHub release and replace fkill with native process kill - Fix minor lint issues in site.js and CtsHome.vue
- Move HTTPS cert generation and proxy config behind command === "serve" so vite build skips unnecessary I/O and cert checks - Sanitize route values in EmailService logging to prevent log injection
…ver config - Cert generation warns instead of throwing, so builds succeed without dotnet CLI - Proxy routes declared unconditionally; HTTPS applied only when certs exist
Bundle ReportChanges will decrease total bundle size by 204.71kB (-8.13%) ⬇️. This is within the configured threshold ✅ Detailed changes
Affected Assets, Files, and Routes:view changes for bundle: viper-frontend-esmAssets Changed:
Files in
Files in
Files in
Files in
Files in
Files in
Files in
Files in
|
- Wrap large .Contains() calls with EF.Parameter() for OPENJSON translation - Replace N+1 loops with batched queries (EPA checks, competency counts, photo URLs) - Replace correlated .Any() subqueries with .Join() or pre-loaded ID sets - Add .AsNoTracking() to read-only queries missing it - Remove unnecessary .ToLower() in string comparisons (CI collation) - Set SQL Server compat level 130 so EF Core 10 generates optimal SQL - Enable ReadyToRun publishing for faster cold-start
- Disable AppendRuntimeIdentifierToOutputPath so R2R publish outputs to net10.0/publish/ matching Jenkins robocopy expectations - Run dotnet linter in parallel with frontend linters via async spawn - Enable compiler server and skip restore in dotnet format calls - Guard RAPS AuditLog against unexpected audit criteria parameters
|
@bsedwards I benchmarked the deployment on TEST and found some performance regressions due to the new parameterized collection changes: https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-10.0/whatsnew#improved-translation-for-parameterized-collection I fixed a bunch of queries and found some other EF improvements. Overall, the site should be faster than before. Need help testing the other areas of the VIPER2 system that I have not yet worked on and am not fully familiar with.
|
…ipts, and backend - Bump GitHub Actions to latest majors (checkout@v6, codeql@v4, codecov@v5) - Add --files-from support in lint scripts to avoid Windows ENAMETOOLONG - Replace string concatenation with StringBuilder in VMACSExport and IamApi - Remove redundant vitest imports (globals enabled) and fix test assertions - Enable capitalized-comments rule and disable numeric-separators-style in oxlintrc
bsedwards
left a comment
There was a problem hiding this comment.
I reviewed most of the backend changes. Next time I'd suggest breaking up changes this extensive into multiple PRs, e.g.
- .Net 10
- NodeJS 24
- Replacing Moq/Mapper
- Fixing warnings and implementing suggestions
- Linting

Summary
LTS upgrade bringing VIPER2 to .NET 10 + Node.js 24, with support through late 2028. Beyond the runtime bump, this branch replaces several libraries that had licensing, security, or governance concerns — and modernizes DX patterns across the stack.
OnConfiguring()to proper DI<script setup lang="ts">DX Improvements
Scrutor Auto-Registration
Replaced 18+ manual
AddScoped<IService, Service>()lines inProgram.cswith convention-based auto-discovery. New services matching the*Service/*Validatornaming pattern are registered automatically — no manual wiring needed.AutoMapper → Mapperly
Replaced AutoMapper (which had a high-severity DoS vulnerability and moved to a commercial license) with Mapperly, a compile-time source-generator mapper. Benefits:
IMapperinjection from ~15 service constructorsMoq → NSubstitute
Replaced Moq (abandoned since the SponsorLink incident) with NSubstitute across all 64 test files. NSubstitute is actively maintained by multiple contributors. Cleaner API — no
mock.Objectunwrapping, no.Setup()ceremony.Libman Build Optimization
Moved
libman restorefrom running on every build to a one-time pre-dev restore. Eliminates race conditions during concurrent builds and speeds up the inner dev loop.DbContext DI Pattern
Migrated 6 DbContext classes from
OnConfiguring()connection string hardcoding to properAddDbContext<T>()dependency injection inProgram.cs. TheOnConfiguring()pattern is deprecated in EF Core 10 in favor of constructor-injected options — aligning with ASP.NET Core's DI-first design.Vue Composition API
Migrated all 8 SPA entry points and layouts from Options API to
<script setup lang="ts">. Removed legacyv-cloakdirectives,this.$route/this.$router, andref()insidedata()anti-patterns.Build Warnings Cleanup
Reduced .NET build warnings from 125 → 25 (80% reduction). Fixed 21 critical nullability warnings (CS8603/CS8618/CS8604), 40 mechanical LINQ/style warnings, 22 low-risk warnings, 4
throw new Exception→ specific types, and 10 design/naming issues. Test project warnings dropped from 64 to 2.Linting & Formatting
bootstrapSpa()helper to DRY multi-SPA entry pointsPerformance
Vitest ~20% faster
Frontend test suite averages 16.1s (down from 20.2s). Environment setup ~27% faster.
Vite 8 with Rolldown
Build pipeline upgraded to Vite 8, powered by Rolldown (Rust-based bundler).
EF Core 10 JIT Improvements
Free server-side performance gains from better inlining and devirtualization in .NET 10.
EndsWith(char)SQL TranslationEF Core 10 now translates
EndsWith('R')char overloads to SQL — removed#pragma warning disable S6610suppressions from 4 Effort service files.Security
EntityFrameworkCore.Testing.MoqdependencySystem.Linq.Async— .NET 10 has built-inSystem.Linq.AsyncEnumerableBackend Tests
1,099 backend tests passing. 575 frontend tests passing.