๐Ÿ“– star365 Docs
โ† ๋ณด๊ณ ์„œ ๋ชฉ๋ก

Stage8 cash_point Audit Log Sprint

ํŠธ๋ฆฌ๊ฑฐ

stage8-cash-point-gap-rootcause-20260506 ๋ฉ”๋ชจ๋ฆฌ์˜ ๊ถŒ์žฅ ์‚ฌํ•ญ: "future remediation: introduce 1127_cash_point_audit_log table that records every cash_point UPDATE with before/after value, source code path, and admin actor. Apply at all UPDATE sites." + 5/6 PRIMARY fix(payoutAllSummary status not 2) ๋ฏธ๋ฐฐํฌ ์ž”์กด.

์‚ฐ์ถœ๋ฌผ

1. DB migration

์‹ ๊ทœ ํ…Œ์ด๋ธ” 1127_cash_point_audit_log:

2. Prisma model

prisma db pull ์œผ๋กœ ์ž๋™ model ์ถ”๊ฐ€ + prisma generate ํ†ต๊ณผ.

3. Helper ์‹ ๊ทœ (1 ํŒŒ์ผ)

/home/stage8-user/src/lib/audit/cashPointAudit.ts (76 LOC)

4. Wiring ์ตœ์ข… ๋งคํŠธ๋ฆญ์Šค (7 ํŒŒ์ผ, 9๊ณณ)

Phase 1 (5 ํŒŒ์ผ 5 endpoint, 7๊ณณ):

ํŒŒ์ผ ์œ„์น˜ source
admin/payout/route.ts:245 reject ํ™˜๋ถˆ ์งํ›„ payout_refund
admin/wallet/adjust/route.ts:102 manual credit/debit ์งํ›„ admin_credit / admin_debit
ewallet/transfer/route.ts:112 sender ์ฐจ๊ฐ ์งํ›„ transfer_out
ewallet/transfer/route.ts:124 recipient ๊ฐ€์‚ฐ ์งํ›„ transfer_in
admin/users/bulk-register/route.ts:49 initialCash ๊ฐ€์‚ฐ ์งํ›„ bulk_register

Phase 2 (2 ํŒŒ์ผ 4 endpoint, 4๊ณณ) โ€” ์‚ฌ์šฉ์ž ๋ช…๋ น ํ›„์† wiring:

ํŒŒ์ผ ์œ„์น˜ source
investmentService.ts:260 ์‹ ๊ทœ ํˆฌ์ž ์ฐจ๊ฐ ์งํ›„ investment_create
investmentService.ts:441 ์ผ์ผ ์ˆ˜์ต ๊ฐ€์‚ฐ ์งํ›„ investment_yield
investmentService.ts:503 ๋งŒ๊ธฐ ๋ฐ˜ํ™˜ ๊ฐ€์‚ฐ ์งํ›„ investment_principal
BscWatcher.ts:174 USDT ์ž๋™ ์ž…๊ธˆ ์งํ›„ deposit_bsc

SKIP (์ •์ฑ… ๋ฐ˜์˜):

5. 5/6 PRIMARY fix ๋™์‹œ ๋ฐฐํฌ (์ž”์กด ๋ฏธ๋ฐฐํฌ ์ž‘์—…)

/home/stage8-user/src/app/api/user/ewallet/route.ts:213

- prisma.payout_release_requests.aggregate({
-   where: { user_id: userIdBigInt },
+ prisma.payout_release_requests.aggregate({
+   where: { user_id: userIdBigInt, status: { not: 2 } },
    _sum: { amount: true, payout_fee: true }
  })

โ†’ rejected payout double-count 5๊ฑด ($114) ํ•ด์†Œ.

DC ๊ฒ€์ฆ (7/7 PASS)

# ํ•ญ๋ชฉ ๊ฒฐ๊ณผ
1 1127_cash_point_audit_log ํ…Œ์ด๋ธ” + 4 ์ธ๋ฑ์Šค ์ƒ์„ฑ โœ…
2 Prisma model cash_point_audit_log ์ƒ์„ฑ + generate โœ…
3 helper recordCashPointAudit 76 LOC โœ…
4 5 ํŒŒ์ผ 7๊ณณ wiring (audit insert ํ˜ธ์ถœ) โœ…
5 5/6 PRIMARY fix ์ ์šฉ (status: { not: 2 }) โœ…
6 DB ๋น„๊ต ๊ฒ€์ฆ โ€” kstone0675 $54 / star365 $5 / LHU86968923 $25 / anyhome1 $30 = $114 ํ•ด์†Œ โœ…
7 PM2 ์–‘์ชฝ reload zero-downtime, unstable=0 โœ…

๋ฉ”๋ชจ๋ฆฌ ์ •ํ•ฉ ๊ฒ€์ฆ

stage8-cash-point-gap-rootcause-20260506 ์˜ PRIMARY ROOT CAUSE ๊ฒ€์ฆ:

ํ–ฅํ›„ ์ถ”๊ฐ€ wiring ํ›„๋ณด โ€” Phase 2 ์™„๋ฃŒ (์‚ฌ์šฉ์ž ๋ช…๋ น ํ›„์†)

ํ•ญ๋ชฉ ์ƒํƒœ
investmentService.ts 3๊ณณ (create / yield / principal return) โœ… Phase 2 ์™„๋ฃŒ
BscWatcher.ts:174 (deposit_bsc) โœ… Phase 2 ์™„๋ฃŒ (PM2 stage8-bsc-watcher reload)
TronWatcher.ts โญ๏ธ TRON ๋ฏธ์ง€์› ์ •์ฑ… SKIP
authService.ts:151 โญ๏ธ cash_point=0 INSERT (audit ์˜๋ฏธ ์—†์Œ) SKIP

์ตœ์ข…: 9 wiring + 1 helper + 1 migration. ํ•ต์‹ฌ cash_point ๋ณ€๋™ ํ๋ฆ„ 100% ์ปค๋ฒ„ (admin actor 5 + ์ž๋™ ํŠธ๋ฆฌ๊ฑฐ 4 โ€” BSC deposit / investment yield / investment principal / investment create).

5/6 ๋ฉ”๋ชจ๋ฆฌ์˜ PENDING 4๋ช… (a01071540697, garnet, ljm5177, lst6485)

์ด๋ฒˆ sprint ํ›„ ๋™์ž‘: ์‹ ๊ทœ cash_point ๋ณ€๊ฒฝ ์‹œ audit ์ž๋™ ๊ธฐ๋ก๋จ. ๊ธฐ์กด gap์€ ํ‘œ ์—†๋Š” OFF-LEDGER ๋ณ€๊ฒฝ(race condition + retroactive INSERT)์ด๋ผ backfill ์–ด๋ ค์›€. ํ–ฅํ›„ ๋ชจ๋“  ๋ณ€๋™์ด audit_log์— ๋‚จ์œผ๋ฏ€๋กœ ์žฌ๋ฐœ ์‹œ ์ฆ‰์‹œ root cause ์‹๋ณ„ ๊ฐ€๋Šฅ.

์•ˆ์ „

์‚ฌ์šฉ์ž ๊ฒ€์ฆ SQL

-- ์‚ฌ์šฉ์ž๋ณ„ audit ์ด๋ ฅ
SELECT * FROM 1127_cash_point_audit_log WHERE user_id = ? ORDER BY created_at DESC LIMIT 50;

-- 24h source๋ณ„ ํ†ต๊ณ„
SELECT source, COUNT(*) cnt, SUM(amount) total_amount
FROM 1127_cash_point_audit_log
WHERE created_at >= NOW() - INTERVAL 24 HOUR
GROUP BY source ORDER BY cnt DESC;

-- balance_before/after ์ •ํ•ฉ ๊ฒ€์ฆ (race ์ถ”์ )
SELECT user_id, source, amount, balance_before, balance_after,
  (balance_after - balance_before) AS calc_delta
FROM 1127_cash_point_audit_log
WHERE balance_before IS NOT NULL AND balance_after IS NOT NULL
  AND ABS((balance_after - balance_before) - amount) > 0.001
ORDER BY created_at DESC LIMIT 20;