Public Access
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.
This commit is contained in:
1 parent
732970697d
commit
837dad8a6f
28 files changed
+1470
-3
No files matched your search
@@ -57,6 +57,13 @@ To Be Played is split into three repositories:
|
||||
- **Status history**: a database trigger logs every status change of a library game in `user_game_status_change`
|
||||
(old and new status, time, whether the user chose it), whatever code path made it. It starts with V14; older
|
||||
changes are not known.
|
||||
- **Pile Points** (`modules/rewards`): users earn points for playing games off the pile, in an append-only ledger
|
||||
(`reward_ledger`, V26; the balance is the sum). No code path pays: a settle (on `GET /api/rewards/wallet` and
|
||||
nightly at 02:30, `app.rewards.settle-cron`) derives rows from the status log, playtime days, achievements and pile
|
||||
snapshots, once per user, kind and game (`ref`). Rules and numbers: `RewardRules`; a Steam finish needs playtime and one
|
||||
proof of fresh play (ending achievement or playtime around the finish, or half of the IGDB time played since the finish; old history pays nothing). The month bonus needs a finished game in that month. Games added by hand pay 15 for
|
||||
a finish, at most 3 per ISO week. The settle takes a per-user advisory lock. V26 also pays a one-time starter grant
|
||||
for finishes from before the status log.
|
||||
- **Wishlist**: synced from Steam with store price and discount.
|
||||
- **Broken image repair**: the frontend reports a Steam cover or achievement icon that does not load. At 01:30
|
||||
(Europe/Berlin) a job checks up to 200 reports. A cover that loads again is left alone; else the store's hashed
|
||||
@@ -114,6 +121,7 @@ ArchUnit role rules (`RoleAnnotationRules`) and `src/test/resources/contract/aut
|
||||
|
||||
| Method | Path | Auth |
|
||||
|---|---|---|
|
||||
| `GET` | `/api/rewards/wallet` (balance, catalog, owned, equipped, last 50 ledger rows with the game name) | JWT |
|
||||
| `GET` | `/api/library/games`, `/api/library/games/{appid}` | JWT |
|
||||
| `PATCH` | `/api/library/games/{appid}/backlog` (only the sent fields; `null` clears one) | JWT |
|
||||
| `PUT`, `DELETE` | `/api/library/games/{appid}/corrections/{field}` (`{value}`; `name`, `image`, `speedrun`, `moods`, `endless`, `genres`; `204`, `400 INVALID_CORRECTION`) | JWT, AUDITOR |
|
||||
@@ -165,6 +173,7 @@ flowchart LR
|
||||
Stats["stats"]
|
||||
Version["version"]
|
||||
Account["account"]
|
||||
Rewards["rewards"]
|
||||
Steam["steam_adapter"]
|
||||
Igdb["igdb_adapter"]
|
||||
Speedrun["speedrun_adapter"]
|
||||
@@ -173,6 +182,7 @@ flowchart LR
|
||||
LibService --> Speedrun
|
||||
end
|
||||
Browser -->|"tbp_access cookie"| Security
|
||||
Rewards --> Db
|
||||
Security -->|"JWKS by kid"| Auth["ToBePlayed-Auth"]
|
||||
Steam --> SteamApi["Steam Web API"]
|
||||
Steam -->|"HEAD"| SteamCdn["Steam CDN"]
|
||||
|
||||
Reference in new issue
Block a user