Replaces EZShop 1.0-SNAPSHOT (bespoke, sell-only, 27-slot) and Kiranhart
AuctionHouse 1.4.6 (ARR no-LICENSE, dupe history) with a single GPL-3
stack: ExcellentShop 5.0.1 + CoinsEngine 2.7.0 + nightcore 2.15.3.
Per SHOP-SYSTEM-DECISION.md (commit 9565f0b), Stack A wins on three
counts: GPL-3 source (vs ARR/proprietary), unified theme across shop
and AH, single-vendor support story under NightExpress.
Jars sourced from upstream Reposilite repo.nightexpressdev.com — same
artefacts a local mvn package would produce, just reproducible without
the alex9849 integration that breaks on TLS handshake. SHA256SUMS
committed for receipt; never re-fetched at swap time.
Bundle:
build/ — three jars + SHA256SUMS (~2.1MB total)
configs/ — post-first-run overrides (chest module off, /shop alias,
AH 1% tax + BIN+bid + 10 listings matches Kiranhart)
scripts/ — swap.sh, rollback.sh, lp-shop-migration.sh,
lp-shop-rollback.sh, docker-compose.patch.yml
itzg integration: COPY_PLUGINS_SRC=/plugins-custom mount per
ITZG-CUSTOM-JAR-PERSISTENCE.md, plus REMOVE_OLD_MODS_EXCLUDE expanded
with the three new globs.
LP migration grants default-tier excellentshop.* + coinsengine.*
nodes; staff tier gets *.admin equivalents to legacy
auctionhouse.moderator. Group prefixes/suffixes untouched per
feedback_lp_prefixes_locked.md.
DOES NOT touch live /data/plugins/EZShop or /data/plugins/AuctionHouse
— staging only. Operator runs swap.sh in scheduled maintenance window.
Refs: SHOP-SYSTEM-DECISION.md, AUDIT-2026-05-07.md F-11,
ITZG-CUSTOM-JAR-PERSISTENCE.md, MIGRATION-PLAN-EXCELLENTSHOP.md.
8 KiB
Migration Plan — EZShop + Kiranhart AH → ExcellentShop unified
Date: 2026-05-08
Author: s8n
Supersedes: AUDIT-2026-05-07 F-11; SHOP-SYSTEM-DECISION sec. 6 (now operational)
Staging: staging/excellentshop/
Status: Ready for operator-scheduled maintenance window.
1. Summary
Replace two plugins (EZShop 1.0-SNAPSHOT bespoke + Kiranhart AuctionHouse
1.4.6 ARR-no-LICENSE) with one GPL-3 stack:
ExcellentShop 5.0.1 + CoinsEngine 2.7.0, both built by NightExpress against
nightcore 2.15.3. All three jars are sourced from the upstream Reposilite
(repo.nightexpressdev.com) — source-of-truth identical to a local
mvn package from github.com/nulli0n/ExcellentShop-spigot, just reproducible
without the brittle alex9849 integration that fails on TLS handshake.
Both modules share one theme, one perm tree, one update cadence. Chest Shop module is disabled — not a future-of-server commit (QuickShop-Hikari path already documented in SHOP-SYSTEM-DECISION).
2. Pre-flight (not in swap.sh, do these first)
- Heads-up window: post in-game notice via
/pm newsminus 7d, 1d, 1h. "Auction listings will be drained on YYYY-MM-DD HH:MM." - Drain Kiranhart AH: instruct players to claim/cancel listings.
Bid-in-progress items revert at the close of the bid window (max 2h,
per
bid-auction-duration: 7200). Manual refund the residue to the listing owner via/eco giveafter the window — record the audit trail inlive-server/migration-2026-05-08-residue.log. - Snapshot live data: invoke
scripts/restic-backup-playerdata.sh(already wired for nullstone). Verify the snapshot viarestic snapshots --tag pre-shop-migration. - Verify staged bundle:
cd staging/excellentshop/build sha256sum *.jar # match the values committed alongside this doc - Confirm operator window: compose stop → up takes ~3 minutes; ExcellentShop generates ~11 default shops + 400 items on first start (~30s extra). Total expected downtime: 4-6 minutes best case, 12 minutes worst case (if itzg downloads stall).
3. Swap procedure
scripts/swap.sh runs as user@nullstone and performs:
| Step | Action |
|---|---|
| 1 | docker compose stop mc |
| 2 | tar legacy EZShop + AuctionHouse plugin trees + jars to /opt/docker/minecraft/plugins.tar.bak-<ts> |
| 3 | privileged rm -rf of legacy trees and jars (uses docker run --privileged --userns=host per feedback_docker_sudo_bypass) |
| 4 | populate /opt/docker/minecraft-custom-plugins/ with the three staged jars, chown 1000:1000 |
| 5 | replace docker-compose.yml with docker-compose.patch.yml (adds COPY_PLUGINS_SRC=/plugins-custom, the bind mount, and the new REMOVE_OLD_MODS_EXCLUDE glob list) — keeps a .bak-<ts> |
| 6 | docker compose up -d mc (first-start config generation runs here) |
| 7 | poll mc-health for up to 4 minutes |
| 8 | docker cp the staged config overrides into the now-populated plugin tree, run excellentshop reload + coinsengine reload, then run lp-shop-migration.sh over RCON to grant default-tier perms |
The compose patch is identical to the existing live compose except for
the three lines: PLUGINS (drops EZShop+AH URLs), REMOVE_OLD_MODS_EXCLUDE
(adds three new globs), and COPY_PLUGINS_SRC + matching volume mount.
4. Smoke test (post-swap, manual)
Run as a non-staff player and as a staff player:
/shop→ main category menu, 11 shops, GUI renders within 1s./sellall→ sells inventory,+N coinschat feedback,/balanceupdates./sellhand→ sells hand stack, hand cleared./ah→ AH GUI opens, list a test item via/ah list 100, see it in browse./ahadmin:/ah admin remove <listing>works,/ah admin expireworks./balance,/pay,/ecoresolve through CoinsEngine via Vault bridge.- Tail logs
docker logs -f minecraft-mc | grep -E 'nightcore|ExcellentShop|CoinsEngine|ERROR|WARN'for 5 minutes after first player joins.
If any of the above fail, run scripts/rollback.sh.
5. Rollback
scripts/rollback.sh reverses everything: stops the container, removes
ExcellentShop+CoinsEngine+nightcore plugin trees and jars, clears the
custom-plugins bind dir, restores legacy EZShop+AuctionHouse from the
tar snapshot, restores the previous docker-compose.yml, restarts, and
runs lp-shop-rollback.sh over RCON to restore the legacy perm nodes.
Rollback total time: ~5 minutes.
6. Risk register
| # | Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|---|
| R1 | nightcore 2.15.3 incompatible with Purpur 1.21.11 (api-version 1.21 should match) | Low | High | Smoke-test on a throwaway container first; rollback path < 5 min if breakage |
| R2 | CoinsEngine 2.7.0 fails Vault bridge (EssentialsX expects Vault) | Medium | High | Vault_Compatibility.Default: true set in staged currency YAML; verify /balance in smoke step 4 |
| R3 | NightExpress reposilite goes dark before next maintenance | Low | Low | Jars are committed to the repo at staging/excellentshop/build/ with sha256 receipts — never re-fetched at swap time |
| R4 | Players keep typing /auctionhouse (legacy alias) |
Certain | Low | commands.yml aliases [ah, auctionhouse, market] keep muscle memory |
| R5 | EZShop balance migration loss (if EZShop tracked any) | Very Low | Low | EZShop was sell-only with Vault → balances live in EssentialsX, untouched by this swap |
| R6 | Live AH listings lost (residual stuck items) | Medium | Medium | Pre-flight step 2 drains, residue refund is documented |
| R7 | First-start delay > 4 min healthcheck window (large default catalog generation) | Low | Medium | start_period: 240s already set; if exceeded, manual docker exec mc mc-health poll |
| R8 | Compose typo locks server out of plugins | Low | High | swap.sh keeps docker-compose.yml.bak-<ts> for trivial revert; rollback restores it |
| R9 | excellentshop.shop.use not granted to default group → no players can /shop |
Medium | High | lp-shop-migration.sh step 8 grants the full perm tree; verify with /lp user <name> permission check excellentshop.shop.use |
| R10 | Compose cap_drop: ALL strips a cap CoinsEngine needs |
Low | Low | If /data/plugins/CoinsEngine/ write fails, cap_add: DAC_OVERRIDE rescue documented in swap.sh comments |
7. Top 3 swap-window risks (operator brief)
- R9 (perm regression) — if the LP migration RCON call drops mid-script,
players see
/shopwork but/sellallfail. Mitigation: re-runlp-shop-migration.shidempotently — every line ispermission set <node> true. - R7 (slow first-start) — first start of a fresh ExcellentShop with the
bundled catalog generation takes ~30s extra and might trip the 240s
healthcheck on a cold pool. Mitigation:
swap.shstep 7 polls manually before declaring success. - R2 (Vault bridge) — if
/balancereturns 0 instead of the player's actual balance, the Vault bridge from CoinsEngine is mis-wired. Mitigation:Vault_Compatibility.Default: trueis in the staged YAML; if still broken,/eco give <player> <prev-balance>from the EssentialsX-side dump thatrestic-backup-playerdata.shalready takes.
8. Estimated downtime
- Best case: 4 minutes (compose stop → up + health check, no log churn).
- Typical: 6 minutes (one extra stall on jar copy or LP RCON timeout).
- Worst case: 12 minutes (first-start catalog generation slow + manual smoke).
If the worst case is exceeded, abort and run rollback.sh — the data
snapshot from pre-flight step 3 is the source of truth.
9. Post-migration
- Update
AUDIT-2026-05-07.mdF-11: status → Resolved (date 2026-05-08). - Update
docs/COMMANDS.md:/shop,/ah,/sellall,/sellhand,/balanceall now route through ExcellentShop+CoinsEngine. - Update
SYSTEM.mdplugin table: drop EZShop, drop AuctionHouse 1.4.6, add ExcellentShop 5.0.1, CoinsEngine 2.7.0, nightcore 2.15.3. - Schedule a follow-up audit in 7d to confirm no log spam, no economy drift, no listing exploits.