feat(library): library-wide achievement sync and summary

Achievements were fetched only when a game detail page was opened, and a Steam error was stored as "no achievements" or "hidden". A background run after each library sync now fetches schemas and the unlocks of games with new playtime, one Steam call per second for all runs together, and never overwrites stored data on a Steam error. Adds GET /api/library/achievements/summary, achievement counts on GameDto and the public profile, and migration V7 (playtime_at_refresh).
This commit is contained in:
lobo committed 2026-09-25 10:13:31 +02:00
1 parent 86db6f7167
commit 9fd552a785
25 files changed
+1399 -95

No files matched your search

+8 -2
View File
@@ -19,12 +19,18 @@ To Be Played is split into three repositories:
filters and sorting. "Pile of Shame" summary with a random suggestion of what to play.
- **Picker**: up to 10 random backlog games for a time budget (IGDB normal time to beat), HIGH priority first, then
MEDIUM, then the rest. Games already shown can be excluded for a reroll.
- **Achievements**: after every library sync a background job fetches the achievement schema of each owned game
and the user's unlocks of each game whose playtime changed. One Steam call per second, so user requests keep half
of the rate limit; it stops after 3 Steam errors in a row or when Steam hides the achievements. A Steam error never
overwrites stored data. Summary: unlocked total, perfect games, average completion over started games, the 5
games closest to 100 %.
- **Playtime history**: one row per game and day, for the activity view and the "most played in the last two weeks"
dashboard banner.
- **Wishlist**: synced from Steam with store price and discount.
- **Time to beat**: story, extras and completionist hours from the IGDB API. Optional: without credentials the
feature is off and the rest works.
- **Public profile data**: totals, status counts, games in progress and finished games with rating. Readable only
- **Public profile data**: totals, status counts, games in progress and finished games with rating, perfect games
and average completion. Readable only
with a profile ticket issued by Auth. Never returns notes, priority or the Steam ID.
## Authentication
@@ -43,6 +49,7 @@ on normal endpoints; the profile ticket is accepted only by `GET /api/public/pro
| `PUT` | `/api/library/games/{appid}/status` (status only, keeps rating, notes, priority) | JWT |
| `POST` | `/api/library/sync` | JWT |
| `GET` | `/api/library/picker?maxMinutes=&count=&exclude=` | JWT |
| `GET` | `/api/library/achievements/summary` | JWT |
| `GET` | `/api/library/sync-status`, `/summary`, `/activity`, `/wishlist`, `/steam-profile`, `/games-count` | JWT |
| `GET` | `/api/public/profiles/library` | profile ticket |
| `GET` | `/api/stats/public` | public |
@@ -107,7 +114,6 @@ Runs unit, WebMvc, persistence and integration tests plus the ArchUnit rules. Ne
## Roadmap
- Mood filter for the picker (needs genres or themes from IGDB).
- Achievement summary per game and library-wide, "closest to 100 %".
- Sale alerts for wishlist games.
- Move `steam_adapter` DTOs out of `api`, then turn on strict module independence in ArchUnit.
- Fetch the public key from a JWKS endpoint in Auth instead of an environment variable.