Commit Graph

1547 Commits

Author SHA1 Message Date
Houmgaor
649eebe67c docs: log bookshelf data pointer fix in changelog and technical debt tracker 2026-02-27 16:53:35 +01:00
Houmgaor
4c47c8e18f fix(channelserver): correct bookshelf save data pointers for non-ZZ (#164)
The pBookshelfData offsets for G1-Z2, F4-F5, and S6 were off by -14810,
placing bookshelf before houseData in the save blob and reading garbage.
All other 12 save fields have consistent inter-version deltas (36000,
32000, 48000); only bookshelf broke the pattern. Correcting by +14810
restores the gallery-bookshelf gap to 136 bytes (matching ZZ) and aligns
all field deltas across versions.

Supersedes Mezeporta/Erupe#155 (same fix, merge conflict on renamed file).
2026-02-27 16:46:32 +01:00
Houmgaor
7911d84d48 docs: log alliance application toggle fix in changelog 2026-02-27 15:02:30 +01:00
Houmgaor
d6938f2a27 fix(guild): implement alliance application toggle (#166)
Alliance applications were hardcoded to always-open. Add a `recruiting`
column to guild_alliances and handle OperateJoint actions 0x06 (Allow)
and 0x07 (Deny) confirmed via Wii U debug symbols. Only the parent
guild leader can toggle the setting, matching the existing disband guard.
2026-02-27 14:59:18 +01:00
Houmgaor
fba8c2413c docs: link remaining TODOs to GitHub issues in technical debt tracker
Filed #164-#168 for all 8 remaining TODOs. Added Tracker column
with issue links, fixed stale line numbers, added MhfAddUdPoint
stub entry, and expanded the suggested execution order.
2026-02-27 13:46:12 +01:00
Houmgaor
7f5d30e2f5 fix: resolve code scanning findings in commands and wizard
Add bounds check (0 to MaxUint32) before casting strconv.Atoi result
to uint32 in the rights command handler. Replace manual allowlist
validation with pq.QuoteIdentifier for CREATE DATABASE to eliminate
the SQL injection finding.
2026-02-27 13:45:56 +01:00
Houmgaor
7e24bbc087 ci: serialize test packages to fix shared database race condition
The migrations and channelserver packages both DROP and recreate the
public schema on the shared erupe_test database. With parallel package
execution, they destroy each other's schema mid-migration. Adding -p 1
serializes package execution while preserving t.Parallel() within each
package.
2026-02-27 13:28:45 +01:00
Houmgaor
31266fcb21 test(entranceserver): push coverage from 56.1% to 82.2%
Add 18 tests covering makeSv2Resp (ZZ, G3.2/SVR, MezFes/Return
filtering, debug logging), encodeServerInfo branches (non-local IP,
empty IP fallback, GG/G1-G5 client modes, ProxyPort, type filtering),
makeUsrResp debug logging, sanitizeAddr, and startEntranceCapture
(disabled, entrance-disabled, enabled, default output dir).
2026-02-27 13:19:33 +01:00
Houmgaor
35d920f5da docs: mark repo test coverage as complete in technical debt tracker
The 17 previously-untested repo files all have test files now.
2026-02-27 13:12:43 +01:00
Houmgaor
156b5c53f7 test(signserver): push coverage from 62.9% to 70.3%
Add handlePacket dispatch tests for all switch cases (DSGN, SIGN,
DLTSKEYSIGN, PS4SGN, PS3SGN, VITASGN, WIIUSGN, COGLNK, VITACOGLNK,
DELETE). Add makeSignResponse branch tests covering PSN client PSNID
field, CapLink key/host paths, MezFes minigame switch, non-localhost
remote addr, and PSN token registration. Add startSignCapture
enabled-path tests with temp dir and default output dir.
2026-02-27 13:07:12 +01:00
Houmgaor
3ad2836088 feat(api): add DELETE /v2/characters/{id} route, v2 test coverage, and OpenAPI spec
Add REST-idiomatic DELETE method as alias for POST .../delete.
Add 8 router-level tests exercising Bearer auth, invalid tokens,
soft delete, export body decoding, and MaxLauncherHR capping.
Create OpenAPI 3.1.0 specification covering all v2 endpoints.
2026-02-27 12:58:31 +01:00
Houmgaor
bcfdf48dad test(signserver): add session handler and utility coverage tests
Cover all previously-untested session handlers (authenticate,
handleDSGN, handleWIIUSGN, handlePSSGN, handlePSNLink, sendCode)
plus validateLogin ban/bcrypt paths, registerPsnToken, and
sanitizeAddr/startSignCapture. Uses a spyConn implementing
network.Conn to capture plaintext packets for assertion.

Raises signserver coverage from 46% to 63%.
2026-02-27 12:54:13 +01:00
Houmgaor
7ff26f4980 feat(api): add v2 routes, auth middleware, structured errors, and server status endpoint
Introduces incremental API improvements for custom launcher support
(mhf-iel, stratic-dev's Rust launcher):

- Standardize all error responses to JSON envelopes with error/message
- Add Bearer token auth middleware for v2 routes (legacy body-token preserved)
- Add `returning` (>90d inactive) and `courses` fields to auth response
- Add /v2/ route prefix with HTTP method enforcement
- Add GET /v2/server/status for MezFes, featured weapon, and event status
- Add APIEventRepo for read-only event data access

Closes #44
2026-02-27 12:46:23 +01:00
Houmgaor
9f43940a44 docs: add pre-commit checks section to CLAUDE.md
Enforce gofmt and golangci-lint before every commit to catch
formatting and lint issues locally instead of waiting for CI.
2026-02-27 12:37:48 +01:00
Houmgaor
d38fef08bb refactor(discordbot): introduce Session interface for testability
Extract a Session interface from *discordgo.Session so DiscordBot methods
can be tested with a mock — no live Discord connection required. Add
AddHandler, RegisterCommands, and UserID methods to DiscordBot so
external callers (main.go, sys_channel_server.go) no longer reach
through bot.Session directly. Rewrite tests with a mockSession,
raising discordbot coverage from 12.5% to 66.7%.
2026-02-27 11:45:20 +01:00
Houmgaor
4e8c4b4e92 fix(channelserver): handle silently discarded errors across handlers
Replace ~17 instances of '_ =' / '_ :=' with proper error checks that
log warnings or send fail ACKs. Affected handlers: cafe, distitem, data,
guild, guild_board, guild_cooking, guild_scout, house, mercenary, misc,
and rengoku. Also resolves all pre-existing lint issues: unchecked
bf.Seek in tests, unused filtered slice in svc_festa, unused mock
fields, and unused signserver test helper.
2026-02-27 11:33:25 +01:00
Houmgaor
4b24489ebe test(channelserver): add handler coverage tests for scout, house, items, rengoku, tower 2026-02-27 11:33:13 +01:00
Houmgaor
74798fc8b3 fix(channelserver): return error from Save() to prevent misleading success logs
CharacterSaveData.Save() silently returned on failure (nil decompressed
data, compression error, DB error) while the caller unconditionally
logged "Saved character data successfully". This made diagnosing save
failures difficult (ref #163).

Save() now returns an error, and all six call sites check it. The
success log in saveAllCharacterData only fires when the save actually
persisted.
2026-02-27 11:21:37 +01:00
Houmgaor
178a008e25 fix(shop): write gacha header for G1+ clients, not just GG+
The G1 client binary expects 8 uint32 fields (ID, rank restrictions,
MinGR, MinHR) before the name string in the gacha listing response.
PR #150 only wrote these for GG+, causing G1–G32 clients to misparse
the stream. Verified against Wii U G1 RPX decompilation of
import_gacha_list at 0x02C594FC.
2026-02-26 23:53:35 +01:00
Houmgaor
d0837e779c refactor(channelserver): consolidate tests into matching source test files
Move ~300 test functions from 21 catch-all files (handlers_core_test.go,
handlers_coverage*_test.go, *_coverage_test.go) into the *_test.go file
matching each handler's source file. This makes tests discoverable by
convention: tests for handlers_guild.go live in handlers_guild_test.go.

New files: handlers_guild_mission_test.go, sys_time_test.go.
No test logic changed — pure file reorganization.
2026-02-26 23:41:44 +01:00
Houmgaor
a68d76c55f test: add coverage tests to reach 65% total coverage
Add 16 test files across 4 packages covering previously untested
handler paths: guild board operations, house/warehouse management,
tower/tenrouirai progress, diva schedule, festa info, cafe duration,
API error paths, sign server responses, and byteframe boundaries.
2026-02-26 23:17:12 +01:00
Houmgaor
cdc4cd9ba3 test(channelserver): add handler coverage tests for misc, cafe, festa, event
Add four new test files covering previously-untested handler functions
to raise total coverage from 57.7% to 60.0%:

- handlers_misc_coverage_test.go: minidata, trend weapons, etc points,
  equip skin history
- handlers_cafe_coverage_test.go: cafe duration bonuses, daily cafe,
  cafe duration
- handlers_festa_coverage_test.go: mezfes data, festa voting, entry,
  charge, prizes, state queries, member enumeration
- handlers_event_coverage_test.go: weekly schedule, login boost,
  scenario data, friends/blacklist operations

Also make mockCharacterRepo.ReadEtcPoints configurable to support
etc points handler tests.
2026-02-26 22:28:32 +01:00
Houmgaor
4a1e019457 fix(shop): update early return test to use pre-G1 client version
PR #150 moved the early return threshold from G10 to G1, so the test
using G7 no longer hit the early return path and panicked on nil
gachaRepo.
2026-02-26 21:57:40 +01:00
Houmgaor
a399ba7419 fix(shop): fix syntax error and update migration tests after #150 merge
PR #150 introduced a double brace `{  {` on handlers_shop.go:109 that
broke compilation. Migration tests were also hardcoded for 1 migration
but 3 now exist (0001–0003).
2026-02-26 21:55:12 +01:00
Houmgaor
1f0ea6ac23 docs(changelog): log gacha shop fix for G1–GG clients (#150) 2026-02-26 21:51:52 +01:00
Houmgaor
ef1763952c Merge pull request #150 from Sin365/main
Resolve the issue of G1 and GG, gacha cat not being usable
2026-02-26 21:49:59 +01:00
sin365
cf3fc3fed3 gacha shop min version range:G1 2026-02-26 18:09:51 +08:00
sin365
cca84415e4 follow the latest version of the repository and modify gacha for handlers_sthop.go 2026-02-26 18:00:58 +08:00
sin365
caab0016d9 merge for delete handlers_shop_gacha.go 2026-02-26 17:57:40 +08:00
sin365
a23a9ca5c6 standardized code comments 2026-02-26 17:31:44 +08:00
Houmgaor
4e300a227c Update issue templates
More details on server/client.
2026-02-25 15:26:49 +01:00
Houmgaor
d9f90e3b46 fix(shop): resolve ambiguous column and missing unique constraint in RecordPurchase
The ON CONFLICT upsert referenced unqualified "bought" which PostgreSQL
rejected as ambiguous, and the table lacked the UNIQUE constraint needed
for ON CONFLICT. Adds a unique index on (character_id, shop_item_id) via
migration 0003 and qualifies the column as shop_items_bought.bought.
2026-02-24 17:06:38 +01:00
Houmgaor
f9d4252860 test(repos): add SQL integration tests for 17 untested repo files
Add 148 integration tests exercising actual SQL against PostgreSQL for
all previously untested repository files. Includes 6 new fixture helpers
in testhelpers_db.go and CI PostgreSQL service configuration.

Discovered and documented existing RecordPurchase SQL bug (ambiguous
column reference in ON CONFLICT clause).
2026-02-24 16:57:47 +01:00
Houmgaor
c5fd0444f4 docs: update architecture docs to reflect 6-service layer
The CLAUDE.md layered architecture section implied all handlers go
through services. In practice, services handle cross-repo coordination
while handlers call repos directly for simple CRUD. Updated the
diagram, added a services table, and added an "Adding Business Logic"
guide. Marked improvements.md item 4 as done.
2026-02-24 16:18:31 +01:00
Houmgaor
4d3ec8164c refactor(festa): extract festa logic into FestaService
The festa handler contained event lifecycle management (cleanup expired
events, create new ones) and the repo enforced a business rule (skip
zero-value soul submissions). Move these into a new FestaService to
keep repos as pure data access and consolidate business logic.
2026-02-24 16:12:40 +01:00
Houmgaor
7a56810e78 refactor(tower): extract tower logic into TowerService
The tower repo had business logic beyond simple CRUD: AddGem used a
fetch-transform-save pattern, progress capping was inline in the
handler, and RP donation orchestrated multiple repo calls with
conditional page advancement. Move these into a new TowerService
following the established service layer pattern.
2026-02-24 16:07:37 +01:00
Houmgaor
76d139538b refactor(items): extract inline data tables from handleMsgMhfEnumeratePrice
Static data (GZ monster prices, LB prices, wanted list) cluttered the
handler with 130 lines of table literals. Moving them to a dedicated
tables file keeps the handler focused on serialization logic.
2026-02-24 15:34:51 +01:00
Houmgaor
759988ae8e test(mocks): add mock implementations for 8 unmocked repo interfaces
Enables isolated unit tests for tower, festa, rengoku, diva, event,
misc, mercenary, and cafe handlers. All 21 repo interfaces now have
mock implementations in repo_mocks_test.go.
2026-02-24 15:24:08 +01:00
Houmgaor
41a103af9d refactor(test): consolidate two GuildRepo mocks into one
mockGuildRepoForMail and mockGuildRepoOps each implemented different
subsets of the 68-method GuildRepo interface. Adding any new method
required updating both mocks. Merged into a single mockGuildRepo with
configurable struct fields for error injection and no-op defaults for
the rest.
2026-02-24 14:13:20 +01:00
Houmgaor
c1fadd09c3 fix(commands): validate argument parsing in chat commands
KeyQuest set, Rights, and Teleport commands silently used zero values
when given malformed arguments (bad hex, non-integer coords). Now they
send the existing i18n error messages back to the player instead.
2026-02-24 13:57:58 +01:00
Houmgaor
8fead0b1f3 fix(handlers): add error handling for swallowed repo/service errors
Several handler files discarded errors from repository and service
calls, creating nil-dereference risks and silent data corruption:

- guild_adventure: 3 GetByCharID calls could panic on nil guild
- gacha: GetGachaPoints silently returned zero balances on DB error
- house: HasApplication called before nil check on guild;
  GetHouseContents error discarded with 7 return values
- distitem: 3 distRepo calls had no error logging
- guild_ops: Disband/Leave service errors were invisible
- shop: gacha type/weight/fpoint lookups had no error logging
- discord: bcrypt error could result in nil password being set
2026-02-24 13:55:49 +01:00
Houmgaor
2f92b4ff62 feat(db): add catch-up migration for partially-patched databases
The migration consolidation (27fb0fa) merged 33 incremental patches
into 0001_init.sql and marks the baseline as applied for any existing
database. Users who only ran some of the 33 patches have schema gaps
that cause runtime errors.

0002_catch_up_patches.sql replays all 33 patches (skipping 15 and 20,
which are destructive data resets) with idempotency guards so it is a
no-op on fresh or fully-patched databases and fills gaps otherwise.
2026-02-24 11:37:37 +01:00
Houmgaor
077c08fd49 refactor(mail): extract mail logic into MailService
Introduce MailService as a convenience layer between handlers/services
and MailRepo. Provides Send, SendSystem, SendGuildInvite, and
BroadcastToGuild methods that encapsulate the boolean flag combinations.

GuildService now depends on MailService instead of MailRepo directly,
simplifying its mail-sending calls from verbose SendMail(..., false, true)
to clean SendSystem(recipientID, subject, body).

Guild mail broadcast logic moved from handleMsgMhfSendMail into
MailService.BroadcastToGuild.
2026-02-24 00:05:56 +01:00
Houmgaor
1e9de7920d refactor(gacha): extract gacha logic into GachaService
Move payment processing, reward selection, stepup state management,
and box gacha tracking from handlers into a dedicated service layer.
Handlers now delegate to GachaService methods and only handle
protocol serialization.
2026-02-23 23:57:54 +01:00
Houmgaor
32c5a9bf9c docs: add CLAUDE.md with project-specific guidance 2026-02-23 23:44:05 +01:00
Houmgaor
daacb76fb8 refactor(achievement): extract achievement logic into AchievementService
Move EnsureExists + GetAllScores + compute loop from handler into
AchievementService.GetAll, and validation + ensure + increment into
AchievementService.Increment. Handlers now delegate to the service
layer for business logic while retaining protocol response building.

GetAchData stays as a pure function in handlers_achievement.go per plan.
2026-02-23 23:43:39 +01:00
Houmgaor
bcdc4e0b7e fix(setup): reduce friction in installation procedure
- Add Language default ("jp") so missing field no longer produces empty
  string, and include language selector in setup wizard
- Add --setup flag to re-run wizard even when config.json exists,
  providing a recovery path for corrupted configs
- Auto-apply seed data on fresh databases so users who skip the wizard
  still get shops, events, and gacha
- Fix stale docs referencing non-existent init/setup.sh and
  schemas/patch-schema/ in docker/README, CONTRIBUTING, and README
2026-02-23 23:39:49 +01:00
Houmgaor
210cfa1fd1 refactor(guild): extract disband, resign, leave, and scout logic into GuildService
Move business logic for guild disband, resign leadership, leave,
post scout, and answer scout from handlers into GuildService methods.
Handlers now delegate to the service layer and handle only protocol
concerns (packet parsing, ACK responses, cross-channel notifications).

Adds 22 new table-driven service tests and sentinel errors for typed
error handling (ErrNoEligibleLeader, ErrAlreadyInvited, etc.).
DonateRP left in handler due to Session coupling.
2026-02-23 23:35:28 +01:00
Houmgaor
2abca9fb23 refactor(guild): introduce service layer for guild member operations
Extract business logic from handleMsgMhfOperateGuildMember into
GuildService.OperateMember, establishing the handler→service→repo
layering pattern. The handler is now ~20 lines of protocol glue
(type-assert, map action, call service, send ACK, notify).

GuildService owns authorization checks, repo coordination, mail
composition, and best-effort mail delivery. It accepts plain Go
types (no mhfpacket or Session imports), making it fully testable
with mock repos. Cross-channel notification stays in the handler
since it requires Session.

Adds 7 table-driven service-level tests covering accept/reject/kick,
authorization, repo errors, mail errors, and unknown actions.
2026-02-23 23:26:46 +01:00
Houmgaor
48639942f6 style: run gofmt across entire codebase
330 non-vendor files had minor formatting inconsistencies
(comment alignment, whitespace). No logic changes.
2026-02-23 21:28:30 +01:00