Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
db5d796
Add sonar issues in code quality findings docs
devpro Jul 26, 2026
58686f8
Bump version 2.4.1
devpro Jul 26, 2026
372de12
Fix sonar warnings S2365, ASP0025 ×2, CA1862 ×2, CA1859 ×3, JS S2486
devpro Jul 27, 2026
b5c9768
Add list/thumbnail view toggle to inventory list pages
devpro Jul 27, 2026
27f1aef
Add Playwright smoke tests for the three import pages
devpro Jul 27, 2026
49b261a
Add Playwright smoke test for the reference-data admin page
devpro Jul 27, 2026
d180759
Add Playwright smoke test for the account/preferences page
devpro Jul 27, 2026
ba43822
Refine thumbnail grid: side margins + shape-aware column widths
devpro Jul 27, 2026
62b246e
Add bottom padding below the thumbnail grid
devpro Jul 27, 2026
64e7f1a
Fix time entry issue on mobile view
devpro Jul 27, 2026
4409313
Persist the list/thumbnail view as a per-device preference
devpro Jul 27, 2026
ba92c7b
Add the list/thumbnail view toggle to Wishlist and Watch Next
devpro Jul 28, 2026
064d096
Add generic import
devpro Jul 28, 2026
520c98e
Fix UI
devpro Jul 28, 2026
06e5477
Fix button on thumbnails
devpro Jul 28, 2026
1b3c728
Improve video game detail
devpro Jul 28, 2026
620cfaa
Share media items with another user
devpro Jul 28, 2026
c89eae2
Share car/house/health
devpro Jul 28, 2026
29e4825
Improve shared personal lists
devpro Jul 28, 2026
9a3aa40
Share collectibles and gears
devpro Jul 28, 2026
25798c9
Order tabs in sharing view
devpro Jul 28, 2026
fbfb328
Fix custom image display in wishlist
devpro Jul 29, 2026
1fd6848
Add test
devpro Jul 29, 2026
14fd026
UI title refresh improvement
devpro Jul 29, 2026
5fc8e8d
Fix 'RemoteNavigationManager' has not been initialized error
devpro Jul 29, 2026
42ecee2
Add Playwright tests
devpro Jul 29, 2026
8c69a84
Add playwright test for collection sharing
devpro Jul 29, 2026
cf96098
Remove tv show want to watch
devpro Jul 29, 2026
32d1201
Optimize tv show in watch next
devpro Jul 29, 2026
c40758b
Scoped change to the Watch Next thumbnail (grid) view for the TV show…
devpro Jul 29, 2026
df3df02
Update tv show status to current if new episodes appear
devpro Jul 29, 2026
a039397
Add movie rating from tmdb
devpro Jul 29, 2026
4e61434
Add ratings for other media types
devpro Jul 29, 2026
ceab4d7
Use openlibrary to get book rating
devpro Jul 30, 2026
f8d8569
Add doc for reference ratings
devpro Jul 30, 2026
9381be3
Admin select reference rating source
devpro Jul 30, 2026
bee098a
Increment 2 adding IMDB
devpro Jul 30, 2026
894f8be
Add explore for tv shows and movies
devpro Jul 30, 2026
a5a4d63
Add explore for video games and fix dismissal design
devpro Jul 31, 2026
0d03dd7
Clean db when tests run
devpro Jul 31, 2026
c38be22
Update health check endpoint to healthz
devpro Jul 31, 2026
6c1c2f5
Order import
devpro Aug 1, 2026
035b63a
Cosmetic code change
devpro Aug 1, 2026
146e858
Update min metacritic to 60 (instead of 70)
devpro Aug 1, 2026
3e42a63
Format md files with neatmd
devpro Aug 2, 2026
547207c
Improve md files
devpro Aug 2, 2026
d1abc19
Improve md
devpro Aug 2, 2026
22b13b0
Fix test file format
devpro Aug 2, 2026
5c553d9
Fix
devpro Aug 2, 2026
0e02237
FIx test with new health check endpoint
devpro Aug 2, 2026
de9a2ca
Explore fetch in database
devpro Aug 2, 2026
50bd3f6
Fix FindExternalIdsAsync
devpro Aug 2, 2026
fecf869
Enforce OMDb's daily quota with a replica-shared budget
devpro Aug 2, 2026
674183c
Refresh the stalest reference documents first, bounded per pass
devpro Aug 2, 2026
fc77e4b
Stamp the rating source on tenant items so recompute can do nothing
devpro Aug 3, 2026
fa6572f
Improve Playwright tests
devpro Aug 3, 2026
3a50920
Attemps scale and recompute
devpro Aug 3, 2026
3d90bba
Deleting a TV show now cascades to its episodes
devpro Aug 3, 2026
0e790b5
Add Playwright coverage for the Explore feature
devpro Aug 3, 2026
28f8089
Fix invalid md
devpro Aug 3, 2026
a8fdf40
Add IGDB as the default video game reference provider
devpro Aug 3, 2026
10434ec
Move to optional force to sync now and fix book issue
devpro Aug 4, 2026
63da11f
Fix line length
devpro Aug 4, 2026
fafbccb
Upsert on import based on ref id
devpro Aug 4, 2026
b6d5734
Fix/implement 404
devpro Aug 4, 2026
8d599f3
Fix invalid order
devpro Aug 4, 2026
c56549d
Add env var in ci for integration tests
devpro Aug 4, 2026
5496562
Improve reference import
devpro Aug 4, 2026
872f700
Update CI
devpro Aug 4, 2026
c9f39a7
Fix test depending on Open Library for book ref
devpro Aug 4, 2026
362c1d3
Search books by ISBN through every provider, and report provider fail…
devpro Aug 5, 2026
13a3c57
Stop stamping a reference as enriched when the spent OMDb quota skipp…
devpro Aug 5, 2026
df64aac
Let RAWG overwrite its own cover art again
devpro Aug 5, 2026
5e17d5e
Make Explore recognise the video games the owner already tracks again
devpro Aug 5, 2026
5d9a3aa
Stop Discogs' free-text search from burying the album being searched for
devpro Aug 5, 2026
a9f0045
Fix format in test file
devpro Aug 5, 2026
5cf7702
Let an Explore card open the title at the provider it was rated by
devpro Aug 6, 2026
d4ce0f6
Reach the video games a provider's own search can't find
devpro Aug 6, 2026
0ba5208
Rename env var for mobile test
devpro Aug 6, 2026
6ddad5a
Diagnose a failed e2e run, and stop the tests leaving data behind
devpro Aug 6, 2026
2709245
Make a refuel entry quick to add and its station a shared reference
devpro Aug 11, 2026
892b07e
Suggest a health entry's specialty and practitioner, fix the dropdown
devpro Aug 11, 2026
bee736d
Cover video game explore end to end, and the top-up nobody clicks
devpro Aug 12, 2026
ffe047d
Give a detail page a real cover, and quiet the chrome around it
devpro Aug 13, 2026
0c75cf5
Give the app one icon vocabulary
devpro Aug 13, 2026
9011e96
Stop the admin queue owning the top of every detail page
devpro Aug 13, 2026
9b8f5ee
Match a video game to its reference, and stop an edit from undoing it
devpro Aug 16, 2026
ba0d6fe
Identify a book by its author, and stop a link waiting on a rating
devpro Aug 17, 2026
0fe1bda
Store only aliases that name one work, and ask them before any provider
devpro Aug 17, 2026
0fbeb6f
Read the guide in one sitting, and a finding one paragraph at a time
devpro Aug 17, 2026
f98db0e
Switch back rawg as default provider for video games
devpro Aug 17, 2026
aa7a037
Show a game's key art at the size it was made for, and count the cove…
devpro Aug 17, 2026
e347e50
Use IGDB for tests
devpro Aug 17, 2026
2c3ff9c
Home.razor now wraps its whole body in @if (IsStillTheCurrentPage)
devpro Aug 17, 2026
3a74184
Fix admin video game/book provider picker defaulting to the first reg…
devpro Aug 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 6 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,12 @@ jobs:
dotnet-test-args: "--report-xunit-trx --coverage --coverage-output-format cobertura"
extra-vars: |
AllowedOrigins__0=5207
AllowedOrigins__1=7042
Features__IsScalarEnabled=true
Features__IsHttpsRedirectionEnabled=false
Infrastructure__MongoDB__ConnectionString=mongodb://localhost:27017
Infrastructure__MongoDB__DatabaseName=keeptrack_ci
Logging__LogLevel__Keeptrack=Debug
fossa-enabled: true
sonar-enabled: true
sonar-cpd-exclusions: "**/*.g.cs,**/*.generated.cs,**/src/WebApi.Contracts/Dto/*.cs,**/src/Domain/Models/*.cs,**/src/Infrastructure.MongoDb/Entities/*.cs"
Expand All @@ -89,6 +91,10 @@ jobs:
Tmdb__ApiKey=${{ secrets.TMDB_APIKEY }}
Rawg__ApiKey=${{ secrets.RAWG_APIKEY }}
Discogs__Token=${{ secrets.DISCOGS_TOKEN }}
GoogleBooks__ApiKey=${{ secrets.GOOGLEBOOKS_APIKEY }}
Omdb__ApiKey=${{ secrets.OMDB_APIKEY }}
Igdb__ClientId=${{ secrets.IGDB_CLIENTID }}
Igdb__ClientSecret=${{ secrets.IGDB_CLIENTSECRET }}
FIREBASE_APIKEY=${{ secrets.FIREBASE_APIKEY }}
FIREBASE_USERNAME=${{ secrets.FIREBASE_TESTUSERNAME }}
FIREBASE_PASSWORD=${{ secrets.FIREBASE_TESTPASSWORD }}
Expand Down
1,056 changes: 1,056 additions & 0 deletions AGENTS.md

Large diffs are not rendered by default.

981 changes: 1 addition & 980 deletions CLAUDE.md

Large diffs are not rendered by default.

158 changes: 124 additions & 34 deletions CONTRIBUTING.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<PropertyGroup>
<!-- edit this value to change the current MAJOR.MINOR.PATCH version -->
<VersionPrefix>2.4.0</VersionPrefix>
<VersionPrefix>2.4.1</VersionPrefix>
</PropertyGroup>

<Choose>
Expand Down
32 changes: 26 additions & 6 deletions Keeptrack.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,38 @@
<File Path=".gitignore" />
<File Path=".markdownlint-cli2.yaml" />
<File Path=".yamllint.yaml" />
<File Path="CLAUDE.md" />
<File Path="AGENTS.md" />
<File Path="CONTRIBUTING.md" />
<File Path="Directory.Build.props" />
<File Path="Directory.Packages.props" />
<File Path="Local.runsettings" />
<File Path="README.md" />
</Folder>
<Folder Name="/Solution Items/docs/">
<File Path="docs/automapper-removal-plan.md" />
<File Path="docs/backlog.md" />
<File Path="docs/code-quality-findings.md" />
<File Path="docs/igdb-api-notes.md" />
<File Path="docs/operations.md" />
<File Path="docs/plan-quick-add.md" />
<File Path="docs/playwright-e2e-tests-plan.md" />
<File Path="docs/prerender-flash-fix.md" />
</Folder>
<Folder Name="/Solution Items/docs/archived/">
<File Path="docs/archived/automapper-removal-plan.md" />
<File Path="docs/archived/plan-quick-add.md" />
<File Path="docs/archived/playwright-e2e-tests-plan.md" />
<File Path="docs/archived/prerender-flash-fix.md" />
<File Path="docs/archived/README.md" />
<File Path="docs/archived/reference-ratings-plan.md" />
<File Path="docs/archived/share-collections-plan.md" />
<File Path="docs/archived/testing-assessment.md" />
</Folder>
<Folder Name="/Solution Items/docs/findings/">
<File Path="docs/findings/blazor-ui.md" />
<File Path="docs/findings/by-design-and-gaps.md" />
<File Path="docs/findings/persistence-and-mapping.md" />
<File Path="docs/findings/providers.md" />
<File Path="docs/findings/README.md" />
<File Path="docs/findings/reference-matching.md" />
<File Path="docs/findings/sonar.md" />
<File Path="docs/findings/sync-explore-and-import.md" />
<File Path="docs/findings/video-game-matching.md" />
</Folder>
<Folder Name="/Solution Items/pipelines/" />
<Folder Name="/Solution Items/pipelines/azure-devops/">
Expand All @@ -35,11 +52,14 @@
<Folder Name="/Solution Items/scripts/">
<File Path="scripts/dedupe-matched-aliases.js" />
<File Path="scripts/firebase-user-role.js" />
<File Path="scripts/migrate-car-history-station.js" />
<File Path="scripts/migrate-house-schema.js" />
<File Path="scripts/migrate-is-owned-to-owned-versions.js" />
<File Path="scripts/migrate-poster-url-to-image-url.js" />
<File Path="scripts/migrate-videogame-to-embedded-platforms.js" />
<File Path="scripts/mongodb-create-index.js" />
<File Path="scripts/mongodb-install.sh" />
<File Path="scripts/unset-tvshow-want-to-watch.js" />
</Folder>
<Project Path="src/BlazorApp/BlazorApp.csproj" />
<Project Path="src/Common.System/Common.System.csproj" />
Expand Down
15 changes: 15 additions & 0 deletions docs/archived/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Archived documents

Finished work kept for provenance only.
Nothing here describes how the application currently behaves: `AGENTS.md` is the authority for that, and `docs/findings/` tracks open findings.
A document lands here once its plan has shipped, its migration has run, or its snapshot has been overtaken by the code.

Document | What it was | Why it is archived
---------------------------------|----------------------------------------------------------------------------------|-------------------
`automapper-removal-plan.md` | Plan to replace AutoMapper with Riok.Mapperly, and the licensing reason for it. | The migration shipped, Mapperly is the only mapper left.
`plan-quick-add.md` | Design for the one-tap Quick Add capture form. | Shipped as `BlazorApp/Components/QuickAdd`.
`playwright-e2e-tests-plan.md` | Original design of the Playwright e2e suite and its environment variables. | The suite exists, `CONTRIBUTING.md` documents the current `E2E_*` surface.
`prerender-flash-fix.md` | Investigation of the .NET 10 prerender double-render flash. | Fixed, the remaining code comments point back here for the reasoning.
`reference-ratings-plan.md` | Design of provider reference ratings, written when RAWG was the game provider. | Shipped, and the video game half was superseded by IGDB.
`share-collections-plan.md` | Design for sharing whole categories with other Keeptrack accounts. | Shipped as `ShareController`/`SharedWithMeController`.
`testing-assessment.md` | Snapshot of the test suite as of 2026-07-27. | A dated inventory, overtaken by the suite itself.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ RPL-1.5 is an aggressive copyleft license: using AutoMapper under it obligates K
Until this removal ships, Keeptrack relies on AutoMapper's commercial "Community" tier (free below $5M revenue), which keeps the project bound to a third party's licensing terms and enforcement mechanism (license keys).
AutoMapper 16.2.0 is currently the only non-permissive dependency in `Directory.Packages.props`; every other package is MIT, Apache-2.0, BSD-3-Clause or MS-PL.
Removing it therefore ends the last third-party licensing constraint on Keeptrack.
It is also a quality win: the `AllowNullDestinationValues = false` behavior has caused at least four documented production bugs (see CLAUDE.md and `docs/code-quality-findings.md`).
It is also a quality win: the `AllowNullDestinationValues = false` behavior has caused at least four documented production bugs (see CLAUDE.md and `docs/findings/`).

## Replacement choice

Expand Down Expand Up @@ -119,7 +119,7 @@ Each phase builds, passes the full test suite (including integration tests again
4. Delete `AutoMapperConfigurationTest` - its job is now done at compile time.
5. Escalate Mapperly's unmapped-member diagnostics (`RMG012`, `RMG020`) to errors in `.editorconfig`, so configuration drift fails the build the way the deleted test used to fail the run.
6. Update CLAUDE.md: rewrite the `AllowNullDestinationValues` gotchas for the new null-preserving semantics, and update the "Adding a new trackable item type" checklist (step 6 becomes "add a storage mapper and a DTO mapper").
7. Update `CONTRIBUTING.md` and `docs/code-quality-findings.md` where they reference AutoMapper.
7. Update `CONTRIBUTING.md` and `docs/findings/` where they reference AutoMapper.

## Out of scope

Expand Down
47 changes: 26 additions & 21 deletions docs/plan-quick-add.md → docs/archived/plan-quick-add.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ Three extraction refactors come first — they remove exactly the duplication **
4. `IOwnedCopyDto` + `OwnedVersionFields`

- New `src/WebApi.Contracts/Dto/IOwnedCopyDto.cs`:
CopyType, Price, AcquiredAt, Vendor, Reference. Implemented by OwnedVersionDto and VideoGamePlatformDto (identical existing members; precedent: IReferenceLinkedDto; no Mapperly impact — mappers map members, not interfaces).
CopyType, Price, AcquiredAt, Vendor, Reference.
Implemented by OwnedVersionDto and VideoGamePlatformDto (identical existing members; precedent: IReferenceLinkedDto; no Mapperly impact — mappers map members, not interfaces).
- New `src/BlazorApp/Components/Inventory/Shared/OwnedVersionFields.razor`:
params required IOwnedCopyDto Copy, optional EventCallback OnChanged (default no-op for Quick Add's nothing-persists-until-Save flow).
Body = Physical/Digital button pair + the four fields (invariant-culture decimal parsing included), keeping data-testid="version-*-input".
Expand All @@ -79,7 +80,9 @@ Three extraction refactors come first — they remove exactly the duplication **
Movie + TV show always visible; the other six tiles AND their forms inside `<AuthorizeView Policy="MemberOnly" Context="memberContext">` with the preview-account note in `<NotAuthorized>` (hiding is UX; the API enforces).
- Media forms (per-type markup local to the page, same convention as the list FormTemplates):
- Movie: Title, Year, "Watched on" (FirstSeenAt, default today for the "just saw it" scenario — visible and clearable, since prefilling marks it Seen), Rating.
- TV show: Title, Year. Book: Title, Author, Year, FirstReadAt default today. Album: Title, Artist, Year (Author/Artist feed Open Library/Discogs auto-resolution).
- TV show: Title, Year.
Book: Title, Author, Year, FirstReadAt default today.
Album: Title, Artist, Year (Author/Artist feed Open Library/Discogs auto-resolution).
- Video game: Title, Year, Platform `<select>` over VideoGames.VideoGamePlatforms; choosing a platform adds a VideoGamePlatformDto draft rendered via `<OwnedVersionFields Copy="...">` — no platform = unowned game.
- Movie/TvShow/Book/Album: "I own a copy" toggle revealing `<OwnedVersionFields>`; on save if toggled, `dto.OwnedVersions = [_ownedDraft]` (a bare Physical copy is legitimate).
Single POST carries the copy — no follow-up PUT.
Expand All @@ -88,28 +91,30 @@ Three extraction refactors come first — they remove exactly the duplication **

6. Quick Add page — record types

- Parent fetch on type selection via `CarApiClient/HouseApiClient/HealthProfileApiClient.GetAsync("", 1, 100)`, guarded by a per-type loaded flag.
- 0 parents → empty-state note linking to /cars / /houses / /health to create one; 1 → preselected silently (the common "my car" case);N → segmented button row.
- Below it: `<CarHistoryForm Entry=... ShowFuel/ShowElectric from the selected car's EnergyType/>`, `<HouseHistoryForm/>`, `<HealthRecordForm/>`. Selecting a parent stamps the Entry's parent id; Save disabled until a parent is selected.
- SaveRecordAsync → child client AddAsync → navigate /cars/{carId} / /houses/{houseId} / /health/{profileId}.
- Parent fetch on type selection via `CarApiClient/HouseApiClient/HealthProfileApiClient.GetAsync("", 1, 100)`, guarded by a per-type loaded flag.
- 0 parents → empty-state note linking to /cars / /houses / /health to create one; 1 → preselected silently (the common "my car" case);N → segmented button row.
- Below it: `<CarHistoryForm Entry=... ShowFuel/ShowElectric from the selected car's EnergyType/>`, `<HouseHistoryForm/>`, `<HealthRecordForm/>`.
Selecting a parent stamps the Entry's parent id; Save disabled until a parent is selected.
- SaveRecordAsync → child client AddAsync → navigate /cars/{carId} / /houses/{houseId} / /health/{profileId}.

1. Entry points + CSS
7. Entry points + CSS

- NavMenu.razor: first item inside `<AuthorizeView><Authorized>` (directly below Home): `<NavLink class="nav-link" href="add"><span class="nav-icon">+</span> Quick add</NavLink>`.
Verify + (U+FF0B) has default text presentation per the emoji gotcha; plain ASCII + is the safe fallback.
- Home.razor: stats variant gets a kt-home-cta "+ Quick add" primary button above the stat grid; the empty-state variant makes Quick Add the primary CTA, "Go to my movies" secondary.
- CSS: mostly reuse (.kt-stat-grid/.kt-stat-tile, .kt-form-card, row g-3 with col-6/col-12 mobile splits, segmented buttons).
New app.css is minimal: a .kt-quickadd block forcing the picker to 2 columns under 767px and a full-width Save button on mobile. Forms live in .kt-form-card on a page, not a modal.
No sticky save bar in v1 (forms are short) — note as follow-up.
- NavMenu.razor: first item inside `<AuthorizeView><Authorized>` (directly below Home): `<NavLink class="nav-link" href="add"><span class="nav-icon">+</span> Quick add</NavLink>`.
Verify + (U+FF0B) has default text presentation per the emoji gotcha; plain ASCII + is the safe fallback.
- Home.razor: stats variant gets a kt-home-cta "+ Quick add" primary button above the stat grid; the empty-state variant makes Quick Add the primary CTA, "Go to my movies" secondary.
- CSS: mostly reuse (.kt-stat-grid/.kt-stat-tile, .kt-form-card, row g-3 with col-6/col-12 mobile splits, segmented buttons).
New app.css is minimal: a .kt-quickadd block forcing the picker to 2 columns under 767px and a full-width Save button on mobile.
Forms live in .kt-form-card on a page, not a modal.
No sticky save bar in v1 (forms are short) — note as follow-up.

1. Playwright coverage
8. Playwright coverage

- Pages/QuickAddPage.cs page object + OpenQuickAddAsync() on Pages/PageBase.cs.
- QuickAddSmokeTest (E2E gate, cleanup via E2eFixture.ApiHttpClient):
a. Movie with owned copy — GUID-suffixed title, toggle copy + price, Save, assert landing on /movies/{id} with the copy in the Ownership section.
b. Car refuel — seed a car via API, single car auto-preselected, mileage/fuel/cost, Save, assert landing on /cars/{id} with the refuel row.
- MobileScreenshotTest: add /add (picker) and /add?type=movie (form) to the 390×844 capture list — the mobile-first acceptance check.
- Regression safety for the extractions: the existing Car/House/Health/Ownership/VideoGamePlatform smoke tests already cover the refactored surfaces — run them after each extraction step.
- Pages/QuickAddPage.cs page object + OpenQuickAddAsync() on Pages/PageBase.cs.
- QuickAddSmokeTest (E2E gate, cleanup via E2eFixture.ApiHttpClient):
a. Movie with owned copy — GUID-suffixed title, toggle copy + price, Save, assert landing on /movies/{id} with the copy in the Ownership section.
b. Car refuel — seed a car via API, single car auto-preselected, mileage/fuel/cost, Save, assert landing on /cars/{id} with the refuel row.
- MobileScreenshotTest: add /add (picker) and /add?type=movie (form) to the 390×844 capture list — the mobile-first acceptance check.
- Regression safety for the extractions: the existing Car/House/Health/Ownership/VideoGamePlatform smoke tests already cover the refactored surfaces — run them after each extraction step.

## Gotchas to respect

Expand All @@ -122,7 +127,7 @@ Three extraction refactors come first — they remove exactly the duplication **

- `dotnet build`; `dotnet test` (needs local MongoDB + `Local.runsettings`; Playwright self-skips without `E2E_ENABLED`).
E2E: `E2E_ENABLED=true dotnet test test/BlazorApp.PlaywrightTests/BlazorApp.PlaywrightTests.csproj` per the e2e-local-run-recipe memory / `CONTRIBUTING.md`.
Mobile review: `E2E_SCREENSHOTS=true` + `E2E_SHOTS_DIR` screenshot run, plus a manual pass of <https://localhost:5021/add> at 390px width.
Mobile review: `E2E_MOBILE_CHECK=true` + `E2E_MOBILE_DIR` screenshot run, plus a manual pass of <https://localhost:5021/add> at 390px width.
Manual regression: the three detail pages' add/edit modals and the game platform cards must behave identically after the extractions (same fields, date/time proxies, balance preview).

## Ready-to-use implementation prompt
Expand Down
Loading
Loading