이슈 #421
진행중AGX 잔액을 Wallet 종속 → Account(GoTrue user_id) 종속으로 전환
설명
배경¶
GoTrue 인증 전환(#411) 으로 사용자 정체성이 wallet_address → user_id (UUID) 로 바뀌었지만, AGX 잔액 / 보상 / 집계는 여전히 wallet_address 키 기반이다.
현재 상태 (audit 결과)¶
| 테이블 | AGX 키 | 비고 |
|---|---|---|
job_receipts |
wallet_address |
user_id 컬럼 없음, 모든 잔액의 source of truth |
aggregated_earnings |
wallet_address |
일/월 집계 |
wallets.balance_agx |
wallet_address |
dead column (계산은 receipts 합산) |
wallets 는 1 user → N wallets 구조라, 동일 사용자가 여러 wallet 을 가지면 잔액이 wallet 별로 분산된다.
목표¶
- AGX 잔액 / 적립 / 차감의 단일 키를 GoTrue
user_id로 통일 -
wallet_address는 payout destination metadata 로만 유지 (출금 경로 / 노드 서명 키) - 신규
wallet_adjustmentsledger 테이블 (account-scope) 도입 — 리딤/관리자 조정/롤백 가능
변경 범위¶
DB¶
-
job_receipts.user_id UUID컬럼 추가 + backfill (JOIN wallets ON wallet_address) -
aggregated_earnings.user_id UUID추가 + backfill -
wallet_adjustments신규 테이블 (user_id,delta_agx,reason,ref_code) - 인덱스:
(user_id, completed_at DESC)추가
잔액 계산¶
잔액 = SUM(job_receipts.reward_agx WHERE user_id=$1) + SUM(wallet_adjustments.delta_agx WHERE user_id=$1)
Store¶
-
store/wallets.rs::get_balance(user_id)— 시그니처 변경 -
store/receipts.rs의 wallet 기반 함수들 → user_id 기반으로 신규 추가 (기존은 deprecate) -
store/wallet_adjustments.rs신설
Handler / Proto¶
-
WalletService의 RPC 들에서wallet_address요청 필드 →user_id기준 조회로 전환 (요청 필드는 호환 위해 당분간 wallet_address 유지하되, 서버에서 wallet → user_id 룩업 후 user_id 기준 응답) - 또는 신규 RPC 추가:
GetMyEarnings,GetMyReceipts— JWT 의 user_id 자동 사용
마이그레이션 전략¶
- 컬럼 추가 (NULL 허용)
- backfill 스크립트로 기존 row 채우기
- 신규 인덱스 생성
- Store / handler 코드 user_id 기반으로 전환
- 추후 (별도 이슈): wallet 기반 RPC 필드 deprecate
의존 / 관련 이슈¶
- #411 — GoTrue 인증 전환 (선행)
- Redeem Code 이슈 — 본 작업이 선행되어야 리딤이 가능
JL James Lee이(가) 6달 전에 변경
- 상태을(를) 신규에서 해결(으)로 변경되었습니다.
Phase 0 구현 완료 — AGX 계정 스코프 전환¶
commit:server|657e7fa
핵심 변경¶
| 변경 전 | 변경 후 | |
|---|---|---|
| AGX 회계 키 | wallet_address |
user_id (UUID) |
| 잡 receipt | job_receipts.wallet_address |
job_receipts.user_id |
| 일/월 집계 | aggregated_earnings.wallet_address |
aggregated_earnings.user_id |
| 잔액 ledger | (없음) |
wallet_adjustments 신규 |
| 잔액 공식 | Σ receipts(wallet) |
Σ receipts(user) + Σ adjustments(user) |
wallet_address |
identity | payout metadata only |
변경 내역¶
DB (마이그레이션 0007_agx_account_scope.sql)
-
DROP job_receipts,aggregated_earnings(wallet 기반) -
DROP wallets.{balance_agx, total_earned_agx}(dead column 정리) - 신규
job_receipts(user_id UUID)+ 인덱스(user_id, completed_at DESC) - 신규
aggregated_earnings(user_id UUID, UNIQUE(user_id, period_date, period_type)) - 신규
wallet_adjustments— account ledger (redeem / admin credit·debit / AI 차감 등) - 데이터 보존 없이 클린 리라이트
Store
-
store/wallets.rs::get_balance(user_id)—receipts(COMPLETED) + Σ adjustments합산 -
store/receipts.rs—list_by_user_id,count_by_user_id,summary_for_user_id,today_for_user_id,node_reward_stats,entries_by_range,insert모두 user_id 기반 -
store/earnings.rs—list_by_user_id,count_by_user_id -
store/jobs.rs—list_by_user_id(JOINnodes.owner_user_id) -
store/wallet_adjustments.rs신설 —insert / sum_by_user_id / list_by_user_id / count_by_user_id
Proto / Handler
-
proto/alphea/v1/wallet.proto— 모든 request 메시지에서wallet_address필드 제거 -
domain::auth::require_user_token()— node 토큰 거부 (wallet RPC 는 user-only) -
handler/wallet.rs전체 재작성 — caller user_id 사용 (require_user_token)
Admin / Tools
-
src/admin/mod.rs— wallet 엔드포인트는 caller user_id 사용. 경로의{wallet}자리표시자는 호환을 위해 유지하되 무시 (semantic 만 변경) -
tools/client.py— WalletService 호출에서wallet_address인자 제거 -
examples/wallet_earnings.rs— stub 으로 변경 (실제 구동에는 GoTrue 토큰 필요)
검증¶
-
cargo build성공 -
cargo test --lib32 tests passed -
cargo clippy --lib --tests --binsclean
후속 (#420 — Redeem Code 시스템에서 본 ledger 사용)¶
이제 Redeem Code 적립이 wallet_adjustments 테이블에 user_id 기준으로 기록 가능. Phase 1 진행 조건 충족.
JL James Lee이(가) 6달 전에 변경
Go 백포트 Phase 1 — 스키마 경계선¶
commit:server|03c6c64 (이슈 #434)
본 이슈(AGX 회계를 user_id 종속으로 전환) 는 Go 백포트의 Phase 2 에서 처리 예정. 이번 Phase 1 에서는 소유권/인증 경로만 user_id 기반으로 넘겼고, AGX 회계 관련 테이블(job_receipts / aggregated_earnings / wallets(현재 account_id 기반 1:1 구조) / virtual_node_* / wallet_adjustments 미존재)은 현 스키마 그대로 유지 했다.
이유:
- Go 프로젝트의 WalletService / FriendsService / Wallet VIP / Virtual Node 핸들러가 기존 wallet_address 기반 수익 집계에 의존하고 있어 Phase 1 안에서 한 번에 갈아이우는 게 희이움
- 식별 권한 전환(GoTrue user_id)과 AGX 재설계를 분리해야 PR 그룹이 작아짐
후속 Phase 2 (별도 이슈 예정)¶
-
wallets를 (account_id, balance) 1:1 구조 제거 → (user_id, wallet_address, label) 1:N -
job_receipts.user_id UUID/aggregated_earnings.user_id UUID추가, 잔액 계산을 Σ receipts + Σ adjustments 로 교체 -
wallet_adjustmentsledger 테이블 신설 (redeem / admin credit·debit 용) -
WalletService핸들러가 caller user_id 기반으로 조회하도록 재작성 - FriendsService / Virtual Node 관련 테이블도 이 단계에서 user_id 키로 이동
JL James Lee이(가) 6달 전에 변경
Go 백포트 Phase 2 구현 완료¶
후속 이슈 #435 에서 진행. Rust 측 본 이슈의 핵심(AGX 회계 키 = user_id + wallet_adjustments ledger + 1:N wallets) 을 Go 원본으로 백포트.
commit:server|61f09e9
Go 측에서의 차이¶
- 하위 호환 유지: virtual_node_assignments / virtual_node_credits / virtual_node_packages 는 이번 phase 에서 스키마 그대로 유지하고 user→wallets 매핑으로 우회. WalletService 관련 핸들러가 caller 의 wallets 를 순회하며 집계
-
Friends / referral_claims / rewards_log: 각 테이블 자체는 아직 account.ID 절서 키로 남아있으며, account 에 매핑된 user_id 점 활용을 위해
store.CreditAccount(accountID, delta, reason, refCode)헬퍼가 wallet_adjustments 에 기록 -
DiscardUnknown: 서버 JSON codec 에
DiscardUnknown: true추가 — 아직 wallet_address 필드를 보내는 클라이언트가 마이그레이션 기간 동안 완전히 수용
구현 테이블 (Phase 1 이후의 v13 마이그레이션)¶
| Phase 1 (#434) | Phase 2 (이번) | |
|---|---|---|
| accounts | user_id UUID 추가 | (변경 없음) |
| wallets | TRUNCATE 만 | (account_id,balance) 1:1 DROP → (user_id,wallet,label) 1:N 재설계 |
| job_receipts | (변경 없음) | user_id UUID + 인덱스 추가 |
| aggregated_earnings | (변경 없음) | user_id UUID + 고유 인덱스 추가 |
| wallet_adjustments | — | 신규 생성 |
| nodes | owner_user_id UUID 추가 | (변경 없음) |
잔액 계산 공식 적용: Σ receipts(user_id)+Σ adjustments(user_id). wallet_address 는 이제 payout destination metadata 역할만.