PAR-35
Remove firm_players defer to treasury
Both Treasury and Business store overlapping player data (login times, UUID↔name mapping) in separate tables. Consolidate into one economy_players table and backfill.
Technical notes — Business owns firm_players (FirmPlayerMapper: uuid↔name cache, touched by FirmPlayerCreationEventListener on login); Treasury owns player_login_times (PlayerLoginMapper: last-login epoch). Neither stores both. Add an economy-schema migration (V<n>__economy_players.sql — schema changes go there) for a unified economy_players(player_uuid_bin, current_name, name_lower, first_seen, last_seen, last_login_epoch); point both mappers at it (Treasury owns the writer, business reads), then drop the old tables. Cross-plugin coordination required.
Resources
- PR#2 Last major release ParadauxIO/hibernia-economy
- commitde3fd14 Show a firm's proprietor on the explorer firm page (PAR-208)ParadauxIO/hibernia-economy
- commitbaa372c Remove the /tax trigger balance test commandParadauxIO/hibernia-economy
- commitd75f957 Drop legacy firm_players & player_login_times in V19 (PAR-35)ParadauxIO/hibernia-economy
- commit4d62b8f economy_players cutover phase 6: single owner for the login clock (PAR-35)ParadauxIO/hibernia-economy
- commita76e1b5 economy_players cutover phase 5: Business defers player directory to TreasuryParadauxIO/hibernia-economy
- commitcd1865b Migrate treasury sales customer-name join to economy_players (PAR-35, phase 4)ParadauxIO/hibernia-economy
- commit0abd7dd Migrate explorer name resolution to economy_players (PAR-35, phase 3)ParadauxIO/hibernia-economy
- commitbd3ce2a Migrate rest-api name resolution to economy_players (PAR-35, phase 2)ParadauxIO/hibernia-economy
- commit2dfa9ba Harden economy_players write path for the cutover (PAR-35, phase 1)ParadauxIO/hibernia-economy
Comments
tesks · Jun 4, 2026, 9:56 AM
Code context — Two overlapping tables in the shared economy schema: business's firm_players (FirmPlayerMapper: uuid↔name cache, touched by FirmPlayerCreationEventListener on login) and Treasury's player_login_times (PlayerLoginMapper: last-login epoch). Neither stores both.
Approach: new economy-schema migration (V<n>__economy_players.sql — schema changes go there) for a unified economy_players(player_uuid_bin, current_name, name_lower, first_seen, last_seen, last_login_epoch); point both mappers at it, Treasury owns the writer, business reads, then drop the old tables. Cross-plugin coordination required.
tesks · Jun 11, 2026, 11:21 AM
Migration sizing — economy_players consolidation (prod data, 2026-06-11)
Ran the row-count / overlap analysis against the prod economy DB.
Counts
| Metric | Value |
|---|---|
firm_players rows | 109,663 |
player_login_times rows | 109,236 |
| Overlap (UUID in both) | 109,206 |
Only in firm_players | 457 |
Only in player_login_times | 30 |
Distinct union (final economy_players row count) | 109,693 |
Reconciliation checks out: 109,206 + 457 + 30 = 109,693.
Superset / backfill direction
firm_players is effectively the superset and the richer table — it carries every identity column the unified schema needs (current_name, name_lower, first_seen, last_seen), while player_login_times only adds last_login_epoch (no name/timestamp data). So:
- Base the unified table on
firm_players(covers 109,663 of 109,693 = 99.97%). - Backfill
last_login_epochonto it fromplayer_login_timesfor the 109,206 overlap rows. - 30 rows exist only in
player_login_times(have alast_login_epochbut no name/first_seen/last_seen) — these needcurrent_name/name_lower/first_seen/last_seenleft NULL or sourced elsewhere (e.g. Mojang/usercache). Decide the unified schema's nullability for these 30 before migrating. - 457 rows exist only in
firm_players— they get NULLlast_login_epoch(never recorded by Treasury). The unified schema must allowlast_login_epochNULL.
Schema-design implications for V<n>__economy_players.sql
last_login_epochmust be nullable (457 rows have no login epoch).current_name/name_lower/first_seen/last_seenmust tolerate NULL or the 30 login-only rows must be enriched before/at backfill.- PK
player_uuid_binis consistent across both tables (both PK on it), so no dedup logic needed beyond the UNION.
Recommended backfill (single-pass, after the migration creates economy_players)
-- 1. seed from firm_players (the richer/superset table) — 109,663 rows
INSERT INTO economy_players
(player_uuid_bin, current_name, name_lower, first_seen, last_seen, last_login_epoch)
SELECT fp.player_uuid_bin, fp.current_name, fp.name_lower,
fp.first_seen, fp.last_seen, plt.last_login_epoch
FROM firm_players fp
LEFT JOIN player_login_times plt
ON plt.player_uuid_bin = fp.player_uuid_bin;
-- 2. add the 30 login-only rows (name/timestamps NULL)
INSERT INTO economy_players
(player_uuid_bin, current_name, name_lower, first_seen, last_seen, last_login_epoch)
SELECT plt.player_uuid_bin, NULL, NULL, NULL, NULL, plt.last_login_epoch
FROM player_login_times plt
LEFT JOIN firm_players fp ON fp.player_uuid_bin = plt.player_uuid_bin
WHERE fp.player_uuid_bin IS NULL;
Expected final count: 109,693 rows.
Next step
Sizing is small and clean (sub-110k rows, 99.97% covered by firm_players, only 30 edge rows) — no scaling concern, safe for a single-transaction Flyway migration. Open decision before writing the migration: whether to leave the 30 login-only rows' name/timestamp columns NULL or enrich them. Once that's settled, the V<n>__economy_players.sql migration + the two backfill statements above can be written, then re-point both mappers (Treasury writes, Business reads) and drop the old tables.
Activity
- ParadauxIO linked a pull request — PR #2 open — Last major release
- ParadauxIO linked a pull request — PR #2 open — Last major release
- ParadauxIO linked a pull request — PR #2 open — Last major release
- ParadauxIO linked a pull request — PR #2 open — Last major release
- ParadauxIO linked a pull request — PR #2 open — Last major release
- ParadauxIO linked a pull request — PR #2 open — Last major release
- ParadauxIO linked a pull request — PR #2 open — Last major release
- ParadauxIO linked a commit — Commit de3fd14 — Show a firm's proprietor on the explorer firm page (PAR-208)
- ParadauxIO linked a commit — Commit baa372c — Remove the /tax trigger balance test command
- ParadauxIO linked a commit — Commit d75f957 — Drop legacy firm_players & player_login_times in V19 (PAR-35)
- ParadauxIO linked a commit — Commit 4d62b8f — economy_players cutover phase 6: single owner for the login clock (PAR-35)
- ParadauxIO linked a commit — Commit a76e1b5 — economy_players cutover phase 5: Business defers player directory to Treasury
- ParadauxIO linked a commit — Commit cd1865b — Migrate treasury sales customer-name join to economy_players (PAR-35, phase 4)
- ParadauxIO linked a commit — Commit 0abd7dd — Migrate explorer name resolution to economy_players (PAR-35, phase 3)
- ParadauxIO linked a commit — Commit bd3ce2a — Migrate rest-api name resolution to economy_players (PAR-35, phase 2)
- ParadauxIO linked a commit — Commit 2dfa9ba — Harden economy_players write path for the cutover (PAR-35, phase 1)
- tesks changed status to Status → Pending Release
- tesks changed status to Status → In Progress
- paradaux changed status to Status → Planned
- paradaux description: Description updated
- tesks commented
- tesks description: Description updated
- tesks commented
- tesks assigned Assigned to rian