gamer147
5faa5e2445
feat(db): AddArenaTwoPick migration (rewards + viewer-run tables)
...
Register ArenaTwoPickRewards and ViewerArenaTwoPickRuns DbSets in SVSimDbContext and generate the AddArenaTwoPick migration with both CreateTable calls, all four jsonb columns on the run table, and the correct indexes (WinCount scalar + unique WinCount/RewardType/RewardId on rewards; unique ViewerId on runs).
2026-05-31 10:20:37 -04:00
gamer147
b78d7d6cbe
feat(packs): add PackDraw* tables and IsEnabled column
...
Three new EF entities and a migration:
- PackDrawConfigEntry (per-pack: animation rate, has-bonus flag, special-kind label)
- PackDrawSlotRateEntry (pack/slot/tier -> rate, unique index)
- PackDrawCardWeightEntry (per-card-rate facts incl rate-less rows)
DrawSlot {General, Eighth, Bonus} and DrawTier {Bronze, Silver, Gold, Legendary, Special}.
Special collapses leader_card and limited_time_leader (verified mutually exclusive per pack).
IsEnabled column on PackConfigEntry — admin gate for synthesized stubs, distinct from
the wire-mirror IsHide.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-30 21:40:50 -04:00
gamer147
75a2fca8bb
feat(db): StoryDeckEntry presentation table + StoryDeckKind enum
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-29 10:25:03 -04:00
gamer147
21adc68e28
feat(db): add gacha-point balance + received tables
2026-05-28 22:50:22 -04:00
gamer147
2034034c1b
feat(tutorial): add /tutorial/gift_top with hardcoded starter present list
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-28 12:02:54 -04:00
gamer147
7ef5f03eb3
feat(spot-card-exchange): /spot_card_exchange/{top,exchange} + SpotPoints currency
...
Final shop family. Schema additions:
- ViewerCurrency.SpotPoints (ulong) — new currency column on Viewers.
- SpotCardExchangeEntry — catalog (distinct from the pre-existing
SpotCardEntry, which is the /load/index rental-cost concept).
- ViewerSpotCardExchange — standalone composite-PK table tracking
(viewer, card, exchanged_at, is_pre_release_snapshot). Standalone
avoids cartesian-explode on viewer-graph reads.
RewardGrantService gains a SpotCardPoint=12 currency case mirroring
the RedEther/Crystal pattern. Doc comment refreshed; SpotCard=11 and
SpotCardOnlyLatestCardPack=13 remain unimplemented with explanatory
NotSupportedException — captures show emitters always use Card=5 with
the spot-card-specific id.
Controller:
- /top: emits exactly 9 clan buckets [{"1": [cards]}, ...] matching
prod's arbitrary single-key shape. exchange_status per-card (0=
available, 1=already-exchanged, 2=LimitOver after pre-release cap).
pre_relase_info WIRE TYPO PRESERVED ("relase" not "release").
- /exchange: server-authoritative price (client-supplied
exchange_point ignored); debits SpotPoints with post-state-total
reward_list entry; grants card via RewardGrantService.ApplyAsync
(cosmetic cascade included); persists ViewerSpotCardExchange row.
Insufficient points / already-exchanged / pre-release-limit all
return 400 without partial state.
LoadController now populates /load/index spot_point from
viewer.Currency.SpotPoints (was always 0).
PreReleaseLimit hardcoded to 2 matching capture; promote to GameConfig
when captures show variance.
504 tests pass (was 496; +8 spot-card-exchange tests).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-27 23:23:07 -04:00
gamer147
a5999a3e9c
feat(leader-skin): shop catalog + 5 endpoints (/products, /buy, /buy_set, /buy_set_item, /ids)
...
Schema: LeaderSkinShopSeries -> Products (owned rewards) + owned
SetCompletionRewards on the series; ViewerLeaderSkinSetClaim composite
PK (ViewerId, SeriesId) backs the /buy_set_item idempotent-claim check.
Importer mirrors SleeveShopImporter: idempotent find-or-create, owned
collections rewritten wholesale on rerun. 16 series, 104 products.
Controller (extends existing /set with 5 new endpoints):
- /products: dict-keyed-by-series_id-string wire shape. is_completed
per-viewer, rewards.status from ViewerLeaderSkinSetClaim (0=no set
sale, 1=available, 2=claimed) matching client RewardStatus enum.
- /buy: single skin, sales_type 1/2 dispatch, 3=>501.
- /buy_set: whole series at SetPrice; requires set_sales_status != 0;
grants every product's rewards (RewardGrantService idempotent on
already-owned cosmetics, so partial-set buys don't double-add).
- /buy_set_item: requires viewer owns every skin in series; idempotent
on re-claim (returns 200 + empty reward_list, not 400) so client
retries don't error.
- /ids: flat owned-skin-id list for badge refresh.
496 tests pass (was 486; +10 leader-skin-shop tests).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-27 22:55:09 -04:00
gamer147
559a170957
feat(item-purchase): /item_purchase/{info,purchase} + catalog
...
Schema: ItemPurchaseCatalogEntry (single table). Per-viewer quota tracked
via existing ViewerEventCounter keyed by "item_purchase:<id>" with period
JstPeriod.MonthKey when IsMonthlyReset else AllTime.
Controller:
- /info returns catalog + per-period rest (server-computed
max(0, PurchaseLimit - counter)) + user_card_pack_ticket_list (every
Items.Type==2 row joined to viewer count, zeros included — client
unconditionally UpdateItemNum's each entry).
- /purchase: sold_out check before currency check (no counter increment
on currency failure), inline TryDebit covers RedEther/Crystal/Rupy/Item
with post-state-total reward_list entry, grant via RewardGrantService.
Request `rest` accepted but ignored (server counter is canonical).
Importer mirrors PaymentItemImporter shape — idempotent find-or-create,
seed-missing rows preserved. 3 entries from the prod capture.
486 tests pass (was 476; +10 item_purchase tests).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-27 22:41:02 -04:00
gamer147
f237851e42
feat(sleeve): shop catalog + /sleeve/{info,buy} endpoints
...
Schema: SleeveShopSeries -> SleeveShopProducts -> Rewards (owned).
Migration AddSleeveShop creates 3 tables with FK cascade.
Importer mirrors BuildDeck pattern: find-or-create per series/product,
rewards replaced wholesale on rerun (owned collection). 10 series,
270 products imported from seeds/sleeve-shop.json.
Controller:
- /sleeve/info returns wire-faithful dict-keyed shape
({sleeve_list: {<series_id>: {product_info: {<product_id>: ...}}}}).
is_purchased_product derived from viewer.Sleeves.Contains(sleeve_id).
- /sleeve/buy: sales_type 0=free / 1=crystal / 2=rupy / 3=ticket(501).
Validates series_product mismatch, currency, already-purchased.
Currency debited with post-state-total reward_list entry; cosmetic
grants dispatched through RewardGrantService.ApplyAsync (covers
sleeve + emblem bundled grants per product).
476 tests pass (was 466; +10 sleeve tests).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-27 22:09:45 -04:00
gamer147
529fd13668
signup: close two concurrency holes from final review
...
(1) RegisterAnonymousViewer now catches the unique-violation
race (SQLSTATE 23505 on Postgres / code 19 on SQLite) and
re-reads by UDID, returning the existing row instead of
surfacing 500 to the second concurrent /tool/signup caller.
New repo test exercises the back-to-back register path.
(2) Add unique index on SocialAccountConnection (AccountType,
AccountId). The auth handler's find-or-link path claimed
this index existed as the dedup backstop; the claim was
accurate as design intent but the schema was missing. Now
matched. Comment in handler updated.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-27 14:46:19 -04:00
gamer147
ebba3c0eef
feat(missions): wire 6 entities into DbContext + AddMissionsAndAchievements migration
...
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-27 10:11:25 -04:00
gamer147
1420c60486
feat(bp): repositories + identity generation for runtime-inserted tables
...
Add ValueGeneratedOnAdd to ViewerBattlePassProgress.Id and
ViewerBattlePassClaims.Id so Postgres generates IDENTITY values at
runtime. Regenerate AddBattlePass migration in-place to include the
IdentityByDefaultColumn annotations. Add IBattlePassRepository /
BattlePassRepository (season lookup + level-curve cache) and
IViewerBattlePassRepository / ViewerBattlePassRepository
(get-or-create progress, claim reads/writes).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-26 22:40:45 -04:00
gamer147
3f784f4294
feat(bp): wire 4 new entities into DbContext + AddBattlePass migration
...
Adds DbSets and OnModelCreating config for BattlePassSeasonEntry,
BattlePassRewardEntry, ViewerBattlePassProgressEntry, and
ViewerBattlePassClaimEntry; generates migration 20260527021011_AddBattlePass
with DDL-only CreateTable + CreateIndex calls and no InsertData.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-26 22:12:55 -04:00
gamer147
9090086a47
Class leader fixes
2026-05-26 10:01:37 -04:00
gamer147
b6966ece6e
Prebuilt deck purchasing and fixes
2026-05-26 09:16:21 -04:00
gamer147
016efeea2c
DB Cleanup
2026-05-25 16:45:02 -04:00
gamer147
5e7a65fe5a
Story
2026-05-25 14:36:12 -04:00
gamer147
558e8288eb
Puzzles
2026-05-25 12:03:47 -04:00
gamer147
c14408ba06
Seeding reorg
2026-05-24 21:13:15 -04:00
gamer147
34bcc579a5
Additional card content
2026-05-24 17:07:05 -04:00
gamer147
d9ef9fe1fc
Pack logic cleanup
2026-05-24 09:27:10 -04:00
gamer147
79209bd70b
Pack opening
2026-05-24 02:03:13 -04:00
gamer147
21b97269ff
Practice battles work
2026-05-23 22:46:11 -04:00
gamer147
d3b2970e11
Deck list work
2026-05-23 19:57:34 -04:00
gamer147
56d3cf0ec8
Seeding updated
2026-05-23 16:25:49 -04:00
gamer147
6b70850b7b
More features
2026-05-23 14:18:01 -04:00
gamer147
b2024af852
Lots of data and model setup
2025-05-18 02:27:17 -04:00
gamer147
ee7e276036
Updates
2024-09-05 08:32:54 -04:00