Commit Graph
110 Commits
Author SHA1 Message Date
lobo 4d49b0f023 feat(library): soft delete removed games and add restore
Build, Test & Push Core Service / quality-check (push) Successful in 1m46s
Build, Test & Push Core Service / docker (push) Successful in 1m26s
Removed games could not come back (#39). Remove now sets removed_at
and restore clears it. V46 brings back PSN games removed before.
2026-10-11 09:52:11 +02:00
lobo 696e06e7fe fix(test): delete user_game_playtime_day rows in seed
Build, Test & Push Core Service / quality-check (push) Successful in 1m45s
Build, Test & Push Core Service / docker (push) Successful in 1m38s
RewardControllerTest leaves user_game_playtime_day rows for user 1,
affecting paceWeeks calculation. Delete them in seed() to ensure
clean test isolation.
2026-10-09 19:32:35 +02:00
lobo b24fd91e88 feat(rewards): pay early finish points and top-up on proof
Build, Test & Push Core Service / quality-check (push) Failing after 1m49s
Build, Test & Push Core Service / docker (push) Skipped
A linked PlayStation title no longer blocks. Its playtime never
proves a finish. An unproven Steam finish pays 10 early points,
the rest comes with proof. Back pay only from app.rewards.early-since.
2026-10-09 16:00:06 +02:00
lobo 7c4b475321 feat(rewards): add game points endpoint with reason codes
Frontend shows why a game earned no points after a status save.
Settle runs first. Rules and amounts are not changed.
2026-10-09 15:25:04 +02:00
lobo 4ed8a341af feat(library): use set total playtime in sort and stats
Sort, total playtime, most played, genres, moods and the public
profile use the set total of an entry, as the library card does.
New view user_game_entry_playtime (V45) is the one SQL rule.
2026-10-09 14:35:07 +02:00
lobo 1ff1e061c7 feat(library): show play per platform on game detail
Store PSN play per title. A PS title on a Steam row keeps its minutes.
Steam rtime_last_played now fills last played.
Dropped? questions read the newest PSN last played too.
2026-10-09 13:55:57 +02:00
lobo 413381d404 feat(library): show one entry per game in every list
Gitea #34 slice 2 of 3. Lists and stats count a set once.
V43 views map an entry to its editions and platforms.
Remove the hideDuplicates param; GameDto gets platforms[].
2026-10-09 11:31:11 +02:00
lobo 82d3b59165 feat(library): group same game across platforms into sets
One entry per game across platforms (Gitea #34, slice 1 of 3).
Same IGDB game is linked; a user can split one key off its set.
V42 keeps status, rating and notes per set; rewards pay once per set.
2026-10-09 10:57:23 +02:00
lobo 8e4c382563 feat(library): add source filter to owned games
A row matches when its own source, or the source of a listed
linked edition, is selected. The hidden view ignores the filter.
2026-10-09 10:03:05 +02:00
lobo 6cd92f3e83 feat(library): add question queue for open game decisions
Add open questions per game: Start it?, Finished?, Dropped?, Rate it?.
A "No" is saved in user_game_question (V41) and snoozes the question.
Account cleanup clears the new table too. Refs Gitea #32.
2026-10-09 09:31:48 +02:00
lobo 0ddb345a41 feat(psn): sync PlayStation trophies as achievements
Build, Test & Push Core Service / quality-check (push) Successful in 1m30s
Build, Test & Push Core Service / docker (push) Successful in 1m49s
Sets map by exact title id, else by name and platform.
Trophy gains count as achievements; platinum or all earned is perfect.
Max 30 PSN calls per run; trophy lists load only when changed.
Hidden trophies stay hidden (name and detail) until earned.
2026-10-08 09:18:15 +02:00
lobo f5ca7237a9 feat(psn): sync PlayStation titles in the library sync
Exact IGDB matches are added; unsure titles wait in a review import.
Playtime and last played come from PSN: summed per game, not editable.
PSN games give no Pile Points. Users with only a PSN link sync too
(V39 drops steam_id NOT NULL). Linking starts a sync, or schedules one
for the end of the cooldown. Inbox notes 2 days before the PSN link
ends and when it has ended.
2026-10-08 08:15:37 +02:00
lobo 7ac887ed5a feat(psn): link PlayStation account and import played games
Build, Test & Push Core Service / quality-check (push) Successful in 1m22s
Build, Test & Push Core Service / docker (push) Successful in 1m27s
The NPSSO is used once to get a refresh token; only that token is
stored, sealed with AES-GCM (SecretBox, key APP_PSN_TOKEN_KEY; no key
= feature off). One-time import of played PS4/PS5 titles through the
import pipeline as source PSN. Unlink keeps the games. One PSN call
per user at a time. IGDB search now sends UTF-8, so non-ASCII names
like "Yōtei" match again.
2026-10-07 13:30:48 +02:00
lobo e87f40bba0 feat(picker): add FRIENDS row from followed users
Backlog games a followed user finished or played >= 5 h. One game per
friend; strongest signal first (finished, then playtime). Requires an
active follow of a public profile that shows SUMMARY or STATUS. Skips
DROPPED games, blocked and deleted users, hidden and removed games.
2026-10-07 09:42:10 +02:00
lobo 117ff61730 feat(picker): add series and studio rows from IGDB credits
Build, Test & Push Core Service / quality-check (push) Successful in 1m22s
Build, Test & Push Core Service / docker (push) Successful in 1m36s
New V37 tables game_credit and game_credit_check store IGDB
collections and developer/publisher companies per game.
A scheduled job backfills existing games (250 per 30 s);
sync, import, manual add, merge and detail page refresh them.
SERIES row: next part of a collection the user played.
STUDIO row: backlog games from developers of top played games.
2026-10-06 20:22:53 +02:00
lobo 8dd398321c feat(picker): return rows of up to 3 games per source
Picker returns categories in fixed order: NEXT_UP, SIMILAR, LONGEST,
RANDOM, each with up to 3 games. Empty rows are left out.
Param `count` is removed; new optional `category` loads one row (reroll).
Budget and exclude apply to all rows; mood only to RANDOM.
SIMILAR takes the 3 most played games, one similar game each.
Remove PickMix.
2026-10-06 19:41:24 +02:00
lobo 867dc4c4d1 feat(follow): add user follows with activity inbox digest
Build, Test & Push Core Service / quality-check (push) Successful in 1m26s
Build, Test & Push Core Service / docker (push) Successful in 1m31s
2026-10-06 16:22:22 +02:00
lobo 2dba863c54 feat(stats): add owners endpoint to list users who own a game
Build, Test & Push Core Service / quality-check (push) Successful in 1m21s
Build, Test & Push Core Service / docker (push) Successful in 1m33s
2026-10-06 13:19:58 +02:00
lobo 7747bc7b8b feat(library): add hand-ordered backlog with next-up picker source
Build, Test & Push Core Service / quality-check (push) Successful in 1m25s
Build, Test & Push Core Service / docker (push) Successful in 1m29s
2026-10-06 09:06:51 +02:00
lobo 7b538b7f30 feat(library): exclude unreleased games from picker and pile
Build, Test & Push Core Service / quality-check (push) Successful in 1m22s
Build, Test & Push Core Service / docker (push) Successful in 1m34s
2026-10-05 20:33:25 +02:00
lobo 33b230ee91 feat(picker): mix similar, longest waiting and random picks
Build, Test & Push Core Service / quality-check (push) Successful in 2m37s
Build, Test & Push Core Service / docker (push) Successful in 1m45s
Picker slots rotate three sources: backlog games that share moods with
one of the top 5 played games, oldest first seen, and random. Each game
carries a reason (source, anchor game, first seen). Empty slots fall
back to random. Issue #28.
2026-10-05 16:13:19 +02:00
lobo 10b7dc2272 feat(account): reject tokens of blocked users and old roles
Build, Test & Push Core Service / quality-check (push) Successful in 1m23s
Build, Test & Push Core Service / docker (push) Successful in 1m30s
V32 stores the last role change per user, sent by Auth. A token
issued before that change, or of a blocked user, gets 401 within
about 30 s instead of working until it expires.
2026-10-04 20:09:22 +02:00
lobo 35b1db45e6 feat(sync): start Steam sync on visit when data is older than 20 h
A visit starts a background sync when the last successful sync is
older than 20 h; one try per hour, one sync at a time. Migration V31
adds last_success_at and login_sync_tried_at. The nightly sync skips
only users with a successful sync today after 23:00. games-count
returns syncStarted.
2026-10-04 19:05:23 +02:00
lobo a8e208321f feat(sync): record what each Steam sync changed
Build, Test & Push Core Service / quality-check (push) Successful in 1m17s
Build, Test & Push Core Service / docker (push) Successful in 1m28s
Allows dashboard to show what the last sync changed. Migration V30
creates sync_change and sync_result tables. Sync records additions,
removals, playtime, achievements, and status changes per game.
2026-10-04 11:36:09 +02:00
lobo 065048415c feat(library): add drill-down lists for stat numbers
Build, Test & Push Core Service / quality-check (push) Successful in 1m17s
Build, Test & Push Core Service / docker (push) Successful in 1m27s
The number and list share the same SQL query, so they cannot drift.
StatKey enum maps each statistic to its query, validation rules, and visibility.
StatGamesService reads games per key with 40-game pages; repositories share the
same set logic as the stat counts. Three endpoints open games: own library stats,
public profile stats (with ticket checks), and public landing-page stats (cached
10 min). Rewards track and bonus rows support drill-down too.
2026-10-03 18:51:59 +02:00
lobo 74cc8297ce feat(rewards): add 14 new shop items with twin backgrounds
Build, Test & Push Core Service / quality-check (push) Successful in 1m14s
Build, Test & Push Core Service / docker (push) Successful in 1m23s
Each page background gets a matching banner background. Tests verify
pairing, price constraints, and code length limits
2026-10-03 17:31:19 +02:00
lobo 8eab98df74 feat(rewards): unlock items by progress and skins
Build, Test & Push Core Service / quality-check (push) Successful in 1m11s
Build, Test & Push Core Service / docker (push) Successful in 1m27s
Five progress tracks: games finished, completed, weekly finish
streaks, pile-down months and play-more months. Settle books UNLOCK
rows once, also retroactively, when a track reaches an item's target.
12 unlock-only items (incl. the Steam skin) and 3 skins to buy. The
wallet returns progress; buying an unlock item answers NOT_FOR_SALE.
2026-10-02 15:40:46 +02:00
lobo bb8341dfef feat(library): undo auditor merges for 30 days, redirect old keys
Build, Test & Push Core Service / quality-check (push) Successful in 1m14s
Build, Test & Push Core Service / docker (push) Successful in 1m36s
V29 adds game_merge_undo and game_merge_undo_user: every new merge saves
a copy of what it changed. POST /api/library/merges/{mergeId}/undo
(auditors, newest merge first) puts it back; users keep later status
and rating, nothing is paid twice. A nightly job drops copies after 30
days. Old keys follow game_alias to the kept game. Manual games can now
be hidden and shown like Steam games.
2026-10-02 13:39:02 +02:00
lobo 44af19d32e feat(library): auditor catalog search and time to beat correction
GET /api/library/catalog finds any game a user has, by name, for
auditors; GET /api/library/catalog/{appid} loads it for the correction
dialog. New correction field TIME_TO_BEAT (normal + completionist,
1..60000 min, completionist >= normal) that survives the IGDB refresh.
Every correction and reset writes GAME_CORRECT / GAME_CORRECTION_RESET
to admin_audit.
2026-10-02 11:21:15 +02:00
lobo a2ea1e45d3 feat(audit): add audit log endpoint and display names from Auth
Build, Test & Push Core Service / quality-check (push) Successful in 1m14s
Build, Test & Push Core Service / docker (push) Successful in 1m20s
GET /api/library/audit-log for auditors and admins, paged, filter by
action. The account state push stores displayName in account_name so
the log shows names. Contract test updated.
2026-10-02 09:10:56 +02:00
lobo 221b5594c5 feat(library): count linked editions once in pile and stats
All game counts read the counted_user_game view, which keeps only the
most advanced edition of a linked set (older edition wins a tie). Add
the hideDuplicates filter to the library query.
2026-10-02 09:10:56 +02:00
lobo e806670d26 feat(library): add IGDB editions, game links and auditor queue
Tables game_edition (IGDB "same game" id per library key), game_link
(global sets set by auditors), game_link_pair (queue of IGDB and
requested pairs), game_link_request and account_name. Fetch IGDB
editions, link and unlink with audit rows, serve the paged auditor queue
with request counts. WireMock recordings for the editions query.
2026-10-02 09:10:56 +02:00
lobo a12ed20705 feat(rewards): add completed, background and banner effect items
Build, Test & Push Core Service / quality-check (push) Successful in 1m4s
Build, Test & Push Core Service / docker (push) Successful in 1m31s
2026-10-01 15:09:25 +02:00
lobo 349fa40272 feat(rewards): shop, equipped looks and public looks
Build, Test & Push Core Service / quality-check (push) Successful in 1m5s
Build, Test & Push Core Service / docker (push) Successful in 1m35s
Add endpoints to buy items, equip looks by slot and unequip. The shop has
8 whitelisted looks: avatar borders, badges, accents and banner frames.
Ownership is a BUY ledger row; PLATFORM_ADMIN owns every catalog item
without buying. The public profile endpoint shares only the equipped looks
filtered by ownership.
2026-10-01 13:17:04 +02:00
lobo 837dad8a6f feat(rewards): ledger, earning rules and nightly settle
New module rewards tracks Pile Points in an append-only ledger. A settle
derives rows from the status log, playtime days and achievements, once per
user, kind and game. The balance is the sum of all rows. Settle runs on
every wallet read and nightly at 02:30. The unique key (user_id, kind, ref)
makes every run idempotent. V26 also pays a one-time starter grant for
finishes from before the status log.
2026-10-01 13:15:04 +02:00
lobo 732970697d feat(stats): add PLATFORMS stat group and landing page statistics
Add PLATFORMS stat group to user stats: games and playtime per platform.
Add platforms, genres, and finished-per-year statistics to public stats
for the landing page.
2026-10-01 11:10:59 +02:00
lobo 216c1af62f feat(import): source values for exports and bookmarklet
Build, Test & Push Core Service / quality-check (push) Successful in 1m9s
Build, Test & Push Core Service / docker (push) Successful in 1m33s
2026-09-30 15:59:05 +02:00
lobo e347b7aac8 chore(security)!: refuse tokens without aud 2026-09-30 15:00:47 +02:00
lobo 23bf5c41b4 chore(library)!: drop the full-replace PUT of a backlog entry
The Frontend sends PATCH since item 27 batch 2.
2026-09-30 15:00:47 +02:00
lobo 34d64e7215 refactor: item 29 cleanup
C14 C16 C17 C18 C20 A11 A15 X10 X12 X15: dead Steam count code, GameNames, steamIdText, one query per game for the finished estimate, no API versioning config, open-in-view off, CORS from APP_FRONTEND_URL, non-root image, prune only up to the highest known id.
2026-09-30 15:00:47 +02:00
lobo 504c935b27 feat(account): Steam ID and blocked state from Auth (V25)
A blocked user gets no sync and leaves the landing stats. A new or removed Steam ID stops the nightly sync of the old one. No token check in Core: the token lives until it expires.
2026-09-30 15:00:47 +02:00
lobo 3512159b41 test: background work inline, shared mock bases, lock-wait instead of sleep
Build, Test & Push Core Service / quality-check (push) Successful in 1m8s
Build, Test & Push Core Service / docker (push) Successful in 1m31s
2026-09-30 12:08:57 +02:00
lobo 7fe2823519 refactor(library): detail page refreshes, then assembles 2026-09-30 12:08:57 +02:00
lobo 2c97e2ae96 refactor(library): two bounded background pools
Every @Async names a pool: with the scheduler there are two TaskExecutor beans, and a bare @Async ran on an unbounded executor. Page views queue only stale games; the long runs after a sync get their own pool.
2026-09-30 12:08:57 +02:00
lobo 9a09d535fc refactor(library): listed_user_game view and one shared schema (V24) 2026-09-30 09:37:16 +02:00
lobo b499e79c41 refactor(library): one IGDB split and merge for time to beat and moods 2026-09-30 09:37:16 +02:00
lobo c1472c7d59 refactor(library): own IgdbGame record, one owned rule, layer rules
Stored import candidates keep their JSON shape, so READY imports from before still read.
2026-09-30 09:37:16 +02:00
lobo 1abc03d2c1 refactor(library): auditor fields only through applyCorrection 2026-09-30 09:37:16 +02:00
lobo 79d7bf17f2 feat(library): PATCH backlog saves only the sent fields 2026-09-30 07:36:08 +02:00
lobo 73cfcb58e2 refactor(api): one error body, token audiences, contract fixture
Build, Test & Push Core Service / quality-check (push) Successful in 1m7s
Build, Test & Push Core Service / docker (push) Successful in 1m23s
2026-09-29 14:48:28 +02:00