Changelog — 2026-05-14

By ·

Changelog, so y'all can see everything that's been updated. This one is the last 7 days just to get us caught up, from here on out they will be daily.

Window: 2026-05-07T03:11:55Z → 2026-05-14T03:11:55Z (UTC) · Branch: main · PRs merged: 51

Features

#415 — feat(admin): bulk case-fix tool with leaderboard (#414)

by @jdooley-clt · 2026-05-07

Adds an admin tool to scan and bulk-correct improper casing in legacy free-text fields that predate the ProperCaseAttribute validator. The tool provides editable suggestions, enforces server-side validation to prevent invalid updates, and includes a leaderboard showing contributors with entries needing fixes. This improves data consistency and helps maintain clean, properly cased text across the platform without affecting user contribution scores.

#417 — Set imports: create PieceSet, fix undo data loss, fix history badge

by @jdooley-clt · 2026-05-07

Adds creation of a PieceSet when importing a set, linking new and existing pieces to the user's collection for better tracking. Fixes undo functionality to preserve pieces the user owned before import, preventing accidental deletions. Updates history and UI badges to accurately reflect set ownership status, improving clarity and reliability for users managing their collections.

#447 — feat(ci): Playwright smoke job on every PR (closes #426)

by @jdooley-clt · 2026-05-09

Adds a new GitHub Actions workflow that runs Playwright smoke tests on every pull request to main, ensuring critical UI functionality is verified early. Tests are retried up to two times on failure, with detailed tracing and artifacts collected for debugging. This improves test reliability and speeds up feedback for developers without impacting the main Windows-based build pipeline.

#520 — Epic #453: Set parity with ScaleModel

by @jdooley-clt · 2026-05-11

Adds full feature parity between Sets/PieceSets and ScaleModels/Pieces, making Sets first-class catalog entities with the same workflows, audit logging, manufacturer lookup, and ownership ergonomics. Developers and users benefit from streamlined management, including marking Sets complete, barcode display, cascading sale status from PieceSets to Pieces, and improved collection valuation that avoids double-counting MSRP. This update enhances consistency, usability, and data integrity across catalog and ownership models.

#527 — feat(pieces): show release year + prefer user image on hero (closes #472, #473)

by @jdooley-clt · 2026-05-11

Adds a release year display to the Piece detail view for better catalog information. Updates image selection logic to prefer user-uploaded images over inherited ScaleModel images on hero sections and QR-share landing pages, improving visual consistency and user control. Introduces a centralized helper for image resolution and ensures image ordering respects primary flags, aligning with project conventions.

#528 — feat(sets): allow a ScaleModel to belong to multiple Sets (closes #429, #430, #431, #432, #433, #434, #435)

by @jdooley-clt · 2026-05-11

Allows a ScaleModel to belong to multiple Sets instead of just one, enabling many-to-many relationships between models and sets. This change updates the database schema, services, APIs, and UI to support multi-set membership, improving flexibility for catalog management and import workflows. Developers benefit from enhanced data modeling and users see accurate multi-set membership displayed in details and edit views.

#534 — feat(content): Phase 0 — shared Markdown pipeline + media infra (blog wired)

by @jdooley-clt · 2026-05-11

Adds a shared Markdown rendering pipeline and media infrastructure to unify content processing across blog, gallery, and docs features. Introduces a custom YouTube shortcode that defers iframe loading to improve page performance and sanitizes HTML to prevent XSS risks. This foundation enables consistent, secure, and efficient content rendering while reducing future integration costs for new content types.

#538 — feat(blog): authoring toolbar + drag-and-drop image upload (closes #535)

by @jdooley-clt · 2026-05-12

Adds a formatting toolbar with keyboard shortcuts and drag-and-drop image upload to the blog Markdown editor, improving content authoring efficiency. Uploaded images are processed into responsive WebP derivatives with metadata stripped, optimizing load times and bandwidth without storing original files. The editor also supports inline YouTube embeds and displays accessible notifications for errors, enhancing usability and accessibility for authors.

#540 — feat(blog): add Blog Author role for non-admin contributors (closes #536)

by @jdooley-clt · 2026-05-12

Adds a new Blog Author role allowing non-admin users to create and edit their own draft blog posts while restricting publishing and scheduling to admins. This improves content workflow by enabling contributors to work independently without risking unauthorized publication changes. The update includes UI changes, audit logging, and safeguards to prevent authors from unpublishing live posts, enhancing both security and usability.

#574 — feat(docs): Docs / FAQ surface — long-form reference content (closes #532)

by @jdooley-clt · 2026-05-12

Adds a new Docs / FAQ section for long-form reference content like help guides, legal pages, FAQs, and release notes, replacing previously hard-coded views. It includes a public-facing site with organized landing, section, and detail pages, plus an admin interface for creating and managing content with Markdown support and slug uniqueness per section. This improves content management flexibility and user access to up-to-date documentation and legal information.

#576 — feat(profile): social media handles + author popup (#378)

by @jdooley-clt · 2026-05-13

Adds six social media handle fields to user profiles and displays them as icon links on public gallery pages, blog author popups, and dashboard widgets. Introduces an author popup modal on blog posts showing bio, location, website, social links, and other posts for better user discovery. Handles input normalization, privacy gating, and data cleanup to ensure consistent, secure, and private social link presentation.

#580 — feat(catalog): propose-change workflow for locked ScaleModel/Set rows (closes #558)

by @jdooley-clt · 2026-05-13

Adds a workflow allowing non-admin users to submit edit requests on locked ScaleModel or Set entries, with admins reviewing and approving or rejecting changes via a dedicated queue and side-by-side diffs. This ensures controlled edits while maintaining data integrity and audit trails. Developers benefit from a unified EditRequest entity, robust validation, and notification support, improving collaboration and content accuracy without compromising locked data.

#584 — feat(ci): automated daily PR changelog generator

by @jdooley-clt · 2026-05-14

Adds an automated daily changelog generator that collects all PRs merged into main in the past 24 hours, classifies them by type, and produces a Markdown summary uploaded as a GitHub Actions artifact. This helps developers quickly review recent changes without manual effort, improving visibility and release notes accuracy. The changelog is not auto-committed, allowing humans to decide when to include it in the repo.

Bug Fixes

#416 — Hotfix: restore BulkCaseFix value on AuditEntityType enum

by @jdooley-clt · 2026-05-07

Adds the BulkCaseFix value back to the AuditEntityType enum to fix a 500 error on the admin dashboard caused by Entity Framework failing to materialize historical audit log entries. This change preserves audit history and ensures the admin dashboard works without requiring data changes or migrations. The enum value is read-only and only exists to support loading legacy data.

#418 — Register ActivityFeedService in DI

by @jdooley-clt · 2026-05-07

Adds registration of ActivityFeedService to the dependency injection container to fix errors when accessing the CommunityController and its endpoints. This ensures that requests to /Community and related API calls no longer fail due to missing service resolution. The change improves application stability and reliability for users interacting with community feeds.

#419 — Fix EF sentinel-value warning on User notification columns

by @jdooley-clt · 2026-05-07

Removes the database default value of Immediate from four User notification frequency columns to fix an EF Core warning and prevent unintended overrides of user preferences. This ensures that when users explicitly set notifications to Off, their choice is correctly saved rather than silently reverted. The change improves data integrity and aligns database defaults with the application's property initializers.

#484 — fix(dashboard): isolate optional-widget failures from page render

by @jdooley-clt · 2026-05-10

Isolates failures in optional dashboard widgets so that if one widget fails to load, it no longer causes the entire dashboard page to return a 500 error. Optional widget data loads are now wrapped in a helper that logs errors and returns null on failure, allowing the dashboard to render gracefully without the affected widget. This improves user experience by preventing intermittent "Something Went Wrong" errors on first dashboard load after login.

#525 — fix(#521): repair Playwright Nightly tests after manufacturer typeahead refactor

by @jdooley-clt · 2026-05-11

Fixes Playwright Nightly tests broken by the manufacturer typeahead refactor by updating selectors to match the new hidden input and visible input fields. Resolves accessibility issues by adding aria-labels and aria-hidden attributes to distinguish multiple "Edit" links, improving screen reader navigation and test reliability. Also tightens Playwright locators with exact matching to prevent ambiguous element selection.

#543 — fix(pieces): close orphan /Pieces/Create code path

by @jdooley-clt · 2026-05-12

Closes an orphaned code path in the /Pieces/Create endpoint that allowed creating a Piece without a valid ScaleModel, which caused server errors. Now, requests missing or referencing unknown ScaleModel IDs are redirected with user-friendly messages, and invalid submissions are rejected with clear errors. This prevents confusing failures and ensures data integrity when creating Pieces linked to existing ScaleModels.

#577 — fix(gallery): move stat cards into empty right column on profile page

by @jdooley-clt · 2026-05-13

Moves the profile stats cards into the empty right column next to the avatar and bio on user gallery pages, reducing unused whitespace and improving layout on desktop. This change preserves all existing stats content and maintains responsive behavior on mobile. It enhances the visual balance of the profile page, making key user stats more accessible without altering any underlying functionality.

Security

#582 — security(ci): revoke Supabase-legacy public-schema grants from anon/authenticated

by @jdooley-clt · 2026-05-13

Revokes legacy public schema grants from the anon and authenticated roles to eliminate noisy security advisor errors without enabling row-level security. This cleanup aligns the CI environment with production defaults, improving security posture by removing unnecessary broad permissions. The migration is safe, idempotent, and irreversible to prevent reintroducing public write access.

#581 — security: drop overly-broad SELECT policies on storage.objects

by @jdooley-clt · 2026-05-13

Drops overly broad SELECT policies on storage.objects that allowed any authenticated or public user to list all files in the images and documents buckets. This prevents unauthorized enumeration of all uploaded files, improving data privacy without affecting public URL access or server-side operations. Developers should note that listing files via the REST endpoint is now restricted, reducing potential information leaks.

Refactoring

#420 — Add startup smoke test that resolves every controller from DI

by @jdooley-clt · 2026-05-07

Adds a startup smoke test that boots the full application host and attempts to resolve every controller through dependency injection. This catches missing service registrations during CI instead of at runtime, preventing production errors like the previously unregistered ActivityFeedService. The change improves reliability by validating the DI graph for controllers early without impacting production behavior.

#442 — Playwright CI: app lifecycle (closes #423)

by @jdooley-clt · 2026-05-08

Adds a CI-mode lifecycle for Playwright tests that ensures a clean, deterministic app state by introducing a non-interactive seed-and-exit command and a new PlaywrightCiFixture to manage app startup and teardown. It improves test reliability by carefully cleaning user data without affecting catalog tables and includes a local script to run the CI test flow outside GitHub Actions. This enables developers to validate end-to-end tests safely and consistently in CI environments.

Documentation

#575 — feat(docs): Content authoring docs sweep (closes #533, closes epic #529)

by @jdooley-clt · 2026-05-12

Adds comprehensive content authoring documentation covering the shared Markdown pipeline, image processing, shortcode usage, and authoring guidelines for blogs, albums, and docs. Introduces a new seeded Help page demonstrating the YouTube shortcode to aid developers in testing the rendering pipeline. This update clarifies security boundaries, shortcode extension processes, and storage layouts, improving developer onboarding and content authoring consistency without changing runtime behavior.

Tests

#441 — Playwright CI: storage-state auth fixture (#421)

by @jdooley-clt · 2026-05-08

Adds a Playwright authentication fixture that performs a single UI login and caches session cookies for reuse across tests, reducing test runtime by avoiding repeated logins. This approach ensures tests exercise the real login flow, maintaining reliability even if the backend environment changes. Developers benefit from faster, more stable integration tests that better simulate actual user authentication.

#446 — test(playwright): tag smoke-test subset with [Trait(Category=Smoke)] (#425)

by @jdooley-clt · 2026-05-09

Adds a [Trait("Category", "Smoke")] attribute to seven key Playwright tests, enabling a fast smoke test subset that runs in under 60 seconds during PR CI. This allows developers to quickly verify critical user flows without running the full, longer Playwright suite. The change improves test efficiency and provides clear documentation on smoke test criteria and usage.

#451 — test: fix Playwright nightly failures from #450

by @jdooley-clt · 2026-05-09

Fixes 39 nightly Playwright test failures by updating tests to match the redesigned ScaleModel and Piece schema. Tests incompatible with the new schema are skipped with detailed reasons, allowing the test suite to pass while full rewrites are planned. This improves test reliability and provides a clearer path for future test updates, ensuring developers can trust nightly runs and focus on ongoing schema changes.

#486 — test(playwright): disambiguate Create button matcher (fix nightly)

by @jdooley-clt · 2026-05-10

Adds exact matching to Playwright button selectors named "Create" to fix test failures caused by multiple buttons containing "Create" in their labels. This change prevents ambiguous matches in tests, ensuring reliable and stable UI automation. It is purely a test code update with no impact on application logic.

#542 — test(playwright): skip UI-coupled tests until GA — keep smoke suite

by @jdooley-clt · 2026-05-12

Skips all UI-coupled Playwright tests until the product reaches GA to reduce maintenance overhead caused by frequent UI changes. Retains a smaller smoke test suite to catch critical regressions during rapid pre-GA iteration. This allows developers to focus on stable backend logic while avoiding flaky UI test failures until the interface stabilizes.

Chores

#443 — ci: scaffolding for dedicated test Supabase project (#422)

by @jdooley-clt · 2026-05-08

Adds scaffolding for a dedicated Supabase project used in CI to run Playwright integration tests. This includes scripts for provisioning the test database, managing GitHub secrets securely, and a detailed operator runbook. These changes improve test environment reliability and security by isolating test data and automating setup, benefiting developers by enabling consistent, safe integration testing without risking production or development data.

#445 — ci: add actionlint workflow for .github/** changes

by @jdooley-clt · 2026-05-09

Adds a new GitHub Actions workflow that runs actionlint on any changes to files under the .github directory. This ensures YAML syntax, shell script quality, and action inputs are validated on PRs before merging, closing a previous CI gap for local composite actions. Developers benefit from faster feedback and fewer runtime errors in GitHub workflows and actions.

#444 — ci: cached Playwright browser setup composite action (#424)

by @jdooley-clt · 2026-05-09

Adds a reusable GitHub Actions composite action that caches the Playwright browser binaries based on the test project's .csproj file hash. This caching avoids repeated 2-minute downloads on CI runs unless the Playwright package version changes, significantly speeding up test workflows. The action currently supports Linux runners only and includes input validation and fail-fast checks to ensure reliable caching behavior.

#488 — chore: clear all build warnings (NU + CS)

by @jdooley-clt · 2026-05-10

Clears all build warnings by updating dependencies and refining nullability annotations, improving code quality and maintainability. Upgrades HtmlSanitizer and WebPush packages to remove security advisories and framework warnings. Adjusts a generic async loader method to better capture nullability at call sites, eliminating related compiler warnings without changing runtime behavior.

#489 — chore: QOL quick fixes (stray brace, /Sets clear-X, audit-log username fallback)

by @jdooley-clt · 2026-05-10

Removes a stray brace causing rendering issues and adds a clear (×) button to the Sets search input for better usability. Fixes audit-log display to show usernames instead of the default "User" for uncustomized accounts, improving clarity and encouraging users to set unique display names. Also includes a JavaScript fix to ensure filters reset properly when clearing search inputs, plus added tests to prevent regressions.

#523 — chore: ignore local body-draft scratch files (.git-commit-msg.tmp, .issue-body.tmp.md)

by @jdooley-clt · 2026-05-11

Ignores local temporary scratch files used for composing multi-line commit messages and issue bodies, such as .git-commit-msg.tmp and .issue-body.tmp.md. This prevents these files from appearing in git status and cluttering the working directory. The change improves developer workflow by keeping the workspace clean during commit and issue creation.

Other

#439 — Fix GitHub issue prefill to use exact 'User Feedback' label name

by @jdooley-clt · 2026-05-08

Fixes the GitHub issue prefill URL to use the exact label name "User Feedback" instead of a slug version. This ensures that new issues created via the admin feedback page are correctly labeled, improving issue organization and tracking. Historical issues have also been retroactively labeled to maintain consistency.

#448 — Fix AppServerFixture stdout/stderr pipe deadlock (#440)

by @jdooley-clt · 2026-05-09

Fixes a deadlock in AppServerFixture caused by unconsumed stdout/stderr pipes filling the OS buffer when running dotnet processes. The change drains output asynchronously and captures recent logs to include in timeout errors, improving reliability and debuggability of tests that spawn apps. Developers and CI environments benefit from more stable test runs and clearer failure diagnostics.

#449 — Add nightly Playwright full-suite workflow (#427)

by @jdooley-clt · 2026-05-09

Adds a new GitHub Actions workflow that runs the full Playwright test suite nightly and on every push to main, complementing the existing smoke tests. This ensures comprehensive end-to-end test coverage without slowing down pull request validation. Failures automatically create or update a tracking issue and notify via Slack, improving visibility and triage of test regressions.

#487 — Image upload caps (25/Piece, 10/ScaleModel) + per-user rate limit + UI hints

by @jdooley-clt · 2026-05-10

Adds per-entity image upload limits of 25 images per Piece and 10 per ScaleModel to prevent excessive uploads and orphaned storage blobs. Replaces the global IP-based rate limit with a per-user sliding window policy to better manage upload traffic and reduce abuse. The UI now disables the upload button and shows contextual hints when limits are reached, improving user experience and accessibility.

#490 — Add Lionel manufacturing era badge to ScaleModels and Pieces

by @jdooley-clt · 2026-05-10

Adds a Lionel manufacturing era badge to ScaleModels and Pieces based on the model's release year, visible in detail views, index cards, and filter dropdowns. This enables developers and users to search and filter Lionel models by historical manufacturing eras, improving cataloging and discovery. Accessibility improvements ensure screen readers announce the full era range, enhancing usability for all users.

#491 — Admin: notify model creator from /ScaleModels/Details

by @jdooley-clt · 2026-05-10

Adds an admin-only "Notify Creator" button on the ScaleModels details page that lets admins send private notifications to the user who created the model. This enables quick communication for issues like missing citations or typos without leaving the page. Notifications are validated, capped in length, and include a deep link to the model, improving admin workflow and creator engagement.

#492 — Add optional label to documents

by @jdooley-clt · 2026-05-10

Adds an optional, human-friendly label to uploaded documents that appears as the primary heading in document lists, improving clarity and usability. Labels are trimmed, truncated to 60 characters, and stored in the database, with audit logs updated to include the label for better traceability. This enhancement helps users quickly identify documents by meaningful names instead of just filenames.

#493 — Add Lionel Eras reference page

by @jdooley-clt · 2026-05-10

Adds a public Lionel Eras reference page explaining each era badge with descriptions and year ranges, improving user understanding of Lionel manufacturing history. Era badges now link directly to their explanations, enhancing navigation and context. Introduces a new ReferenceController for hosting glossary pages and includes a unit test to ensure all eras have descriptions, preventing missing information.

#499 — AGENTS.md: add step 12 (offer local smoke tests after PR open)

by @jdooley-clt · 2026-05-10

Adds a new mandatory step to the PR review workflow that requires developers to provide 2-3 specific local smoke tests after opening a pull request. This ensures that changes are manually verified across different scenarios before merging, improving code quality and reducing the risk of regressions. The update is documented in the workflow guides and applies to all feature PRs except those with no testable changes.

#522 — Sets parity follow-up: cascade ForTrade symmetric with ForSale (#514)

by @jdooley-clt · 2026-05-11

Adds cascading status updates for PieceSets marked ForTrade, matching existing behavior for ForSale. When a PieceSet transitions into or out of ForTrade, member Pieces now update their status accordingly, preventing inconsistencies between the set and its pieces. This ensures marketplace listings remain synchronized and accurate, improving data integrity and user experience.

#524 — Fix Sets purchase price rollup in Total Inventory Cost (#367)

by @jdooley-clt · 2026-05-11

Fixes the Total Inventory Cost and Replacement Value calculations to correctly include purchase prices set at the PieceSet level instead of summing only member pieces. This ensures that sets with an explicit purchase price are counted accurately on the dashboard, preventing undercounting when individual pieces have zero prices. The change aligns filtering and reporting logic so that dashboard counts and click-through lists consistently reflect missing or present financial data for sets and pieces.

#539 — Harden IsValidImageFile with magic-byte sniffing (#537)

by @jdooley-clt · 2026-05-12

Adds strict magic-byte sniffing to image file validation, replacing the insecure extension and Content-Type header checks. This prevents attackers from uploading disguised malicious files by ensuring the file bytes match the claimed image format before storage. The change improves security and consistency by enforcing correct content types and extensions, while maintaining compatibility with existing HEIC uploads and improving content-type accuracy in Supabase storage.

#545 — Albums feature (#531 slices 1-3): public + admin gallery system

by @jdooley-clt · 2026-05-12

Adds a new Albums feature for curated photo and video collections with admin authoring and public viewing. Albums support visibility controls (Draft, Unlisted, Public), cover images, Markdown descriptions with YouTube shortcodes, and item ordering. This enables admins to create rich multimedia galleries, improving content organization and presentation for users while maintaining strict access and rate limits.

#578 — Make Barcode required on ScaleModel for Mark Complete, mirror MsrpNotApplicable

by @jdooley-clt · 2026-05-13

Adds a required Barcode field to ScaleModel’s Mark Complete step, improving data completeness. Introduces a "No Barcode Used" opt-out checkbox for legitimate exceptions, mirroring the existing MSRP opt-out pattern. This change ensures accurate validation and audit logging while allowing flexibility for models without barcodes.

#583 — Add BarcodeNotApplicable to Set (Sets parity with ScaleModel)

by @jdooley-clt · 2026-05-14

Adds a "No Barcode Used" flag to Sets, allowing them to be marked complete without requiring a barcode, matching existing behavior in ScaleModels. Fixes a bug in propose-change modals where unchecking this flag couldn't be submitted, improving edit proposal accuracy. These changes help authors accurately represent sets without barcodes and ensure completeness validation works correctly during edits.


Generated 2026-05-14T03:11:55Z UTC by scripts/generate-changelog.ps1. Summaries: github-models (openai/gpt-4.1-mini).