Skip to content

V2 New features#462

Merged
devpro merged 44 commits into
mainfrom
feature/dotnet-10-0-7
Jul 14, 2026
Merged

V2 New features#462
devpro merged 44 commits into
mainfrom
feature/dotnet-10-0-7

Conversation

@devpro

@devpro devpro commented Jul 14, 2026

Copy link
Copy Markdown
Owner

No description provided.

devpro added 30 commits July 6, 2026 01:02
1. TMDB sync — ReferenceSyncBackgroundService runs in-process (no Kubernetes CronJob needed) every 24h, re-checking reference docs older than 3 days. It calls TMDB's cheap per-id /changes endpoint first and only does the expensive full re-fetch if something actually changed. Admins also get a "Sync now" button on the Reference Data admin page for an immediate forced check of everything.
2. Future/unaired episodes — excluded from the TV show detail page's episode checklist (same air-date filter Watch Next already used), so an announced-but-unaired season no longer shows checkboxes for episodes that haven't happened yet.
3. Unique TMDB id constraint — added to tvshow_reference/movie_reference/person_reference in mongodb-create-index.js (partial + unique, safe for older documents missing the field).
4. Watch Next movies — now excludes movies already marked watched, even if still flagged "want to watch" (that flag doesn't auto-clear on watch the way the TV Time import path does).
5. All emojis replaced — every color emoji sitewide (nav icons, home page pills, dropzone, dismiss button, etc.) swapped for plain symbols confirmed to have non-emoji default presentation (this caught a real bug: the old ⭐/👁 icons were never actually plain-text despite looking like it).
6. Renamed — "Best of" → Favorites, "Want to watch" → Watchlist, everywhere (buttons, list columns, forms, modals), no icons.
7. Watched flag — now green instead of yellow.
8. Favorites/Watchlist buttons — replaced the harsh solid blue/white btn-primary selected state with a soft accent-tinted pill, consistent in both themes.

One thing I caught along the way: registering the new background sync service made every integration test spin up its own host that fired live TMDB calls against shared test data. I gated it behind a Features:IsReferenceSyncEnabled flag (on by default, off in the test host) so tests stay deterministic — documented in CLAUDE.md along with the rest.
Phase 1 (storage boundary): Added Riok.Mapperly, created IStorageMapper<TModel,TEntity> + CommonStorageMappings (shared DateOnly<->DateTime UTC conversion), and 18 storage mapper classes in Infrastructure.MongoDb/Mappers/ (12 generated via [Mapper], CarHistoryStorageMapper hand-written for the bespoke Location/Fuel/Station flattening). Switched MongoDbRepositoryBase and all 18 repositories off IMapper, deleted the three *DataStorageMappingProfile classes.

Phase 2 (web boundary): Added IDtoMapper<TDto,TModel> + CommonDtoMappings (the ?? string.Empty fallback for nullable-DTO-to-required-model strings), 12 CRUD DTO mappers plus 8 one-directional Model→Dto mappers (WatchNext, Car/House metrics, the five reference-data types). Handled the one enum+nullability edge case (CarDto.EnergyType) with a hand-written null fallback wrapping a Mapperly-generated ByName enum conversion. Switched every controller off IMapper, deleted WebServiceMappingProfile.

Phase 3 (removal/hardening): Removed AddAutoMapper, the AutoMapper package everywhere, and AutoMapperConfigurationTest (its job is now a compile-time check). Escalated Mapperly's RMG012/RMG020 to build errors in .editorconfig. Updated CLAUDE.md, CONTRIBUTING.md, and docs/code-quality-findings.md to reflect the new null-preserving semantics and reframe the old AllowNullDestinationValues gotchas as historical.
@gitguardian

gitguardian Bot commented Jul 14, 2026

Copy link
Copy Markdown

️✅ There are no secrets present in this pull request anymore.

If these secrets were true positive and are still valid, we highly recommend you to revoke them.
While these secrets were previously flagged, we no longer have a reference to the
specific commits where they were detected. Once a secret has been leaked into a git
repository, you should consider it compromised, even if it was deleted immediately.
Find here more information about risks.


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

Comment thread scripts/align_table.js Outdated
process.exit(1);
}
const rows = fs
.readFileSync(path, 'utf8')
try
{
Guid jobId;
await using (var stream = e.File.OpenReadStream(MaxFileSize))

try
{
await using var stream = e.File.OpenReadStream(MaxFileSize);
_importResult = null;
try
{
await using var stream = e.File.OpenReadStream(MaxImportFileSize);
/// hundred rows complete well within a normal request.
/// </summary>
[HttpPost("car-history")]
[RequestSizeLimit(10_000_000)]
/// as an upsert. Runs in the background; poll <see cref="GetStatus"/> with the returned job id for progress.
/// </summary>
[HttpPost("tv-time")]
[RequestSizeLimit(50_000_000)]

public async Task<BookDetails?> GetBookDetailsAsync(string externalId, CancellationToken cancellationToken = default)
{
var work = await http.GetFromJsonAsync<OpenLibraryWorkResponse>($"{externalId}.json", cancellationToken);
/// twice is a no-op the second time, since every document already carries the id it was exported with.
/// </summary>
[HttpPost("import")]
[RequestSizeLimit(50_000_000)]
/// Fellowship of the Ring" (OL27513W). The year is the last such token, since it's always what trails
/// the day/month when both are present, and the only token when the date is a bare year.
/// </summary>
private static readonly Regex s_yearRegex = new(@"\b\d{4}\b", RegexOptions.Compiled);
devpro added 9 commits July 14, 2026 17:51
What I reviewed and how it shaped the plan:

From todo-blazor — I kept the Microsoft.Playwright.Xunit.v3 PageTest + plain xunit facts style, the page-object pattern (locators/actions split, WaitForReadyAsync, chained typed navigation), and the Kestrel-factory in-process hosting. I dropped Reqnroll/Gherkin (your project has both styles side by side, and the Gherkin one is roughly double the code for the same coverage) and the Metalama screenshot aspect (xunit v3's TestContext.Current.TestState gives failure detection in DisposeAsync for free).

Keeptrack-specific findings that drove the design:
- The login page is OAuth-popup-only (GitHub/Google), which Playwright can't automate — but POST /auth/callback accepts any verified Firebase ID token, so auth is programmatic: REST signInWithPassword (reusing the integration tests' AccountRepository), post the token, save the cookie as Playwright storage state. Every test starts signed in.
- By default the fixture creates an ephemeral admin user via the Firebase Admin SDK (Firebase__ServiceAccount is already required by the Blazor host, so no new secrets), seeds data over the REST API with the shared WebApi.Contracts DTOs, and populates references via the admin import endpoint with a synthetic in-memory fixture — the "look for a ref" smoke test then uses the "check for reference match" button, which never calls TMDB/Open Library, so the suite is fully deterministic with zero provider keys.
- Hosting both apps in-process hits a real gotcha: both src/WebApi and src/BlazorApp generate a global Program class, so the test project needs extern alias on the project references.
- The existing KestrelWebAppFactory gets extracted to a small test/Testing.Shared project (no duplicated logic, per the quality bar), parameterized so the e2e project can compose two instances with WebApi:BaseUrl injected.

Your mid-task additions are covered: every knob is an env var (E2E_ENABLED, E2E_TARGET_URL, E2E_READONLY, E2E_HEADLESS, E2E_SLOWMO_MS, E2E_TRACE, credentials, plus the standard app config pass-throughs — full table in the doc). Rider debugging needs no extra machinery: tests are plain xunit, Local.runsettings carries the variables, and in integration mode both apps run inside the test process, so a breakpoint in BlazorApp/WebApi source hits during a browser click.

The doc also covers the read-only mode semantics (mutating tests self-skip), an E2E_ENABLED guard so solution-wide dotnet test stays green, the Blazor Server prerender/circuit waiting gotcha, failure traces/screenshots, a dedicated CI job with browser caching, and a 4-phase implementation plan (foundation → smoke suite → CI → later types/admin/import).
…k, Car, House, Playlist, Song, VideoGame)

- Removed the racy finalItems.TotalCount.Should().BeGreaterThan(initialItems.TotalCount) assertion — it's a global count over a shared tenant, and other test classes (RefreshReferenceResourceTest, TvTimeImportResourceTest, etc.) create/delete items against the same endpoints concurrently for the same fixed test user, so a sibling's create+delete cycle can straddle the window and mask this test's own +1.
- Removed the now-dead initial GetAsync<PagedResult<TDto>>(...) call that only existed to capture the baseline count for that assertion.
- Kept (unchanged) the assertions that actually prove creation happened and do check their result: the by-id GetAsync<TDto> right after update (updated.Should().BeEquivalentTo(created)) and the list-presence check (firstItem.Should().NotBeNull() / firstItem.Title.Should().Be(...)) — both scoped by Id, so they're immune to concurrent siblings.

Left CarHistoryResourceTest and HouseHistoryResourceTest untouched — their TotalCount assertions are already scoped to a per-test unique CarId/HouseId, so no other test can share that filter value and they aren't actually racy.
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
C Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

💡 Need a hand with PR review? Try Gitar by Sonar!

@devpro devpro merged commit 0606309 into main Jul 14, 2026
7 of 8 checks passed
@devpro devpro deleted the feature/dotnet-10-0-7 branch July 14, 2026 20:52
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.

2 participants