Skip to content

feat(vip): VIP tiers + first-login pack + recurring tier gifts (#233, #234) - #98

Merged
AdaInTheLab merged 2 commits into
mainfrom
feat/vip-tiers-first-login-pack
May 29, 2026
Merged

AdaInTheLab merged 2 commits into
mainfrom
feat/vip-tiers-first-login-pack

Conversation

@AdaInTheLab

Copy link
Copy Markdown
Collaborator

Board items #233 and #234. Single PR over a shared "VIP tier" foundation, as discussed.

What this adds

A new spawn-driven VipPerksFeature (auto-discovered via the IFeature scan), plus an admin-assigned VIP tier on player records.

#233 — first-time-login pack

The first time a player ever spawns, a configured VIP-gift template is delivered straight into their inventory (items dropped at their feet via LivePlayerManager.GiveItemToPlayer, linked commands run with {entityId}/{playerId}/{playerName} substitution). One-shot, guarded by the new first_login_grants table (INSERT OR IGNORE on a PK = once-ever). No /vip step — per the "auto-deliver on spawn" decision.

#234 — recurring daily/weekly VIP gifts

Players carry a tier in the new player_metadata.vip_tier column; tier names are admin-editable in settings (no enum, no migration to add "VIP++"). On a (re)connect spawn, each tier-gift rule for that player's tier is materialized once as a repeatable vip_gifts row — then the existing GetPendingForPlayer + /vip claim flow drives the daily/weekly cadence. Players with no tier ("pleb") get nothing.

Why spawn-driven, not a scheduled sweep: a player must be online to claim a gift or receive items anyway, so doing the work on connect is idempotent across reconnects and avoids a background timer entirely.

Changes

Backend

  • Migration 012_vip_tiers.sql: player_metadata.vip_tier + first_login_grants
  • VipPerksFeature + VipPerksSettings (persisted JSON, VoteRewards pattern)
  • FirstLoginGrantRepository; VipGiftRepository.HasGiftByNameAndPeriod; PlayerMetadataRepository.SetTier/GetPlayerIdsByTierSetTier writes only vip_tier so it never clobbers a player's name colour / tag / notes (and Upsert leaves the tier alone)
  • VipPerksController (settings + tier list); tier route on PlayerMetadataController

Frontend

  • VIP tier dropdown in the player editor (replaces the "specific vip name" approach #234 flagged)
  • "VIP Perks" settings tab: tier list, first-login pack, tier-gift rules
  • api / types / i18n — en translated; other 7 locales get English placeholders (admin-only panel, fallbackLocale is en)

Tests

10 new repository tests, all green: tier set/clear + no-clobber both directions + by-tier query, first-login once-ever idempotency, has-gift-by-name-and-period.

Notes / follow-ups

  • A tier gift already assigned to a player persists if their tier is later removed (they keep the crate they had). Cleanup-on-tier-change can be a follow-up if desired.
  • Non-en locale strings are English placeholders pending translation.
  • Pre-existing ModEventBusTests fail locally with a LogLibrary BadImageFormatException (Unity reference assembly can't execute in the test host) — unrelated to this change; untouched here.

🤖 Generated with Claude Code

feat(vip): VIP tiers + first-login pack + recurring tier gifts (#233, #234)

Adds a spawn-driven VipPerks feature covering two board items:

  #233 — first-time-login pack: the first time a player ever spawns, a
  configured VIP-gift template is delivered straight into their inventory
  (items dropped at feet, linked commands run). Once-ever, guarded by the
  new first_login_grants table.

  #234 — recurring tier gifts: players carry an admin-assigned VIP tier
  (new player_metadata.vip_tier, admin-editable tier names in settings).
  On spawn, each tier-gift rule for that tier is materialized once as a
  repeatable vip_gifts row; the existing /vip claim flow then drives the
  daily/weekly cadence. No tier ("pleb") = nothing.

Spawn-driven rather than timer-driven: a player must be online to claim or
receive items anyway, so doing the work on connect stays idempotent across
reconnects without a background sweep.

Backend:
- migration 012: player_metadata.vip_tier + first_login_grants
- VipPerksFeature + VipPerksSettings (persisted JSON, VoteRewards pattern)
- FirstLoginGrantRepository; VipGiftRepository.HasGiftByNameAndPeriod;
  PlayerMetadataRepository.SetTier/GetPlayerIdsByTier (SetTier writes only
  vip_tier so it never clobbers name colour / tag / notes)
- VipPerksController (settings + tiers); PlayerMetadataController tier route

Frontend:
- VIP tier dropdown in PlayerEditDialog
- VIP Perks settings tab (tiers, first-login pack, tier-gift rules)
- api/types/i18n (en translated; other locales English placeholders)

Tests: PlayerMetadata (tier set/clear, no-clobber both ways, by-tier query),
FirstLoginGrant (once-ever), VipGift (has-by-name-and-period). 10 new, green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
@codecov

codecov Bot commented May 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.04545% with 7 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
frontend/src/views/SettingsView.vue 89.70% 7 Missing ⚠️

📢 Thoughts on this report? Let us know!

test(vip): frontend vitest coverage for VIP perks (#233, #234)

codecov/patch flagged the frontend changes (coverage is frontend-only via
vitest). Adds:
- api/vipperks.test.ts — full coverage of the new API module
- players.test.ts — setPlayerTier (encoded id, null-clear)
- PlayerEditDialog.test.ts — tier load on open + save wires setPlayerTier
- SettingsViewVipPerks.test.ts — renders the VIP Perks panel and exercises
  fetch / add+remove tier / add+remove tier-gift / save handlers

+20 tests (89 total green). SettingsView.vue 0% -> 47.6%; the new VIP perks
panel + handlers are the covered portion.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
@AdaInTheLab
AdaInTheLab merged commit 1b8217d into main May 29, 2026
3 checks passed
@AdaInTheLab
AdaInTheLab deleted the feat/vip-tiers-first-login-pack branch May 29, 2026 08:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant