Review fixes on the #338 backend:
1. New table return_match_log (models/return_match_log.go, registered
in migrations.MigratedModels()): match_id/action/operator/detail/
created_at. sys_opera_log is a generic per-HTTP-call framework log,
not queryable per match and not carrying operator/detail in a
stable shape, so match/confirm/cancel/remark each write their own
log row in the SAME transaction as the state change. Detail now
returns the logs (newest first).
2. Race between matching and purchase creation: BatchMatch's outer
screening pass (stage check outside any lock) is now followed by
matchOneWithLock, which takes the same clause.Locking{Strength:
"UPDATE"} lock on syb_product that purchase.Service.create takes,
re-computes the stage inside that transaction via
purchase.NewService(tx).ProcessStages, and returns
errStageNoLongerEligible (surfaced as reasonCode
stage_ineligible) if the product is no longer in a participating
stage instead of inserting a stale match.
TestMatchOneWithLock_SkipsWhenStageNoLongerParticipatesUnderLock
covers the skip path.
3. matchOneWithLock now fills YeekeSpecText (raw variation_name) and
PreviousProcessStage (the stage code at match time) on the
inserted row. Remark takes an operator (for its log row) and
rejects input over 500 runes with errRemarkTooLong instead of
truncating (varchar(500) is a character-count limit in MySQL, so
the check is utf8.RuneCountInString, not len()).
4. returnmatch.SYBSpecText now joins only non-empty color/size parts,
so a single-dimension spec (e.g. color-only) no longer produces a
stray leading/trailing comma ("黑色" instead of "黑色,"); matchKey
additionally trims leading/trailing commas from both normalized
sides via the new trimCommas() helper. New tests cover color-only
and size-only matching through SelectMatches plus SYBSpecText/
trimCommas directly.
5. Detail (service.go) now returns MatchDetail: SYBDetailView (order
code, shopee item id, shop, title, target color/size, quantity,
image, current computed stage+label), YeekeDetailView (return
order sn, item id, variation id, shop, item name, variation name,
quantity, image, destroy deadline), both sides' normalized spec
text, the match row itself, and the operation logs — everything
the prototype's compare screen (screen 3) needs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NTDbDcwbDw1TSAcE6wfh2F