프로젝트

일반

사용자정보

Actions

이슈 #435

진행중
JL HP

[Go backport] AGX 회계 user_id 종속 전환 — Phase 2

이슈 #435: [Go backport] AGX 회계 user_id 종속 전환 — Phase 2

James Lee이(가) 약 7시간 전에 추가함.

상태:
해결
우선순위:
높음
담당자:
목표버전:
시작일:
2026/05/12
완료일:
2026/05/12 (약 6달 지연)
진척도:

0%

추정시간:

설명

배경

GoTrue 인증 전환 (#434 Phase 1, commit:server|03c6c64) 의 후속. 식별 권한을 user_id 기반으로 옮겼으나, AGX 잔액 / 수익 / 집계 는 여전히 wallet_address 키 기반이다. Rust 측 #421 을 Go 원본으로 백포트해 AGX 회계의 단일 키를 GoTrue user_id 로 통일한다.

작업 범위

DB 스키마 v13 (마이그레이션, clean rewrite)

  • wallets 재설계: 기존 (account_id, balance, total_earned) 1:1 → (user_id UUID, wallet_address TEXT, label TEXT, created_at) 1:N. UNIQUE(user_id, wallet_address)
  • job_receipts.user_id UUID 컬럼 추가 + 인덱스 (user_id, completed_at DESC)
  • aggregated_earnings.user_id UUID 컬럼 추가 + UNIQUE(user_id, period_date, period_type)
  • wallet_adjustments 신규 테이블: (id, user_id UUID, delta_agx DOUBLE PRECISION, reason TEXT, ref_code TEXT, created_at). redeem / admin credit·debit 결제를 기록
  • 잔액 공식: Σ job_receipts.reward_agx WHERE user_id=$1 + Σ wallet_adjustments.delta_agx WHERE user_id=$1
  • clean rewrite: receipts / aggregated_earnings / wallets dev 데이터 DROP

Store 계층

  • store/wallets.go (신규 모듈): AddWallet(userID, wallet), RemoveWallet, ListWalletsByUser, GetUserIDByWallet
  • store/wallet_adjustments.go (신규): InsertAdjustment, SumByUser, ListByUser
  • store/wallet_queries.go 재작성: 수익/잔액 조회를 user_id 기반으로 교체. 기존 wallet_address 기반 함수는 deprecated
  • store/receipts.go: ListByUser, CountByUser, SummaryForUser, TodayForUser, EntriesByRange user_id 기반으로. 삽입 시 user_id 함께 저장
  • store/edge_node.go::UpsertAggregatedEarning: user_id 인자 추가

Proto

  • wallet.proto 에서 다음 요청 메시지의 wallet_address 제거: WalletJobsRequest, WalletNodesRequest, WalletEarningsRequest, WalletEarningsTodayRequest, WalletReceiptsRequest, WalletNodesDetailRequest, WalletEarningsByRangeRequest, WalletEarningsSummaryRequest, ClaimVirtualNodesRequest. 서버는 caller user_id 로 조회

Handler

  • handler/wallet_auth.go::requireAuthenticatedWallet → requireAuthenticatedUser (caller user_id 만 검증. wallet 권한 검사가 필요한 곳은 별도 헬퍼)
  • handler/wallet.go: 6개 RPC user_id 기반으로 재작성. Wallet 조회 계산 공식 적용
  • handler/wallet_vip.go: 3개 RPC. 관리자도 caller user_id 기반으로 (admin proxy 는 user_id 로 우회)

본 phase 에서 다루지 않는 것

  • FriendsService 테이블 user_id 전환 (Phase 3 이슈 예정)
  • virtual_node_assignments / virtual_node_credits / virtual_node_packages 스키마를 user_id 기반으로 (이는 그대로 유지하고 user→wallet 매핑으로 우회)
  • Admin Dev Console GoTrue UI (#424 백포트— 별도 phase)

마이그레이션 전략

Clean rewrite. dev/qa DB 는 reset 필요. Phase 1 과 동일한 정책 (scripts/ec2/reset-db.sh).

DoD

  • make build, make test 통과
  • WalletService 9개 RPC 가 GoTrue user JWT 없으면 Unauthenticated 거부
  • Wallet 잔액 = Σ receipts (user_id) + Σ adjustments (user_id) 로 계산
  • wallet_adjustments 으로 admin credit/debit 가능 (store 계층 귀니)

관련 이슈

  • 다른 phase: #434 (Phase 1, 해결), 이속 이슈 (Phase 3 Admin UI #424 백포트)
  • Rust 원본: #421
  • DB: #254 (스키마 변경 — refs 라인 동반)

연결된 일감 4 (4 건 진행 중 — 모두 미완료)

다음 일감과 관련됨: 이슈 #421: AGX 잔액을 Wallet 종속 → Account(GoTrue user_id) 종속으로 전환해결James Lee2026/04/27

Actions
다음 일감과 관련됨: 이슈 #254: 8-2. 데이터베이스 스키마 설계 (사용자. 앱. 일정)진행James Lee2026/04/282026/04/29

Actions
다음 일감을 우선 진행: 이슈 #434: [Go backport] Supabase GoTrue 인증 전환 — Phase 1: 인프라 + 인증 코어해결Henry Park2026/05/11

Actions
다음에 진행할 일감: 이슈 #436: [Go backport] Admin Dev Console GoTrue UI — Phase 3해결Henry Park2026/05/132026/05/13

Actions

JL James Lee이(가) 6달 전에 변경 Actions #1

  • 완료일을(를) 2026/05/12(으)로 지정되었습니다.
  • 시작일을(를) 2026/05/11에서 2026/05/12(으)로 변경되었습니다.
  • 다음 일감을 우선 진행:에 이슈 #434: [Go backport] Supabase GoTrue 인증 전환 — Phase 1: 인프라 + 인증 코어이(가) 추가되었습니다.

JL James Lee이(가) 6달 전에 변경 Actions #2

  • 다음 일감과 관련됨:에 이슈 #421: AGX 잔액을 Wallet 종속 → Account(GoTrue user_id) 종속으로 전환이(가) 추가되었습니다.

JL James Lee이(가) 6달 전에 변경 Actions #3

  • 다음 일감과 관련됨:에 이슈 #254: 8-2. 데이터베이스 스키마 설계 (사용자. 앱. 일정)이(가) 추가되었습니다.

JL James Lee이(가) 6달 전에 변경 Actions #4

  • 상태을(를) 신규에서 해결(으)로 변경되었습니다.

Phase 2 구현 완료

commit:server|61f09e9

적용된 변경

DB 스키마 v13 (clean rewrite)

  • wallets (account_id, balance) 1:1 구조 제거 → (user_id UUID, wallet_address, label, created_at) 1:N. UNIQUE(user_id, wallet_address) + 2개 인덱스
  • job_receipts.user_id UUID + 인덱스 (user_id, completed_at DESC)
  • aggregated_earnings.user_id UUID + 고유 인덱스 (user_id, period_date, period_type) + 일자 인덱스 (user_id, period_date)
  • wallet_adjustments 신규 테이블: (user_id, delta_agx, reason, ref_code, created_at) + 인덱스 2개
  • 잔액 공식: Σ job_receipts.reward_agx WHERE user_id=$1 AND status='completed' + Σ wallet_adjustments.delta_agx WHERE user_id=$1

Store (신규 / 개편)

  • store/wallets.go (신규): AddWalletForUser, RemoveWalletForUser, ListWalletsByUser, GetUserIDByWallet, PrimaryWalletForUser
  • store/wallet_adjustments.go (신규): InsertAdjustment, SumAdjustmentsForUser, ListAdjustmentsForUser
  • store/accounts.go: GetWalletBalance → user→receipts+adjustments 로 대체. GetBalanceForUser, CreditWalletForReward(wallet→user_id 자동 매핑), UpdateLastActiveByUser 헬퍼 추가. ListAccountsWithBalance 는 CTE 로 receipts+adjustments 집계로 재작성
  • store/receipts.go: CreateReceipt 가 wallet→user_id 자동 조회 후 user_id 컬럼에 스탠프. AggregateReceipts 가 user_id 를 그룹에 포함해 aggregated_earnings 에 COALESCE 업서트
  • store/wallet_queries.go: GetJobsByUser, GetEarningsByUser, GetEarningsTodayForUser, GetReceiptsByUser 신규 — 기존 wallet 기반 함수는 유지(virtual-node / engine 경로 호환)
  • store/nodes.go: GetNodesByUserID, GetClientNodesByUserID
  • store/friends.go: UpdateWalletBalanceByAccountID / GetWalletBalanceByAccountID 제거. CreditAccount(accountID, delta, reason, refCode) 가 account→user_id→adjustment 로 라우팅

Proto

  • wallet.proto 의 9개 요청 메시지(WalletJobsRequest, WalletNodesRequest, ClaimVirtualNodesRequest, WalletEarningsRequest, WalletEarningsTodayRequest, WalletReceiptsRequest, WalletNodesDetailRequest, WalletEarningsByRangeRequest, WalletEarningsSummaryRequest) 에서 wallet_address 필드 제거
  • 서버 codec(internal/server/jsoncodec.go) 에 DiscardUnknown: true 추가 — 아직 남아있는 클라이언트가 wallet_address 필드를 보내도 마이그레이션 기간 동안 수용

Handler

  • handler/wallet_auth.go: requireAuthenticatedWallet 제거 → requireUser(user JWT 만 허용) + resolvePrimaryWallet(virtual-node claim 등에서 사용)
  • handler/wallet.go: 6개 RPC(GetJobs/GetNodes/ClaimVirtualNodes/GetEarnings/GetEarningsToday/GetReceipts) caller user_id 기반으로 재작성. virtual-node 집계는 user→wallets 이터레이션 후 합산
  • handler/wallet_vip.go: 3개 RPC(GetNodesDetail/GetEarningsByRange/GetEarningsSummary) user_id 기반으로 전환. wallets 명단 없으면 빈 응답 또는 0 합산

Engine / RPCBridge

  • engine/rpcbridge.go::UpdateWalletBalance → db.CreditWalletForReward(wallet, delta, "scheduler_reward") 로 대체. 등록되지 않은 wallet 은 silent drop(레거시 노드 호환)

SDK

  • sdk/api.go: 9개 Wallet RPC 의 JSON payload 에서 walletAddress 필드 제거. sdk/call_test.go 동일으로 업데이트

Tests

  • internal/handler/test_helpers.go: uniqueTestUserID, ctxWithUser, seedUserWithWallet 헬퍼 추가
  • wallet_today_test, wallet_vip_test, wallet_virtual_nodes_test, friends_halving_test, virtual_node_creditor_test, admin_cleanup_test, agx_halving_test, virtual_credit_overlap_test, virtual_node_claims_test 를 새 인증 모델에 맞춰 수정: CreateWallet (제거됨) 호출 삭제, ContextWithWallet → ctxWithUser(seedUserWithWallet(...)), proto 요청에서 WalletAddress: 필드 제거

문서

  • CLAUDE.md Identity tables / AGX accounting 설명 업데이트, schema_version v13 표기

검증

  • go build ./... PASS
  • go vet ./... PASS (warnings 0)
  • go test ./... PASS — 모든 unit 테스트 완료(integration 테스트는 TEST_DATABASE_URL 미설정으로 skip)

DoD 체크

  • make build, make test 통과
  • WalletService 9개 RPC 가 user JWT 없으면 Unauthenticated 거부 (require_user_token 패턴)
  • Wallet 잔액 = Σ receipts (user_id) + Σ adjustments (user_id) 로 계산
  • wallet_adjustments 으로 friend reward + scheduler reward + redeem(추후) 계도 구축 가능 (store 계층 되)

후속 (Phase 3+ 이슈)

  • FriendsService 테이블 user_id 전환 (friends.inviter_id/invitee_id → user_id; referral_claims/rewards_log user_id)
  • Admin Dev Console GoTrue Sign Up / Log In proxy + UI (#424 백포트)
  • nodes.owner_wallet_address 제거, virtual_node_assignments / virtual_node_credits / virtual_node_packages 을 user_id 직접 키로 전환

JL James Lee이(가) 6달 전에 변경 Actions #5

  • 다음에 진행할 일감:에 이슈 #436: [Go backport] Admin Dev Console GoTrue UI — Phase 3이(가) 추가되었습니다.

CP Chris Park이(가) 6달 전에 변경 Actions #6

  • 담당자을(를) James Lee에서 Henry Park(으)로 변경되었습니다.
Actions

내보내기 PDF Atom