Display real-time share pool balance (积分股池实时余量) in the total
contribution card on the contribution page.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add CDC consumer to listen for UserWalletCreated events from mining-wallet-service
- Create trading accounts when user contribution wallets are created (lazy creation)
- Add WalletSystemAccountCreated handler for province/city system accounts
- Add seed script for core system accounts (HQ, operation, cost, pool)
- Keep auth.user.registered listener for V2 new user registration
This ensures trading accounts are created in sync with wallet accounts,
supporting both V2 new users and V1 migrated users.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove accountSequence (ID: xxxx) display from profile page
- Rename "手机:" label to "ID:" for phone number display
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update all formatDecimal, formatNumber, formatPercent, formatCompactNumber
and formatShareAmount calls to use 8 decimal precision for consistent display
across all pages (dashboard, users, reports, system-accounts).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Effective contribution should equal theoretical total (totalTrees * 22617)
since it includes all parts: personal 70% + operation 12% + province 1% +
city 2% + level 7.5% + bonus 7.5% = 100%.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed "全网算力" card to show theoretical total (totalTrees * 22617) instead
of effective contribution. Added effective contribution to subValue for reference.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Backend: Add status filter to getPlantingLedger and getPlantingSummary
- Frontend: Change Row to Wrap for info items to prevent width overflow
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Map miningMinute->distributionMinute, minedAmount->shareAmount,
secondDistribution->priceSnapshot to match entity fields
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add totalTrees field from syncedAdoption aggregate
- Rename fields: networkLevelPending, networkBonusPending
- Stats card: show level pending and bonus pending separately
- Add new stats card for total trees count
- Price overview: 2-row layout showing all contribution metrics
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add networkPendingContribution and networkBonusPendingContribution to API
- Display combined pending contribution (teamLevel + teamBonus) in stats card
- Replace 'total contribution' with 'pending contribution' in price overview
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, totalContribution was incorrectly set to effectiveContribution.
Now correctly calculated as: personal + teamLevel + teamBonus
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add networkTotalContribution field to dashboard API response
- Display total hashrate alongside effective hashrate in stats cards
- Update price overview to show both effective and total contribution
- Change grid from 3 to 4 columns in price overview
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add mining records page showing distribution history with share amounts
- Add planting records page with adoption summary and detailed records
- Remove 推广奖励 and 收益明细 from profile page
- Add planting-ledger API endpoint and data models
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Profile page: 团队上级 shows '15' instead of actual unlockedBonusTiers
- Contribution page: 已解锁上级 shows '15级' instead of actual value
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Changed "VIP等级" label to "团队上级" in profile stats row
- Changed display value from vipLevel (V3 format) to unlockedBonusTiers (raw number)
- Changed "直推人数" label to "引荐人数" for consistency
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add hideAmountsProvider to control amount visibility
- Add tap handler to eye icon in total contribution card
- Toggle icon between visibility_outlined and visibility_off_outlined
- Hide amounts with **** when toggled in:
- Total contribution value
- Three column stats (personal, team level, team bonus)
- Today's estimated earnings
- Contribution detail summary rows
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Reduce bottom SizedBox from 100 to 24 on all four main navigation
pages (contribution, trading, asset, profile) to eliminate excessive
whitespace when scrolling to bottom.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Rename page class from ContributionRecordsPage to ContributionRecordsListPage
- Add typedef RecordsPageData for ContributionRecordsPage data model
- Fix import statements and unused variable
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create contribution_records_page.dart with full list view
- Pagination support with page navigation
- Filter by source type (personal, team level, team bonus)
- Show detailed info: tree count, base contribution, rate, amount
- Display effective/expire dates and status badges
- Update contribution_page.dart detail card
- Show category summary instead of record list
- Display three categories with icons: personal, team level, team bonus
- Add navigation to full records page via "查看全部"
- Add route configuration for /contribution-records
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, adoptions were synced with hardcoded contributionPerTree=1,
resulting in contribution values like 0.7 instead of the expected 15831.9.
Now the handler fetches the actual contribution rate from ContributionRateService
based on the adoption date, storing values like:
- Personal (70%): 22617 × 70% = 15831.9
- Team Level (0.5%): 22617 × 0.5% = 113.085
- Team Bonus (2.5%): 22617 × 2.5% = 565.425
Note: Historical data may need migration to apply the correct multiplier.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Kong routes /api/v2/auth/* to auth-service without stripping the path,
so controllers need 'auth/' prefix to match frontend requests:
- SmsController: 'sms' -> 'auth/sms'
- PasswordController: 'password' -> 'auth/password'
- UserController: 'user' -> 'auth/user'
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use cached auth state from AuthNotifier instead of ref.read() to avoid
"Cannot use ref functions after provider changed" exception during rebuild.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Changed `record.finalContribution` to `record.amount` for getting final contribution value
- Added optional chaining to prevent undefined errors
- Added default values for safety
The ContributionRecordAggregate uses `amount` property, not `finalContribution`.
This was causing "Cannot read properties of undefined (reading 'value')" errors.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ContributionStats entity and model for network-wide statistics
- Add /api/v2/contribution/stats endpoint
- Implement estimatedEarningsProvider to calculate daily earnings
- Formula: (user contribution / total contribution) × daily allocation
- Update contribution page to display real estimated earnings
- Add debug logs for contribution records API
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Asset page now uses trading-service /asset/my endpoint
- Profile page integrates auth-service /user/profile and contribution-service
- Add new entities: AssetDisplay, PriceInfo, MarketOverview, TradingAccount
- Add corresponding models with JSON parsing
- Create asset_providers and profile_providers for state management
- Update trading_providers with real API integration
- Extend UserState and UserInfo with additional profile fields
- Remove obsolete buy_shares and sell_shares use cases
- Fix compilation errors in get_current_price and trading_page
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add trading burn system with black hole, share pool, and price calculation
- Implement per-minute auto burn and sell burn with multiplier
- Add Kafka event publishing via outbox pattern (order, trade, burn events)
- Add user.registered consumer to auto-create trading accounts
- Implement Redis + DB dual idempotency for event processing
- Add price, burn, and asset API controllers
- Add migrations for burn tables and processed events
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Publish UserWalletCreated when a new wallet is created
- Publish UserWalletUpdated when wallet balance changes
- Events sent to cdc.mining-wallet.outbox topic for mining-admin-service
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add handler for CONTRIBUTION_CREDITED events from mining-wallet-service
to sync user wallet data to synced_user_wallets table.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Return usdtAvailable, usdtFrozen, pendingUsdt, settleableUsdt,
settledTotalUsdt, expiredTotalUsdt instead of old field names
- Query SyncedUserWallet table for GREEN_POINTS wallet data
- Use miningAccount.availableBalance for pendingUsdt
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add @Public() decorator to MiningController to allow mining-admin-service
to fetch mining records without authentication.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed event handler to:
- Listen to 'cdc.contribution.outbox' topic (CDC/Debezium format)
- Handle 'ContributionAccountUpdated' events instead of 'ContributionCalculated'
- Use effectiveContribution for mining power calculation
This fixes the issue where mining accounts had zero totalContribution
because they weren't receiving contribution sync events.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update getUserMiningRecords to call mining-service API instead of
returning empty records. This enables the admin dashboard to display
actual user mining records.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
NestJS matches routes in definition order. The :category/:key route was
matching mining/status before the specific mining routes. Moved mining
routes before the parameter routes to fix routing.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add debug logging to trace mining service calls
- Return error object instead of null when data is missing
- Include error message in response for debugging
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Clean NEXT_PUBLIC_API_URL to remove trailing /api/v2 if present,
preventing paths like /api/v2/api/v2/configs/mining/status
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Browser cannot access Docker internal URLs like http://mining-admin-service:3023.
Always use /api which is proxied by Next.js rewrites to the backend service.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add GET and POST /configs/transfer-enabled endpoints to control
the transfer switch. Routes are placed before :category/:key to
avoid being matched as path parameters.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
mining-admin-service uses TransformInterceptor which wraps all responses
with { success, data, timestamp } format. Frontend needs to access
response.data.data to get the actual data.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 添加ts-node/typescript到生产环境以支持seed执行
- 启动脚本中添加prisma db seed执行
- 复制tsconfig.json到生产环境
参考mining-wallet-service的Dockerfile配置
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add admin endpoints:
- GET /admin/status - Get mining system status
- POST /admin/initialize - Initialize mining config (one-time)
- POST /admin/activate - Activate mining distribution
Add prisma seed script for database initialization:
- MiningConfig: 100.02B total shares, 200万 distribution pool
- BlackHole: 100亿 burn target
- MiningEra: First era with 100万 distribution
- PoolAccounts: SHARE_POOL, BLACK_HOLE_POOL, CIRCULATION_POOL
Based on requirements:
- 第一个两年分配100万积分股
- 第二个两年分配50万积分股(减半)
- 100亿通过10年销毁到黑洞
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use 'all' instead of empty string for SelectItem value (Radix requirement)
- Add null safety for items array with fallback to empty array
- Fix potential undefined access on data.items
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Frontend expects flat DashboardStats and RealtimeData interfaces.
Transform backend nested response to:
- totalUsers, adoptedUsers, networkEffectiveContribution, etc.
- currentMinuteDistribution, activeOrders, pendingTrades, etc.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
System initialization is now handled by seed scripts and CDC sync,
so the manual initialization UI is no longer needed.
Removed:
- Frontend: initialization page and sidebar menu item
- Backend: InitializationController and InitializationService
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change controller path from /audit-logs to /audit to match frontend
- Transform response to frontend expected format (items, totalPages, etc.)
- Map admin.username to adminUsername field
- Add keyword query parameter support
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add ReportsController with /reports/daily endpoint that maps the
dashboard service data to the format expected by the frontend.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update categorizeAccounts to use correct account types returned by backend:
- Core accounts: HEADQUARTERS, OPERATION, FEE
- Region accounts: PROVINCE, CITY
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change SystemAccountsService to read from syncedWalletSystemAccount and
syncedWalletPoolAccount tables instead of local tables. This fixes the
issue where the frontend shows "暂无数据" despite data being synced.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add WalletSystemAccountCreated and WalletPoolAccountCreated events:
- seed.ts: publish events when creating HQ/OP/FEE and pool accounts
- contribution-wallet.service.ts: publish events when auto-creating
province/city system accounts
This enables mining-admin-service to sync system accounts via CDC.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use unitOfWork.isInTransaction() to detect if already in a transaction
context (called from ContributionCalculationService). If so, reuse the
existing transaction instead of opening a new one, preventing Prisma
interactive transaction timeout errors.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use provinceCode directly instead of inferring from cityCode
- Use code as name for province/city records
- Add ts-node to production for seed execution
- Run prisma db seed on container startup
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a user's direct referral count reaches 2 or 4, the system now automatically
backfills previously pending TEAM_BONUS (T2/T3) contributions that were allocated
to headquarters while waiting for unlock conditions.
- Add BonusClaimService for handling bonus backfill logic
- Add findPendingBonusByAccountSequence and claimBonusRecords to repository
- Integrate bonus claim into updateReferrerUnlockStatus flow
- Add BonusClaimed event consumer in mining-wallet-service
- Generate ledger records for backfilled contributions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add prisma seed to initialize core system accounts (HQ, OP, FEE) and pool accounts
- Auto-create province/city system accounts on-demand during contribution distribution
- Province/city regions are also auto-created if not exist
This ensures:
1. Core accounts exist after deployment (via seed)
2. Province/city accounts are created dynamically as orders come in
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change consumers from @Injectable to @Controller for @EventPattern to work
- Move consumers from providers to controllers array in module
- Add subscribe.fromBeginning config to Kafka microservice
The consumers were not receiving messages because NestJS microservices
require @EventPattern handlers to be in @Controller classes, not just
@Injectable services.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed system-accounts/initialize and pool-accounts/initialize endpoints from
@AdminOnly to @Public to allow deploy scripts to call them without authentication.
These endpoints are only accessible from internal network.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use admin.resetOffsets({ earliest: true }) before connecting consumer
to ensure CDC sync always starts from the beginning of Kafka topics,
regardless of previously committed offsets.
This fixes the infinite loop issue where existing consumer groups
had committed offsets at high watermark, causing eachMessage to
never be called.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change CDC consumer startup from blocking await to non-blocking .then()
so HTTP server starts immediately and /health/cdc-sync API is accessible
for deploy script to poll sync status.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change await to .then() for cdcConsumer.start()
- Allows HTTP endpoints to be accessible during CDC sync
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add initialSyncCompleted flag to track CDC sequential sync completion
- Add getSyncStatus() method to CDCConsumerService
- Add /health/cdc-sync endpoint to expose sync status
- Update deploy-mining.sh to wait for CDC sync completion before calling publish APIs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previous consumer group had already consumed messages, so fromBeginning
had no effect. Now using timestamp-based unique group id to ensure
fresh consumption from beginning each time.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The previous change was wrong - running sequential consumption in
background defeats its purpose. The whole point is to ensure data
dependency order (users -> referrals -> adoptions) before any other
operations can proceed.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Prevents blocking NestJS onModuleInit during CDC sync by running
the sequential consumption in the background with error handling.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements sequential phase consumption to ensure correct data sync order:
1. User accounts (first)
2. Referral relationships (depends on users)
3. Planting orders (depends on users and referrals)
Each phase must complete before the next starts, guaranteeing 100%
reliable data dependency ordering. After all phases complete, switches
to continuous parallel consumption for real-time updates.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Reverts commits:
- 1fbb88f7: setDirectReferralAdoptedCount change
- 471702d5: ancestor_path chain building change
These changes were made without authorization. The original code was correct.
MINING_ENABLED filtering (from dbf97ae4) is preserved.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed updateReferrerUnlockStatus to:
1. Create account if not exists (for full-reset scenarios)
2. Use setDirectReferralAdoptedCount instead of increment loop
3. This ensures the count is always accurate regardless of processing order
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Users were being redirected to login page when clicking navigation
because the background token refresh was failing and clearing user state.
Token refresh should only happen when API returns 401, not on every app launch.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add system account types and display metadata
- Create API layer with getList and getSummary endpoints
- Add React Query hooks for data fetching
- Create AccountCard, AccountsTable, SummaryCards components
- Refactor page with tabs, refresh button, and error handling
- Add Alert UI component
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Root cause: CDC sync order issue caused referrerAccountSequence to be null,
resulting in empty ancestor chain and all TEAM_LEVEL contributions going to unallocated.
Changes:
- buildAncestorChainFromReferral: Uses ancestor_path (contains complete user_id chain) to build upline chain
- getDirectReferrer: Gets direct referrer using ancestor_path as fallback
- findAncestorChain: Updated to use ancestor_path when available
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Only process adoptions with MINING_ENABLED status for contribution calculation.
This fixes the bug where non-final adoption records (PENDING, PAID, etc.) were
incorrectly being processed, causing duplicate contribution records.
Affected methods:
- findUndistributedAdoptions: only process MINING_ENABLED adoptions
- getDirectReferralAdoptedCount: only count users with MINING_ENABLED adoptions
- getTotalTreesByAccountSequence: only sum trees from MINING_ENABLED adoptions
- getTeamTreesByLevel: only count MINING_ENABLED adoptions
- countUndistributedAdoptions: only count MINING_ENABLED adoptions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ContributionAccountUpdatedEvent for real-time account updates
- Publish outbox events when saving distribution results
- Publish outbox events when updating adopter/referrer unlock status
- Add incremental sync every 10 minutes for recently updated accounts
- Add daily full sync at 4am as final consistency guarantee
- Add findRecentlyUpdated repository method for incremental sync
Three-layer sync guarantee:
1. Real-time: publish events on every account update
2. Incremental: scan accounts updated in last 15 minutes every 10 mins
3. Full sync: publish all accounts daily at 4am
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove conditional skip logic in CDC handlers
- Always sync all field updates (including status changes)
- Trigger contribution calculation only when status becomes MINING_ENABLED
- Fix user and referral handlers to sync all fields without skipping
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Revert the previous change that removed the status filter. The stats
should only count adoptions with MINING_ENABLED status, as only those
are active for mining. The issue is likely that the status field in
synced_adoptions table doesn't have the correct value.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The adoption stats were showing 0 because the synced_adoptions table
contains status values directly from 1.0 system (PAID, POOL_INJECTED, etc.)
rather than MINING_ENABLED. Since contribution-service doesn't update the
status after calculating contributions, we now count all synced adoptions.
Changes:
- Remove status filter in getAdoptionStatsForUsers
- Remove status filter in getUserDetail adoption queries
- Remove status filter in getUserAdoptionStats for referral tree
- Add order count display in user detail page
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Backend:
- Add personalOrders and teamOrders to adoption stats
- Return order count alongside tree count in user list API
Frontend:
- Add personalAdoptionOrders and teamAdoptionOrders to UserOverview type
- Display format: "树数量(订单数)" e.g. "6(3单)"
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Only count adoptions with status='MINING_ENABLED' when calculating:
- Personal adoption count (user list)
- Team adoption count (user list)
- Personal adoption stats (user detail)
- Direct referral adoptions (user detail)
- Team adoptions (user detail)
- Referral tree adoption stats
This fixes incorrect adoption counts that included pending/unconfirmed orders.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fix hydration race condition where token check happened before
localStorage was read. Now waits for client-side initialization
before deciding whether to redirect to login.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
kafkacat/kcat not available in containers. Switch to kafka-console-producer
with null.marker property to send tombstone messages for Debezium offset deletion.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Debezium Connect container uses OFFSET_STORAGE_TOPIC=debezium_offsets,
not the default connect-offsets. This fix updates the tombstone method
to use the correct topic name.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This fixes an issue where Debezium would skip initial snapshot after
full-reset because the connector offset persisted in Kafka Connect's
internal connect-offsets topic.
The fix adds two strategies to delete connector offsets:
1. REST API method (Kafka Connect 3.6+): DELETE /connectors/<name>/offsets
2. Tombstone method (Kafka Connect 3.5-): Send NULL messages via kafkacat
Reference: https://debezium.io/documentation/faq/#how_to_remove_committed_offsets_for_a_connector
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Old messages in Kafka topics were corrupting the sync because they contained
outdated data from previous resets. Now we delete the outbox topics during
full-reset to ensure clean re-sync.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The full-reset script was missing the cleanup of rwa_mining_admin.processed_events
table, which caused stale idempotency records to prevent re-consumption of
contribution outbox events after reset.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace skeleton blocks with shimmer text placeholders across all pages:
- Asset page: show full UI with flickering numbers during load
- Trading page: show full UI with flickering market data during load
- Contribution page: show full UI with flickering stats during load
- shimmer_loading.dart: add ShimmerText, DataText, AmountText components
This approach shows the complete UI immediately, with only the dynamic
number values flickering while data loads - much better UX than showing
grey skeleton blocks.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Optimize splash page: reduce wait to 500ms, refresh token in background
- Cache SharedPreferences instance to avoid blocking API requests
- Add global 401 handler to auto-redirect to login page
- Create shimmer loading components (ShimmerLoading, ShimmerBox, skeletons)
- Replace CircularProgressIndicator with skeleton screens across all pages
- Add keepAlive + auto-invalidation (5min) to providers to reduce API calls
- Fix trading page: invalidate globalStateProvider after trade for data sync
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The outbox_events table uses outbox_id as the primary key column name
(mapped from id in Prisma). When Debezium captures changes, the message
contains outbox_id field, not id. This caused all events to have
undefined eventId, resulting in duplicate detection treating all events
as duplicates after the first one.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Root cause: calculateForAdoption uses separate DB connections, which
cannot see uncommitted data in Serializable isolation level, causing
"Adoption not found" errors.
Solution (following Kafka Idempotent Consumer best practice):
- Add TransactionalCDCHandlerWithResult<T> type for handlers with return
- Add withIdempotencyAndCallback() wrapper for post-commit callbacks
- Add registerTransactionalHandlerWithCallback() registration method
- AdoptionSyncedHandler.handle() now returns AdoptionSyncResult
- Contribution calculation runs AFTER transaction commits via callback
Reference: Lydtech Consulting - Kafka Idempotent Consumer Pattern
https://www.lydtechconsulting.com/blog/kafka-idempotent-consumer-transactional-outbox
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Problem: full-reset script resets Kafka consumer offsets but doesn't
clear the processed_cdc_events table. When migrations run, containers
may start and consume CDC events, inserting records into this table.
After offset reset, the service restarts and detects all events as
"duplicates" because the idempotency records still exist.
Solution: Add TRUNCATE processed_cdc_events step after CDC offset reset
in Step 8, before starting services. This ensures the idempotency table
is in sync with the Kafka offset position.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The bcrypt package requires native compilation. Added build dependencies
to the builder stage so npm ci can compile bcrypt successfully.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add comments explaining unique key composition:
- CDC events: (source_topic, offset) = Kafka topic + message offset
- Outbox events: (source_service, event_id) = service name + outbox ID
- Fix contribution-service migration:
- Extend source_service column from VARCHAR(50) to VARCHAR(100)
- Set source_service as NOT NULL to match schema
- Use snake_case for index name consistency
- Clarify that offset/event_id are NOT database auto-increment IDs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update splash_page.dart to orange theme (#FF6B00) matching other pages
- Change app name from "榴莲挖矿" to "榴莲生态"
- Fix refreshTokenIfNeeded to properly throw on failure instead of
silently calling logout (which caused Riverpod ref errors)
- Clear local storage directly on refresh failure without remote API call
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements 100% exactly-once semantics for CDC events from 1.0 identity-service
(user_accounts table) to auth-service.
Key changes:
- Add ProcessedCdcEvent model with (sourceTopic, offset) unique constraint
- Implement processWithIdempotency() using Serializable transaction isolation
- All database operations now use the transaction client
- Outbox event creation is also within the same transaction
This ensures that:
1. Each CDC event is processed exactly once
2. Idempotency record and business logic are in the same transaction
3. Outbox event publishing is atomic with data sync
4. Any failure causes complete rollback
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements 100% exactly-once semantics for CDC events from 1.0 databases
(identity-service, planting-service, referral-service) to contribution-service.
Key changes:
- Add ProcessedCdcEvent model with (sourceTopic, offset) unique constraint
- Add withIdempotency() wrapper using Serializable transaction isolation
- Add registerTransactionalHandler() for handlers requiring idempotency
- Modify CDC handlers to accept external transaction client
- All database operations now use the passed transaction client
This ensures that:
1. Each CDC event is processed exactly once
2. Idempotency record and business logic are in the same transaction
3. Any failure causes complete rollback
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use Prisma $transaction with Serializable isolation level
- Insert idempotency record FIRST, then execute business logic
- Unique constraint violation (P2002) indicates duplicate event
- All operations atomic - either fully commit or fully rollback
- Modified all handlers to accept transaction client parameter
- Removed old non-atomic isEventProcessed/recordProcessedEvent methods
This ensures 100% data consistency for CDC synchronization, which is
critical for financial data where any error is catastrophic.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use (sourceTopic, eventId) as composite unique key in processed_events
- Add sourceTopic to ServiceEvent for globally unique idempotency key
- Wrap all handlers with withIdempotency() for duplicate event detection
- Fix ID collision issue between different service outbox tables
This implements the industry-standard CDC exactly-once semantics pattern.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Wrap content in LayoutBuilder + ConstrainedBox to ensure proper
scrolling behavior when content exceeds viewport height.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changes:
1. Delete Debezium connectors BEFORE dropping databases (releases replication slots)
2. Start services BEFORE registering connectors (ensures tables exist and data is synced)
3. Register connectors AFTER services sync from 1.0 CDC (snapshot.mode=initial captures existing data)
4. Add wait time for connectors to initialize before publishing data
Step order: stop services → delete connectors → drop DBs → create DBs → migrate →
start services → wait for sync → register connectors → publish data
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update login/register pages to use orange color scheme (#FF6B00)
matching the navigation pages design
- Fix SafeArea bottom: false on all navigation pages since MainShell
handles bottom safe area via bottomNavigationBar
- Add AlwaysScrollableScrollPhysics to asset page for consistent scroll
- Increase bottom padding to 100px on all navigation pages to clear
the navigation bar
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The full-reset function was calling contribution-records/publish-all API
which caused duplicate records in mining-admin-service because:
- Contribution records are already published to outbox when calculated
- Debezium automatically captures outbox_events and sends to Kafka
- Calling publish-all again creates duplicate events with different IDs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The toDto method was accessing non-existent properties on ContributionAccountAggregate:
- teamLevelContribution -> totalLevelPending
- teamBonusContribution -> totalBonusPending
- totalContribution -> effectiveContribution
- isCalculated -> true (always calculated when account exists)
- lastCalculatedAt -> updatedAt
This was causing "Cannot read properties of undefined (reading 'value')" error
on GET /api/v2/contribution/accounts/{accountSequence}
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Delete old green-themed HomePage and its widgets (asset_card, price_card, quick_actions)
- Remove /home route from router configuration
- Fix SplashPage to redirect to /contribution instead of /home after login
- Now all navigation goes through the new orange-themed UI pages
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Delete incorrect TEAM_BONUS records (where account_sequence !=
source_account_sequence) on each container startup after migrations.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove the UPDATE statement that referenced non-existent columns.
The contribution_accounts table uses different field structure.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use treeCount * contributionPerTree from adoption record to calculate
the actual distribution amounts (70%, 12%, 1%, 2%, 15%) instead of
deriving from contribution_records table.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
TEAM_BONUS should only be given to the adopter themselves, not to their
uplines. This migration deletes all TEAM_BONUS records where
account_sequence != source_account_sequence.
Also updates contribution_accounts totals in contribution-service.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The AuthEventBus was causing "Cannot use ref functions after the
dependency of a provider changed" error when 401 responses triggered
logout during provider rebuilds.
Now 401 handling is done through normal exception flow in splash page
and route guards respond to isLoggedInProvider state changes.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Login fixes:
- Add AuthEventBus for global 401 error handling with auto-logout
- Add route guards with GoRouter redirect to protect authenticated routes
- Remove setMockUser() security vulnerability and legacy login() dead code
- Remove unused AuthInterceptor class
Contribution page:
- Add ContributionRecord entity and model for records API
- Connect contribution details card to GET /accounts/{id}/records endpoint
- Display real team stats (direct referrals, unlocked levels/tiers)
- Calculate expiration countdown from actual record data
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add distributionSummary Text column to synced_adoptions table for storing
distribution details calculated during contribution calculation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changes:
1. contribution-service:
- Add distributionSummary field to SyncedAdoption schema
- Store distribution summary after contribution calculation
2. mining-admin-service:
- Add distributionSummary field to SyncedAdoption schema
- Calculate actual distribution from contribution_records table
- Return distribution details in planting ledger API
3. mining-admin-web:
- Display distribution details in planting ledger table
- Show: 70%(amount) personal, 12%(amount) operation,
1%(amount) province, 2%(amount) city, 15%(amount) team
- Show team distribution breakdown (distributed vs unallocated)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
TEAM_BONUS (7.5% = 2.5% × 3 tiers) should be given to the adopter themselves,
not to their direct referrer. The unlock conditions are:
- T1 (2.5%): Self adoption (always unlocked when adopting)
- T2 (2.5%): 2+ direct referrals adopted
- T3 (2.5%): 4+ direct referrals adopted
Also fixed findAncestorChain to correctly include the first ancestor
in the chain instead of skipping it.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Switch to Prisma's "prisma" relation mode to handle CDC event ordering issues.
This mode emulates foreign key relations at the Prisma Client layer instead of
creating database-level FK constraints, which is the recommended approach for
CDC scenarios where event arrival order cannot be guaranteed.
Reference: https://www.prisma.io/docs/orm/prisma-schema/data-model/relations/relation-mode
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
CDC events arrive asynchronously and order is not guaranteed.
Child records (referrals, accounts) may arrive before parent (users).
This follows CDC best practices: destination tables should not have FK constraints.
Reference: https://estuary.dev/blog/cdc-done-correctly/
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add synced_contribution_records table for tracking contribution ledger
- Add synced_network_progress table for tracking network-wide stats
- Revert Dockerfile to use prisma migrate deploy
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change Dockerfile to use `prisma db push` instead of `migrate deploy`
- Add publish steps for contribution records and network progress in full-reset
- This ensures new tables are created automatically when schema changes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add isHeartbeatMessage to detect heartbeat messages (only have ts_ms field)
- Skip processing for heartbeat messages to avoid unnecessary warnings
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add isDebeziumOutboxEvent to detect outbox table CDC messages
- Add handleDebeziumOutboxEvent to extract service event from payload.after
- Fix CDC consumer not recognizing events from contribution-service outbox
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change saveMany to return saved records with IDs
- Update saveDistributionResult to use saved records for event publishing
- Contribution records are now automatically synced to mining-admin-service
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update ContributionRecord type to match backend response fields (sourceType, baseContribution, distributionRate, etc.)
- Update contribution-records-list component with improved UI showing source type badges, user info, tree count, and expiry status
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix updateContribution to properly update levelXPending and bonusTierXPending fields
- Add NetworkAdoptionProgress and DailyContributionRate tables for tracking contribution coefficient
- Create ContributionRateService for dynamic rate calculation (base 22617, +0.3% per 100 trees after 1000)
- Add ContributionRecordSynced and NetworkProgressUpdated events for CDC sync
- Add admin endpoints for network progress query and contribution records publishing
- Update mining-admin-service to sync contribution records and network progress
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add detailed [CDC] prefixed logs to all CDC handlers:
- cdc-consumer.service.ts: log message parsing, handler dispatch
- user-synced.handler.ts: log user sync operations with field details
- adoption-synced.handler.ts: log adoption sync and contribution calc
- referral-synced.handler.ts: log referral relationship sync
All logs use consistent [CDC] prefix for easy filtering.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove HOT_WALLET and COLD_WALLET from initializeCoreAccounts
- Remove BLOCKCHAIN from counterpartyType union
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove KavaBlockchainService and blockchain.repository
- Remove BlockchainIntegrationService and BlockchainController
- Update health controller to remove blockchain check
- Clean up Prisma schema (remove blockchain models and enums)
- Add migration to drop blockchain-related tables
This functionality will be re-implemented when needed.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
将增量migration改为完整的初始化migration,包含所有表的CREATE TABLE语句。
原migration使用ALTER TABLE假设表已存在,但这是服务的第一个migration文件。
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- mining-admin-service: 更新package-lock.json以包含bcrypt依赖
- auth-service: Dockerfile添加python3 make g++用于编译bcrypt
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
使用 BoxFit.contain 替代 BoxFit.cover,
图片保持原比例显示,不足部分用黑边填充。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
移除划转按钮的临时禁用标志,恢复正常功能。
用户点击划转按钮后将跳转到划转页面。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
在用户管理页面的钱包分类账明细表格中添加"备注"列,
用于显示转账对象信息,如"转账至 D25XXXXXX"或"来自 D25XXXXXX 的转账"。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
问题:创建授权失败时只显示"Request failed with status code 400"
用户无法了解失败的真实原因(如用户未种树、授权冲突等)
修复:
- handleCreate和handleRevoke的catch块优先从err.response.data.message提取后端错误
- 后端已有完善的错误提示如"用户尚未认种任何树,无法授权"
- 前端现在能正确显示这些提示帮助管理员了解真实情况
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
合同生成时使用 new Date().toISOString().split('T')[0] 获取日期,
该方法返回UTC时间,导致北京时间凌晨签署的合同显示为前一天日期。
修复方案:新增 getBeijingDateString() 函数,将UTC时间转换为北京时间(UTC+8)
影响范围:仅影响PDF合同上显示的签署日期,不影响数据库时间戳或业务逻辑
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
不同授权事件使用不同的字段名:
- province 事件:provinceCode/provinceName
- city 事件:cityCode/cityName
- community 事件:communityName
- 通用:regionCode/regionName
现在正确处理所有变体,避免显示 "undefined undefined 完成授权"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
只显示 status !== 'REVOKED' 的角色对应的考核记录
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
根据 authData.roles 中的角色类型过滤 assessments,
避免显示用户没有的角色(如只有市授权但显示省考核)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
日志输出时不再使用 JSON.stringify 序列化包含 BigInt 的对象,
改为直接输出关键字段值,避免 "Do not know how to serialize a BigInt" 错误
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
将 Dockerfile 和 docker-compose.yml 中的健康检查路径从
/api/health 修改为 /api/v1/health,与实际 API 路由保持一致
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 添加 filter 过滤掉 data 为 null 的账户
- 修复空白卡片显示问题(账户数据不存在时不显示卡片)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 所有方法改为使用 .data.data 解析响应数据
- API响应结构为 { success, data: { code, message, data } }
- 修复 "e.map is not a function" 错误
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
在个人中心设置菜单中添加"联系客服"入口,点击后显示弹窗,
用户可以查看客服的QQ号和微信号,并支持一键复制到剪贴板。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
移除公共账户和因子卡片的 dUSDT 和 KAVA 单位显示,保持界面简洁一致。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
添加 console.log 输出,用于调试固定账户明细数据匹配问题。
请在浏览器开发者工具控制台查看输出,确认后端返回的数据格式。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
将固定系统账户的分类账明细从每个卡片内部展开改为在卡片网格下方
的公共区域显示。点击任一账户的"查看明细"按钮,明细表格在下方
完整展示,提供更好的阅读体验。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
在固定系统账户卡片下方添加"查看明细"按钮,点击后展开显示
该账户的分类账流水记录,包括时间、类型、金额、余额和备注。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
将 bigint 类型的 userId 转换为 number 类型以匹配返回类型定义
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previous format showed meaningless city code like "浙江01市 (330100)".
Now shows cleaner format: "浙江市级 (330100)" for city-level accounts.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Root cause: @@unique([field], name: "xxx") requires { xxx: { field } } syntax
in findUnique/upsert, but code used { field } directly.
Fix: Change to @unique(map: "uk_realtime_stats_date") on the field itself.
This keeps the same database index name while allowing { statsDate } syntax.
No migration needed - only Prisma client type generation changes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace upsert with findFirst + create/update pattern to avoid Prisma
unique constraint syntax issues. The @@unique constraint with a custom
name doesn't allow direct field-based queries in findUnique/upsert.
This approach maintains the same behavior without schema changes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Prisma requires using the named unique constraint (uk_realtime_stats_date)
in where clauses for findUnique and upsert operations. This fixes the
PrismaClientValidationError that was occurring when processing planting
order events.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The wallet-service API requires operatorId parameter but frontend
was not sending it, causing 400 error. Now includes operatorId
and operatorName from current logged-in user.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- wallet-service: 新增 getOfflineSettlementEntries 方法和 API
- reporting-service: 新增客户端方法和 API 转发
- admin-web: 添加明细列表组件和样式,支持展开/收起
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed controller route from 'system-withdrawal' to 'wallets/system-withdrawal'
to align with Kong's /api/v1/wallets/* routing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add system-transfer page with transfer form and order history
- Add SystemWithdrawalService for API calls
- Add useSystemWithdrawal hooks for React Query integration
- Add system-withdrawal types definitions
- Add navigation menu item for system transfer
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
表名应为 planting_orders(复数),不是 planting_order
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add SystemWithdrawalApplicationService to handle system account transfers
- Add SystemWithdrawalController with endpoints for request, query, and account listing
- Add SystemWithdrawalStatusHandler to process blockchain confirmation/failure events
- Add SystemWithdrawalRequestedHandler in blockchain-service to execute ERC20 transfers
- Add getUserByAccountSequence endpoint in identity-service for user lookup
- Support dynamic memo generation based on actual source account name
- Dual-sided ledger entries for system account transfers
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
这些服务不需要同步手续费账户的定义,wallet-service 独立处理。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Ensure new database installations use TEXT type for memo column from the start.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change wallet_ledger_entries.memo from VARCHAR(500) to TEXT to support longer settlement memos.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 在统计卡片上方添加"同伴认种"标题(紫色)
- 在统计卡片下方添加"引荐"、"同伴"、"本人"快捷标签
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
面对面结算和过期收益Tab在数据为空时会崩溃,添加空值检查修复此问题。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change userId to optional in PlantingOrderPaidEvent interface
- Add accountSequence field for user identification
- Remove relatedUserId from activity creation (was causing BigInt error)
- Store accountSequence in metadata instead
Fixes: TypeError: Cannot convert undefined to a BigInt
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Rename account labels:
- 成本账户 → 总部储备
- 运营账户 → 运营账户1
- 总部社区 → 运营账户2
- RWAD待发放池 → 积分股池
- Change all USDT displays to 绿积分 throughout the system account report
- Add getAssetTypeLabel function for asset type mapping in ledger details
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
删除使用嵌套 $queryRaw 进行条件拼接的错误查询,保留简化版本。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
wallet-service API 返回 { success, data } 格式,需要解析 response.data.data
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The system account balances were showing 0 because data was being fetched
from authorization-service.system_accounts table instead of the actual
wallet-service.wallet_accounts table where funds are stored.
Changes:
- wallet-service: Add getAllSystemAccounts() method to query all system
accounts (fixed S*, province 9*, city 8*) with actual balances
- wallet-service: Add /wallets/statistics/all-system-accounts API endpoint
- reporting-service: Update SystemAccountReportApplicationService to fetch
data from wallet-service instead of authorization-service
- reporting-service: Fix default service URLs to use correct container names
and ports (rwa-wallet-service:3001, rwa-reward-service:3005)
- docker-compose: Add WALLET_SERVICE_URL and REWARD_SERVICE_URL env vars
for reporting-service
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Kong route for the new system account reports API endpoint
at /api/v1/system-account-reports, forwarding to reporting-service.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add missing dependency injection for SystemAccountApplicationService
which is required by InternalAuthorizationController for system account
report statistics API.
- Import SystemAccountRepositoryImpl and SYSTEM_ACCOUNT_REPOSITORY
- Register SystemAccountApplicationService as provider
- Register SYSTEM_ACCOUNT_REPOSITORY with SystemAccountRepositoryImpl
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
## Changes
- Add system account report aggregation APIs in reporting-service
- Add internal statistics APIs in wallet-service, reward-service, authorization-service
- Add system accounts tab in admin-web statistics page
- Enhanced metadata in reward entries for traceability
## Backend Changes
- wallet-service: Add offline settlement summary and system accounts balances APIs
- reward-service: Add expired rewards summary API
- authorization-service: Add fixed accounts list, region accounts summary APIs
- reporting-service: Add HTTP clients and aggregation service for system account reports
## Frontend Changes
- admin-web: Add SystemAccountsTab component with fixed accounts, region summaries,
offline settlement stats, and expired rewards display
## Rollback Instructions
Each file includes rollback comments with [2026-01-04] tag marking new additions.
To rollback: delete files marked as new, remove code sections marked with date comments.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove local storage cache priority to avoid returning wrong address
after account switching. Always fetch from server API to ensure the
address belongs to the currently logged-in user.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The wallet address displayed in long-press mode was incorrectly showing
another user's address from local storage cache. Now fetches the correct
address from the /me API endpoint for the currently logged-in user.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When there are no settlement records to deduct, show a more informative message:
- If user has balance from deposits/transfers: explain it's not from earnings
- If user has no balance: explain there are no settlement records
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The entry.id field is BigInt type from Prisma which cannot be JSON serialized directly.
Convert to string for API response and back to BigInt when storing to database.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change default mode from "指定金额扣减" to "全额线下结算扣减"
to match batch create behavior where empty/0 amount means offline settlement.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When batch creating special deductions:
- Amount empty or 0: auto-switch to offline settlement mode
- Amount > 0: normal deduction mode (requires reason)
- Add hint text in batch create modal for special deduction
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use planting-service's reliable database aggregation for total planting count
instead of reporting-service's Kafka event-driven statistics.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add new functionality for admins to automatically deduct all settled
earnings when creating special deductions with amount=0, marking
each record to prevent duplicate deductions.
- Add OfflineSettlementDeduction model to track deducted records
- Add API endpoints for querying unprocessed settlements and executing batch deduction
- Add mode selection UI in admin-web pending-actions
- Add offline settlement card display in mobile-app special deduction page
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add new endpoint GET /api/v1/planting/stats/global to query planting
statistics directly from the database, providing reliable data source
for verifying reporting-service statistics.
New features:
- GlobalPlantingStats: total tree count, order count, amount
- StatusDistribution: breakdown by order status (PAID to MINING_ENABLED)
- TodayStats: daily statistics with tree count, order count, amount
Implementation:
- Pure additive changes, no modifications to existing code
- Read-only aggregate queries using Prisma aggregate/groupBy
- No database schema changes required
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The 'type' field was missing validation decorator, causing 400 Bad Request
when ValidationPipe with forbidNonWhitelisted was enabled.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The AdminAccount table stores roles in lowercase (admin, super_admin),
but AdminGuard was checking for uppercase (ADMIN, SUPER_ADMIN).
This caused 403 Forbidden errors for authenticated admin users.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Match the global prefix convention used by all other services.
This fixes Kong routing 404 errors for /api/v1/leaderboard/* endpoints.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The leaderboard-service needs to connect to referral-service for
team statistics data. Without this environment variable, it falls
back to localhost:3004 which fails inside Docker network.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The API base URL already includes /api/v1, so the path should be
/leaderboard/status instead of /leaderboard-service/api/v1/leaderboard/status
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add public /leaderboard/status endpoint (no auth required)
- Add LeaderboardService in mobile-app to fetch board status
- Update RankingPage to show "待开启" when board is disabled
- Connect admin-web leaderboard page to real API
- Board toggle now takes effect immediately
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The original migration only used DROP CONSTRAINT which failed silently
because Prisma created an INDEX instead. Added DROP INDEX as well to
handle both cases in future deployments.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Signature field position: x=449.51, y=140.18 (moved further right and up).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Moved signature button field further right (x=435.60) and down (y=113.51).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Updated signature field position to x=427.60 for better alignment.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed to always include revoked records in API query, filtering is done
on frontend side. This ensures all historical records are visible.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed type definition from 'ACTIVE' to 'AUTHORIZED' to match backend API.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The backend returns status as 'AUTHORIZED'/'REVOKED' but frontend was
checking for 'ACTIVE'. Fixed all status comparisons to use correct value.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The findByAccountSequenceAndRoleType query now excludes REVOKED status,
allowing users to be re-authorized after their authorization was revoked.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Hidden txHash display in both transfer details and withdrawal details
as it's not necessary for end users.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed display name from "总部社区" to "总部" in:
- authorization-service
- identity-service seed
- leaderboard-service seed and entity
Note: Existing database records need manual update if already seeded.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Moved the signature field from x=415 to x=470 in the PDF template
to prevent the signature image from covering the "乙方(签字/盖章):" text.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The apiClient interceptor already unwraps response.data, so we should
access .data instead of .data.data to get the actual business data.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously used findAllActive() which only returned users with benefitActive=true,
causing users still in assessment period to be hidden. Now uses findByStatus()
to show all AUTHORIZED users regardless of benefit activation status.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Calculate signature position based on field center instead of left-bottom
corner, so the signature image is properly centered within the field area.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove the ellipsis logic that hides nodes when there are too many.
Now all nodes are displayed and users can scroll horizontally to see them.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The signature button field has a gray background that covers the drawn
signature image when the form is flattened. Now we remove the signature
field after drawing the signature image to prevent this.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change all "社区" labels to "部门" in profile page (所属部门, 上级部门, 下级部门, 部门权益考核, 部门贡献奖励)
- Add SPECIAL_DEDUCTION entry type display name as "面对面结算" in ledger
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The PDF signature field is only 92x51 points, which causes signatures to
appear too small or invisible. Changed to use drawImage() directly on
the page at the field's position with a larger size (150x80 max).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The signature image was 600x200 (3:1 ratio) but the PDF signature
field is 92x51 (1.8:1 ratio). This caused the signature to be scaled
down to only 60% of the field height, making it appear too small.
Changed signature image dimensions to 460x255 (~1.8:1) to better
match the PDF field proportions and maximize signature size.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Admin JWT tokens from identity-service don't include the accountSequence
field (only userId, email, role, type). This caused a 400 error with
message "管理员账户序列号不能为空" when admins tried to grant authorizations.
Changes:
- Update AdminUserId value object to make accountSequence optional
- Use 'ADMIN' as default value when accountSequence is not provided
- Update all controller methods to handle optional accountSequence
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Backend (authorization-service):
- Add QueryAuthorizationsDto for query parameters (roleType, keyword, includeRevoked, page, limit)
- Add queryAuthorizations method to fetch all authorizations with user info
- Add GET /admin/authorizations endpoint for listing authorizations
- Add POST /admin/authorizations/:id/revoke endpoint for revoking authorization
Frontend (admin-web):
- Add authorization.types.ts with RoleType, Authorization, and request types
- Add authorizationService.ts for API calls (list, revoke, grant operations)
- Add useAuthorizations.ts React Query hooks
- Update authorization page to use real API data instead of mock data
- Add loading/error states, pagination, and revoke reason display
- Add new styles for loading, error, pagination, and date columns
The authorization management page now displays all authorized users
from the database with support for filtering by role type, status,
and keyword search.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add complete fiat withdrawal feature that allows users to withdraw
green credits (绿积分) to their bank card, Alipay, or WeChat account
with 1:1 CNY conversion. Key changes:
Backend (wallet-service):
- Update Prisma schema with fiat withdrawal fields (paymentMethod,
bankName, bankCardNo, cardHolderName, alipay*, wechat*, review fields)
- Rewrite withdrawal status enum for fiat flow: PENDING → FROZEN →
REVIEWING → APPROVED → PAYING → COMPLETED (or REJECTED/FAILED)
- Add PaymentMethod enum: BANK_CARD, ALIPAY, WECHAT
- Update WithdrawalOrderAggregate with new fiat withdrawal methods
- Add review/payment workflow methods in WalletApplicationService
- Add internal API endpoints for admin withdrawal management
- Remove blockchain withdrawal event handler (no longer needed)
Frontend (admin-web):
- Add withdrawal review management page at /withdrawals
- Add tabs for reviewing/approved/paying order states
- Add withdrawal service and React Query hooks
- Add types for withdrawal orders and payment methods
- Add sidebar menu item for withdrawal review
Frontend (mobile-app):
- Add withdrawFiat() method to WalletService
- Add PaymentMethod enum with BANK_CARD/ALIPAY/WECHAT
- Create new WithdrawFiatPage for fiat withdrawal input
- Create WithdrawFiatConfirmPage with SMS + password verification
- Add routes for /withdraw/fiat and /withdraw/fiat/confirm
- Keep existing withdraw/usdt (划转) pages unchanged
Note: The existing withdraw_usdt_page.dart is for point-to-point
transfer (划转), which is a different feature from fiat withdrawal.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add complete settlement-to-balance feature that transfers settleable
earnings directly to wallet USDT balance (no currency swap). Key changes:
Backend (wallet-service):
- Add SettleToBalanceCommand for settlement operations
- Add settleToBalance method to WalletAccountAggregate
- Add settleToBalance application service with ledger recording
- Add internal API endpoint POST /api/v1/wallets/settle-to-balance
Backend (reward-service):
- Add settleToBalance client method for wallet-service communication
- Add settleRewardsToBalance application service method
- Add user-facing API endpoint POST /rewards/settle-to-balance
- Build detailed settlement memo with source user tracking per reward
Frontend (mobile-app):
- Add SettleToBalanceResult model class
- Add settleToBalance() method to RewardService
- Update pending_actions_page to handle SETTLE_REWARDS action
- Add completion detection via settleableUsdt balance check
Settlement memo now includes detailed breakdown by right type with
source user accountSequence for each reward entry, e.g.:
结算 1000.00 绿积分到钱包余额
涉及 5 笔奖励
- SHARE_RIGHT: 500.00 绿积分
来自 D2512120001: 288.00 绿积分
来自 D2512120002: 212.00 绿积分
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add accountSequence field to PendingActionResponseDto
- Add helper methods to fetch accountSequence from UserAccount
- Update queryActions and getAction to include accountSequence
- Update admin-web table and detail view to show both fields
- accountSequence displayed prominently, userId shown as secondary info
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change FORCE_KYC check from isCompleted to level1.verified
(FORCE_KYC only requires real-name verification, not all KYC levels)
- Add post-navigation re-check for FORCE_KYC and BIND_PHONE actions
(handles cases where user completes action but page doesn't return true)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Wrap ElevatedButton in SizedBox(width: 72) to prevent
BoxConstraints infinite width error in Row layout.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The API returns a nested structure {success, data: {code, data: [...]}}
but the service was only checking for {actions: [...]} format.
Now correctly extracts the actions list from data.data.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Comment out debugPrint statements in pending actions and contract
check services to reduce log noise during development.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Allow admin to create pending actions using accountSequence (e.g.,
D25122700022) instead of requiring numeric userId.
- Add findUserByIdOrSequence helper method
- Update createAction to use helper
- Update batchCreateActions to use helper
- Update queryActions to support accountSequence filter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Admin Web:
- Redesign create modal to support multi-select action types
- Add drag-and-drop ordering for execution sequence
- Auto-calculate priority based on order (first = highest)
- Add @dnd-kit dependencies for sortable functionality
Flutter Mobile App:
- Add pre-check logic before executing pending actions
- Auto-complete FORCE_KYC if KYC already verified
- Auto-complete BIND_PHONE if phone already bound
- Skip unnecessary user interactions for completed tasks
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
API returns nested structure: { success, data: { code, message, data: {...} } }
After apiClient interceptor unwraps response.data, we still need to access
.data.data to get the actual business data.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The apiClient interceptor already unwraps response.data, so the service
was accessing .data on the already-unwrapped response. Fixed by properly
casting the response type to access the nested data field.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add null-safe access and fallback to empty arrays to prevent
"Cannot read properties of undefined" errors when API returns
unexpected data structure.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add fixed-supply ERC-20 token contract for Durian USDT (dUSDT):
- Total supply: 1 trillion tokens with 6 decimals
- No minting capability - all tokens minted at deployment
- Includes compile and deploy scripts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Skip JWT auth for admin pending-actions endpoints since admin-web
authenticates through a different mechanism (admin-service tokens).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix pending_action_service.dart to access response.data instead of response
- Add Kong route for /api/v1/admin/pending-actions to identity-service
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a fully optional pending actions system that allows admins to configure
specific tasks that users must complete after login.
Backend (identity-service):
- Add UserPendingAction model to Prisma schema
- Add migration for user_pending_actions table
- Add PendingActionService with full CRUD operations
- Add user-facing API (GET list, POST complete)
- Add admin API (CRUD, batch create)
Admin Web:
- Add pending actions management page
- Support single/batch create, edit, cancel, delete
- View action details including completion time
- Filter by userId, actionCode, status
Flutter Mobile App:
- Add PendingActionService and PendingActionCheckService
- Add PendingActionsPage for forced task execution
- Integrate into splash_page login flow
- Users must complete all pending tasks in priority order
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change API from Id2MetaStandardVerify to Id2MetaVerify for two-factor
identity verification (name + ID card number). The previous API was
returning error 440 (no permission).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add ability to backup wallet shares to files and restore from backups:
- Add ShareBackup data class in Models.kt for backup format
- Add exportShareBackup() and importShareBackup() in TssRepository
- Add export/import state and methods in MainViewModel
- Add file picker integration in MainActivity using ActivityResultContracts
- Add import FAB button in WalletsScreen
- Export saves as .tss-backup file with address and timestamp in filename
- Import validates backup format and checks for duplicate wallets
The backup file contains all necessary data to restore a wallet share:
sessionId, publicKey, encryptedShare, threshold, partyIndex, address.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add @OptIn(ExperimentalMaterial3Api::class) to TransferInputScreen
composable to fix compilation error for FilterChip and FilterChipDefaults.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add support for the dUSDT token "绿积分" (Green Points) on both Android
and Electron applications:
Android changes:
- Add TokenType enum and GreenPointsToken config in Models.kt
- Implement ERC-20 balance fetching and transfer encoding in TssRepository
- Update TransactionUtils with ERC-20 transfer support
- Add dual balance display (KAVA + 绿积分) in WalletsScreen
- Add token type selector in TransferScreen
Electron changes:
- Add TokenType and GREEN_POINTS_TOKEN config in transaction.ts
- Implement fetchGreenPointsBalance and ERC-20 transfer encoding
- Update Home.tsx with dual balance display and token selector
- Add token selector styles in Home.module.css
Token contract: 0xA9F3A35dBa8699c8C681D8db03F0c1A8CEB9D7c3 (Kava mainnet)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The TSS native bridge returns signatures in Base64 format, but the
broadcast function expected hex format. Added Base64 decoding in
broadcastTransaction() to properly parse r, s, v components.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extract current round number from tss-lib message type string using
regex pattern `Round(\d+)`. This enables real-time progress updates
(1/4, 2/4... for keygen, 1/9, 2/9... for signing) instead of only
showing completion status.
Changes across all three platforms:
- tss-wasm/main.go: Add extractRoundFromMessageType() and call
OnProgress with parsed round on each outgoing message
- service-party-android/tsslib/tsslib.go: Same implementation for
Android gomobile binding
- service-party-app/tss-party/main.go: Same implementation for
Electron subprocess, with isKeygen parameter to distinguish
keygen (4 rounds) vs signing (9 rounds)
Safe fallback: Returns 0 if parsing fails, which doesn't affect
protocol execution - only UI display.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The broadcast button was disabled because isLoading remained true after
signing completed. Added isLoading = false reset in startSigningProcess
after waitForSignature succeeds or fails.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
TSS native library expects pure hex string without 0x prefix.
Fix both startSigning (initiator) and executeSignAsJoiner (joiner) functions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add ensureSessionEventSubscriptionActive() call at the start of createSignSession()
to prevent race condition where session_started event arrives before subscription
is ready. Also add debug logging for _signSessionId and pendingSignInitiatorInfo
in event callback to help diagnose sign initiator event matching issues.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The resetSessionStatus() function was not clearing pendingSessionId,
causing events from new sessions to be ignored because pendingSessionId
still held the old session ID.
Added:
- Clear pendingSessionId = null in resetSessionStatus()
- Clear _currentSession.value = null in resetSessionStatus()
- Added debug logging for session state clearing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The session event gRPC stream may silently disconnect without triggering
onError or onCompleted callbacks. This causes session_started events to
be lost, preventing the sign process from starting.
Changes:
- Add ensureSessionEventSubscriptionActive() to refresh event subscription
- Call it in joinSignSessionViaGrpc for sign joiner
- Call it in createSignSession for sign initiator after auto-join
This ensures a fresh event stream connection before waiting for events.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
GG20 signing protocol has 9 rounds, not 6. This aligns WASM with
Electron (tss-party/main.go:717) and Android (tsslib/tsslib.go:477).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changes:
- Add sign initiator handling for participant_joined events in MainViewModel
- Add sign initiator handling for session_started events in MainViewModel
- Add sign initiator handling for all_joined events in MainViewModel
- Set pendingSessionId in TssRepository.createSignSession for event matching
- Refactor initiateSignSession to wait for session_started instead of starting immediately
- Add PendingSignInitiatorInfo data class to store pending sign info
- Add sessionAlreadyInProgress flag to SignSessionResult for immediate trigger case
This fixes the issue where sign initiator couldn't detect when other parties
joined the signing session, making Android flow 100% consistent with Electron.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Connect TssNativeBridge.progress Flow to UI through:
- Add progressCallback in TssRepository with startProgressCollection/stopProgressCollection
- Subscribe to native bridge progress in keygen and sign methods
- Add setProgressCallback in MainViewModel to update appropriate round state
- Progress now flows: Go Native → TssNativeBridge → TssRepository → MainViewModel → UI
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Displays remaining time during the 5-minute polling timeout:
- Shows countdown in CreateWalletScreen (SessionScreen)
- Shows countdown in JoinKeygenScreen (JoiningScreen, KeygenProgressScreen)
- Shows countdown in CoSignJoinScreen (JoiningScreen, SigningProgressScreen)
- Format: mm:ss with Timer icon in tertiary container card
- Countdown starts on all_joined event and stops on session start/cancel
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Critical fixes to prevent app crashes when screens are kept open for extended periods:
- Add repositoryScope with SupervisorJob for structured concurrency in TssRepository
- Replace detached CoroutineScope(Dispatchers.IO).launch with repositoryScope.launch:
- Session event subscription (line 206)
- Session status polling (line 291)
- Message routing (line 1508)
- Add cleanup() method to properly cancel all jobs and repositoryScope
- Update disconnect() to also cancel sessionStatusPollingJob
- Update MainViewModel.onCleared() to call repository.cleanup()
This ensures all background coroutines are properly cancelled when the ViewModel
is cleared, preventing memory accumulation over time.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements Electron's checkAndTriggerKeygen() polling fallback:
- Adds polling every 2 seconds with 5-minute timeout
- Triggers keygen/sign via synthetic session_started event on in_progress status
- Handles gRPC stream disconnection when app goes to background
- Shows timeout error in UI via existing error mechanism
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Android TransferScreen:
- Add QR code display above invite code text
- Import QRCodeWriter and related components
- Add generateInviteQRCode helper function
- Update hint text to mention scanning
Electron CoSignSession:
- Import QRCodeSVG from qrcode.react
- Add QR code above invite code text with proper styling
- Center QR code and update hint text
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Transfer Screen improvements:
- Add QR code scanning for recipient address (using zxing library)
- Support EIP-681 URI format (ethereum:0x...) and plain address
- Remove password requirement - TSS wallets don't need passwords
- Remove unused onScanQrCode callback parameter
WalletsScreen changes:
- Simplify onTransfer callback to only pass shareId
- Remove TransferDialog - now navigates directly to TransferScreen
- Remove unused state variables (showTransferDialog, transferWallet)
Bug fix:
- Remove 0x prefix from message_hash before sending to API
- Backend expects pure hex, not 0x-prefixed hex string
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Participant class is already imported via domain.model.* wildcard import,
no need for separate import from data.repository (where it doesn't exist).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- TssRepository: Use address-based wallet name since ShareRecordEntity
doesn't have wallet_name field (unlike Electron's ShareRecord)
- MainViewModel: Add missing Participant import and simplify type reference
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changes:
- Fix Android state not resetting after successful keygen/join
- Add resetSessionStatus() method in TssRepository
- Call reset on success navigation in MainActivity
- Make Android co-sign flow 100% consistent with Electron:
- Get keygen session status for participants list
- Filter out co-managed-party-* (server backup parties)
- Auto-join via gRPC after creating sign session
- Start message routing BEFORE signing (prepareForSign)
- Use gRPC response partyIndex instead of local share
- Use original keygen thresholdN instead of signingParties.size
- Pass parties list in join sign flow
- Update SignSessionInfoResponse to include parties array
- Update validateSignInviteCode to parse parties from API response
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, after keygen completed, the Session page would just update the
status to 'completed' but not navigate away. Users had to manually click
the "Return Home" button. This could result in a white screen if the button
wasn't visible or clickable.
Now the page auto-navigates to home after 2 seconds, giving users time to
see the completion status and public key before redirecting.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a party re-subscribes (e.g., Android reconnects), the old gRPC stream's
defer Unsubscribe() was accidentally removing the NEW subscription from the
subscribers map, causing the party to miss session_started events.
Fix:
- Subscribe() now returns the channel to the caller
- Unsubscribe() now takes the channel and only removes if it matches
- This prevents older streams from removing newer subscriptions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add AppSettingEntity and AppSettingDao to Database.kt for key-value storage
- Add database migration (version 1 → 2) to create app_settings table
- Modify TssRepository.registerParty() to load/create partyId from database
- PartyId is now persisted across app restarts, matching Electron's getOrCreatePartyId()
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add warning log when parties miss session event broadcast (message-router)
- Add logging for subscribeSessionEvents to detect null asyncStub
- Add sessionStatusPollingJob field for future fallback polling mechanism
This helps diagnose why Android parties are not receiving session_started events.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Problem:
- Android initiator/joiner could miss session_started events due to race condition
- Events arriving between joinSession() and _currentSession.value assignment were ignored
- This caused keygen timeout because parties never started the TSS protocol
Solution:
- Add pendingSessionId field set BEFORE joinSession() call
- Modify startSessionEventSubscription() to match events against both activeSession and pendingSessionId
- Clear pendingSessionId on session completion, failure, or cancellation
This ensures session_started events are correctly processed even if they arrive
before _currentSession is fully initialized.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add getPartyId() method to TssRepository
- Call getSessionStatus after createKeygenSession to fetch all participants
including server-party-co-managed that have already auto-joined
- This matches Electron's behavior of calling getSessionStatus on session page
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Backend changes (session-coordinator):
- Add PublishParticipantJoined method to JoinSessionMessageRouterClient interface
- Implement PublishParticipantJoined in MessageRouterClient to broadcast events
- Call PublishParticipantJoined in join_session.go after participant joins
- Add detailed logging for debugging event broadcast
Android changes (service-party-android):
- Add detailed logging in TssRepository for session event handling
- Add detailed logging in MainViewModel for participant_joined processing
- Log activeSession state, event matching, and participant updates
This enables the initiator's waiting screen to receive real-time updates
when participants join the session, matching the expected behavior.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Created PortraitCaptureActivity that extends CaptureActivity
- Registered it in AndroidManifest.xml with screenOrientation="portrait"
- Updated JoinKeygenScreen and CoSignJoinScreen to use the portrait activity
- Also simplified keygen join logic to match Electron exactly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Removed polling fallback and simplified to match Electron's design:
- If joinSession returns sessionStatus="in_progress", trigger keygen immediately
- Otherwise wait for session_started gRPC event
Added debug log to show sessionStatus value for troubleshooting.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed from single 2-second delay to 5 attempts at 500ms intervals.
This provides faster detection while covering a longer window (2.5 seconds total).
The polling loop:
- Checks every 500ms for up to 5 times
- Stops immediately if keygen is already triggered
- Stops if session context changes (user cancelled/navigated away)
This handles the case where the last joiner triggers session_started
but cannot receive the event themselves.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When multiple Android devices join a keygen session nearly simultaneously,
the last joiner may miss the session_started gRPC event because it's sent
before the device has fully set up its event subscription.
This fix adds a 2-second delayed polling check after join to detect if
the session has already started. If the session is in_progress and we
haven't started keygen yet, trigger it via polling instead of relying
solely on the session_started event.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changes:
- Change address derivation from deriveKavaAddress to deriveEvmAddress
in TssRepository.kt (3 locations)
- Add AddressUtils.isEvmAddress() and getEvmAddress() helper methods
to handle both old Cosmos and new EVM address formats
- Fix balance query for old wallets by deriving EVM address from
public key when needed (MainViewModel.fetchBalanceForShare)
- Add retry logic for optimistic lock conflicts in join_session.go
to prevent party_index collision during concurrent joins
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Major improvements to Android gRPC client:
- Add automatic reconnection with exponential backoff (1s to 30s)
- Add heartbeat mechanism with failure detection (30s interval, 3 failures trigger reconnect)
- Add stream version tracking to filter stale callbacks
- Add channel state monitoring (every 5s)
- Add per-call deadline instead of one-time deadline for stubs
- Add SharedFlow for connection events (Connected, Disconnected, Reconnecting, Reconnected, PendingMessages)
- Add callback exception handling for robustness
- Add stream recovery after reconnection via callback mechanism
TssRepository changes:
- Save message routing params for recovery after reconnect
- Expose grpcConnectionEvents SharedFlow for UI notifications
- Auto-restore event subscriptions after reconnection
Other changes:
- Add QR code to Electron Create page for mobile scanning
- Auto version increment from version.properties
- SettingsScreen shows BuildConfig version info
- CreateWalletScreen tracks hasEnteredSession state
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The server validates device_type and only accepts specific values.
Electron doesn't send device_info at all, which passes validation.
Match that behavior for consistency.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The app was crashing with FRAME_SIZE_ERROR because the gRPC client
was using plaintext mode when connecting to port 443 (TLS endpoint).
This caused the client to receive encrypted data that it couldn't parse.
Fix: Use useTransportSecurity() for port 443, usePlaintext() for other ports.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Theme changes:
- Replace green theme with dark gray & gold color scheme
- Primary color: Gold (#D4AF37)
- Background: Dark gray (#1A1A1A)
- Surface: Medium gray (#2D2D2D)
- Disable dynamic colors to enforce custom theme
- Default to dark theme for best visual impact
- Update success indicators from green to gold across screens
JoinKeygen flow fixes (100% Electron compatible):
- Add onResetState callback for proper state reset
- Cancel in confirm/joining/progress resets to input state (stays on page)
- Two-step flow: joinKeygenSessionViaGrpc + executeKeygenAsJoiner
- Wait for session_started event before executing keygen
CoSign flow fixes (100% Electron compatible):
- Add onResetState callback and QR scanner support
- Add three-button layout (Cancel, Back, Join) in select_share step
- Two-step flow: joinSignSessionViaGrpc + executeSignAsJoiner
- If session already in_progress, trigger sign immediately (Solution B)
- Wait for session_started event otherwise
Repository changes:
- Add joinKeygenSessionViaGrpc and executeKeygenAsJoiner methods
- Add joinSignSessionViaGrpc and executeSignAsJoiner methods
- Add JoinKeygenViaGrpcResult and JoinSignViaGrpcResult data classes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Matching Electron app functionality:
1. Copy address button:
- Shows "✓ 已复制" feedback after copying
- Auto-resets after 2 seconds
2. Explorer link button (new):
- Opens address in Kava block explorer
- Uses correct URL based on network type:
- Mainnet: kavascan.com
- Testnet: testnet.kavascan.com
Changes:
- WalletsScreen: Added networkType parameter
- WalletDetailDialog: Added copy feedback state and explorer button
- MainActivity: Pass networkType to WalletsScreen
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1. Copy address button:
- Changed from alert() to visual feedback (shows "✓ 已复制")
- Feedback auto-hides after 2 seconds
2. Explorer link button:
- Was hardcoded to testnet (true)
- Now uses getCurrentNetwork() to determine correct explorer URL
- Links to kavascan.com for mainnet, testnet.kavascan.com for testnet
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, the network badge (testnet/mainnet) in Layout sidebar only
loaded once on mount and didn't update when user changed network in
Settings page.
Changes:
- Layout.tsx: Read network from localStorage first (consistent with
transaction.ts), then fallback to Electron API
- Layout.tsx: Listen for 'storage' event (cross-tab) and custom
'kava-network-change' event (same-tab) to update display
- Settings.tsx: Dispatch custom event when switching networks so
Layout can update immediately
Android app doesn't have this issue - it uses StateFlow which
automatically triggers re-renders when settings change.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Both Electron and Android apps now calculate the maximum transferable
amount by subtracting estimated gas fees from the balance:
Electron (Home.tsx):
- Added calculateMaxAmount() async function that fetches gas price
- Uses 21000 gas limit for simple transfers
- Shows loading state while calculating
Android (TransferScreen.kt):
- Added calculateMaxTransferAmount() in TransactionUtils
- Uses coroutine to fetch gas price asynchronously
- Shows "..." while calculating, falls back to balance on error
Both implementations:
- Add 10% buffer to gas price for safety
- Round down to 6 decimal places
- Show error if balance insufficient for gas
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The network toggle in Settings was saving to database via electron API
but getCurrentNetwork() in transaction.ts reads from localStorage.
This caused the balance display to use wrong RPC endpoint after switching.
Now syncs to localStorage when switching networks to ensure consistency.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously Home.tsx hardcoded testnet RPC for balance queries.
Now uses getCurrentRpcUrl() to respect user's network setting.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Key changes:
- Add `go get -d golang.org/x/mobile/cmd/gomobile` step (official recommended)
- This adds golang.org/x/mobile dependency to go.mod, fixing "unable to import bind" error
- Remove complex Go 1.22 version detection logic (no longer needed)
- Simplify gomobile installation flow
- Update tsslib/go.mod with proper golang.org/x/mobile dependency
The fix follows the official Go Mobile documentation:
https://go.dev/wiki/Mobile🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This ensures compatibility with modern NDK versions that don't
support older Android API levels. API 21 (Android 5.0) is the
minimum supported by current NDK versions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The tsslib source code is located in service-party-android/tsslib/,
not in libs/tsslib/. Updated the path and output location accordingly.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changes:
- Get GOPATH using 'go env GOPATH' command
- Add GOPATH/bin to PATH if not already present
- Check for gomobile.exe directly in GOBIN directory
- Use full path to gomobile.exe for init and bind commands
- Add verification that gomobile was installed correctly
This fixes the issue where gomobile is installed but not found
because GOPATH/bin is not in the system PATH.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When tsslib.aar is not found, the build script now automatically:
1. Checks if Go is installed
2. Installs gomobile if not present (go install golang.org/x/mobile/cmd/gomobile@latest)
3. Initializes gomobile if needed
4. Runs go mod tidy in the tsslib directory
5. Builds tsslib.aar using gomobile bind
This allows building APKs on any machine with Go installed, without
needing to manually compile the TSS library first.
Requirements:
- Go installed and in PATH
- Android NDK (installed via Android SDK)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When ANDROID_HOME environment variable contains quotes (e.g., set with
quotes in system settings), the generated local.properties file would
have an invalid path like 'sdk.dir=C:/Android"'.
This fix strips any surrounding quotes from ANDROID_HOME before using
it to create local.properties, ensuring valid SDK path format.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When local.properties is missing, the build script now automatically:
- Checks ANDROID_HOME environment variable first
- Scans common Windows SDK locations:
- %LOCALAPPDATA%\Android\Sdk
- %USERPROFILE%\AppData\Local\Android\Sdk
- C:\Android\Sdk
- C:\Android
- Creates local.properties with the detected SDK path
- Displays helpful error message if SDK is not found
This allows the build script to work on machines without manual
configuration, making it easier to build APKs on different systems.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Windows batch script for building Android APKs:
- build-apk.bat debug - Build debug APK only
- build-apk.bat release - Build release APK only
- build-apk.bat - Build both debug and release APKs
- build-apk.bat clean - Clean build files
- build-apk.bat help - Show usage help
Output locations:
- Debug: app/build/outputs/apk/debug/app-debug.apk
- Release: app/build/outputs/apk/release/app-release.apk
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Major changes:
- Add complete Android app (service-party-android) with Jetpack Compose UI
- Implement real account-service API calls for keygen and sign sessions:
- POST /api/v1/co-managed/sessions (create keygen session)
- GET /api/v1/co-managed/sessions/by-invite-code/{code} (validate invite)
- POST /api/v1/co-managed/sessions/{id}/join (join keygen session)
- POST /api/v1/co-managed/sign (create sign session)
- GET /api/v1/co-managed/sign/by-invite-code/{code} (validate sign invite)
- POST /api/v1/co-managed/sign/{id}/join (join sign session)
- Add QR code generation and scanning for session invites
- Remove password requirement (use empty string)
- Add floating action button for wallet creation
- Add network type aware explorer links (mainnet/testnet)
Network configuration:
- Change default network to Kava mainnet for both Electron and Android apps
- Electron: main.ts, transaction.ts, Settings.tsx, Layout.tsx
- Android: Models.kt (NetworkType.MAINNET default)
Features:
- Full TSS keygen and sign protocol via gomobile bindings
- gRPC message routing for multi-party communication
- Cross-platform compatibility with service-party-app (Electron)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Additional safeguards to prevent "CANCELLED: Cancelled on client" error:
1. Add `this.connected` check at the start of subscribeMessages()
2. Set messageStream to null after canceling old stream
3. Wrap new stream creation in try-catch to handle creation errors
4. Add logging for ignored cancel errors
These changes ensure that:
- subscribeMessages won't proceed if connection is lost
- Old stream is fully cleaned up before creating new one
- Errors during stream creation are properly caught and logged
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Root cause: After keygen/sign completion, the gRPC message stream was not
unsubscribed. On the second operation, prepareForSign/prepareForKeygen
would try to cancel the stale stream, causing "CANCELLED: Cancelled on client".
Changes in tss-handler.ts:
- Add grpcClient.unsubscribeMessages() in all cleanup paths:
- participateKeygen close handler
- participateKeygen error handler
- participateSign close handler
- participateSign error handler
- cancel() method
- Reset sessionId and partyId in all cleanup paths
Changes in main.ts:
- Add reconnection logic in app 'activate' event for macOS
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The app was crashing with "CANCELLED: Cancelled on client" error when
opening the app a second time. This happened because:
1. When window was reopened, old gRPC streams were in cancelled state
2. prepareForSign/prepareForKeygen tried to subscribe on cancelled streams
3. The error was unhandled and crashed the app
Changes:
- Add isConnected() check in prepareForSign() and prepareForKeygen()
- Throw meaningful error when gRPC client is not connected
- Wrap all prepareFor* calls in try-catch in main.ts
- Return user-friendly error message instead of crashing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Changed getGasPrice() to use eth_gasPrice RPC method instead of calculating
from baseFeePerGas (which is for EIP-1559 transactions)
- Added 10% buffer to gas price to ensure transaction gets included
- Updated Home.tsx to use gasPrice instead of maxFeePerGas for display
KAVA doesn't support EIP-1559, so we must use Legacy (Type 0) transactions
with gasPrice from eth_gasPrice RPC.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
KAVA EVM does not support EIP-1559 dynamic fee transactions.
Changed from EIP-1559 (Type 2) to Legacy (Type 0) format:
- prepareTransaction: Use [nonce, gasPrice, gasLimit, to, value, data, chainId, 0, 0]
- finalizeTransaction: Use EIP-155 v calculation (chainId * 2 + 35 + recoveryId)
- Remove type prefix (0x02) as Legacy transactions don't need it
- Update Home.tsx and CoSignSession.tsx to use gasPrice instead of maxFeePerGas
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The signature was 64 bytes (r + s) but EVM transactions need 65 bytes (r + s + v).
Now the recovery ID is appended to the signature so the frontend can correctly
parse and broadcast the transaction.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
TSS-lib convention: threshold=t means (t+1) signers required.
User expectation: "2-of-3" means 2 signers needed.
Before this fix:
- Keygen used thresholdT directly (e.g., 2)
- TSS-lib interpreted as needing 3 signers (2+1)
- 2-of-3 wallet was actually 3-of-3!
After this fix:
- Both keygen and signing use (thresholdT-1)
- For 2-of-3: tss-lib threshold=1, needs 1+1=2 signers ✓
Files changed:
- tss-party/main.go: keygen and signing both use thresholdT-1
- tss-wasm/main.go: keygen and signing both use thresholdT-1
- pkg/tss/keygen.go: uses config.Threshold-1
- pkg/tss/signing.go: uses config.Threshold-1
BREAKING CHANGE: Existing wallets created before this fix used wrong
threshold and need to be regenerated. New wallets will work correctly.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The signing code was using thresholdT-1 while keygen was using thresholdT,
causing Lagrange coefficient mismatch and "U doesn't equal T" error in round 9.
Root cause: commit d0c504dc added -1 to signing threshold to "match user expectation",
but this broke the keygen/sign consistency that TSS-lib requires.
Changes:
- tss-party/main.go: Sign now uses thresholdT (same as keygen)
- pkg/tss/signing.go: Add logging, emphasize threshold must match keygen
- tss-wasm/main.go: Add comment about threshold consistency
NOTE: This fix maintains backward compatibility with existing wallets.
No wallet regeneration is needed.
ROLLBACK: If this causes issues, revert to commit before this one.
Previous signing threshold was thresholdT-1 (commit d0c504dc).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When signing with fewer parties than keygen (e.g., 2-of-3 signing with only 2 parties),
the TSS-lib requires filtered save data containing only the participating parties.
Without this fix, signing fails with "U doesn't equal T" error because:
- Keygen creates save data for all N parties (e.g., 3 parties with indices 0, 1, 2)
- Sign uses only T parties (e.g., 2 parties with indices 1, 2)
- TSS-lib internal index validation fails due to mismatch
Changes:
- pkg/tss/signing.go: Use len(sortedPartyIDs) for partyCount and call BuildLocalSaveDataSubset
- tss-party/main.go: Add BuildLocalSaveDataSubset call for Electron app
- tss-wasm/main.go: Add BuildLocalSaveDataSubset call for WASM builds
This fix is backward compatible - when all parties participate, the subset equals the original data.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
User says "3-of-5" meaning 3 signers needed.
tss-lib threshold t means t+1 signers required.
Now we store t-1 at session creation (like persistent-only does).
Changes:
- co_managed_handler.go: tssThresholdT = req.ThresholdT - 1
- tss-party/main.go: remove -1 from sign (now consistent with keygen)
BREAKING: Existing co-managed wallets must be regenerated.
ROLLBACK: Revert this commit if signing still fails.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The tss.NewParameters() expects the party count to match the number of
parties in peerCtx. For signing, this should be len(sortedPartyIDs)
(actual signing participants), not thresholdN (original keygen parties).
This fixes the "U doesn't equal T" error in round 9 when doing 3-of-5
co-managed signing with parties at indices 2,3,4.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When switching message/event streams, the old stream's 'end' or 'error'
events could fire after the new stream was created. Since activeMessageSubscription
was already updated to the new session, the old stream's events would
incorrectly trigger reconnection, causing TSS message routing to fail.
Fix:
- Remove event listeners from old stream before canceling
- Use closure to capture current stream reference
- Check if event is from current active stream before triggering reconnect
This fixes the "Not connected" error during co-sign TSS message routing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Keygen/co-keygen: must have exactly N participants joined
- Sign (co-sign/persistent): only check all registered participants joined
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
User says 3-of-5 meaning 3 signers needed, but tss-lib threshold t means t+1 signers.
Pass thresholdT-1 so tss-lib needs (t-1)+1 = t signers, matching user expectation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Reverts e81757ad - the threshold conversion was wrong.
Keygen works with original thresholdT/thresholdN parameters.
The signing issue needs a different fix.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Rename thresholdT/thresholdN to requiredSigners/totalParties in Create.tsx
- Add parameter conversion in main.ts: threshold_t = requiredSigners - 1
- In tss-lib, threshold t means t+1 parties needed to sign
- For 3-of-5: requiredSigners=3 → threshold_t=2 (t+1=3 signers)
- externalCount = requiredSigners (user parties)
- persistentCount = totalParties - requiredSigners (server parties)
- Backward compatible with legacy thresholdT/thresholdN format
BREAKING: Existing co-managed wallets need re-keygen with new params
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The TSS signing was failing with "U doesn't equal T" error because
tss-party was passing incorrect parameters to tss.NewParameters():
- Was: len(sortedPartyIDs)=3 (signing participants), thresholdT-1=2
- Now: thresholdN=5 (keygen N), thresholdT=3 (keygen T)
This matches how pkg/tss/signing.go creates parameters in server-party,
which uses TotalParties=N and Threshold=T from the original keygen.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add keygenThresholdN to the CreateSignSession response so frontend
can access the original N value from keygen session. This is required
for proper TSS operation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add detailed comments to warn about changes that affect persistent sign flow:
- session_coordinator.go: ValidateSessionCreation now allows T <= count <= N for sign
- mpc_session.go: CanStart/AllPartiesReady now check registered participants, not N
- session_coordinator_client.go: ThresholdN now uses keygenThresholdN instead of len(parties)
Each comment includes:
- Original code behavior
- New code behavior
- How to revert if persistent sign breaks
- Related files list
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change ValidateSessionCreation to accept T <= participantCount <= N for sign sessions
- Co-managed sign uses exactly T parties
- Persistent sign uses T+1 parties
- Both now pass validation with correct keygenThresholdN
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- CanStart(): Check if all registered participants have joined, not based on T/N
- AddParticipant(): Keep N as max limit (API handles T vs T+1 validation)
- AllPartiesReady(): Check all registered participants, not based on T/N
- This approach works for both co-managed (T parties) and persistent (T+1 parties) signing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- For keygen sessions: require all N parties to join before starting
- For sign sessions: require only T parties to join before starting
- This fixes session_started event not being triggered for signing sessions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Modify ValidateSessionCreation to differentiate between keygen and sign sessions
- For keygen: require participantCount == threshold.N() (all parties must participate)
- For sign: require participantCount == threshold.T() (only t parties needed)
- This fixes "session is full" error when creating signing session with 3 parties but n=5
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Query keygen session from mpc_sessions table to get correct threshold_n
- Pass keygenThresholdN to CreateSigningSessionAuto instead of len(parties)
- Return parties list and correct threshold values in GetSignSessionByInviteCode
- This fixes TSS signing failure "U doesn't equal T" caused by mismatched n values
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Problem: Participants joining early only got incomplete participant list
from other_parties (only those who had joined), causing partyIndex mismatch.
Solution:
- Add parties field to SessionInfo (from validateInviteCode response)
- Pass parties to joinSession call from frontend
- Backend joinSession uses params.parties (complete list) instead of
result.other_parties (incomplete list)
- Add debug logging to track participant list state
Now all participants have the complete parties list with correct partyIndex.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add logic in handleCoSignStart to update participants from event.selectedParties
- Fix initiator immediate trigger to use other_parties + self instead of incomplete participants list
- Add debug logging for participant list updates
- Ensures all parties have correct participant list before TSS signing starts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change /sign to /cosign/join so participants use the correct page
with auto-join functionality.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add console.log statements to trace the auto-join logic:
- Log loaded shares with sessionId
- Log auto-select share matching check
- Log auto-join conditions and share match status
- Log validateInviteCode results including joinToken
- Log handleJoinSession parameters
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When multiple sign sessions share the same invite code (due to retries),
the query now:
1. Excludes failed sessions (status != 'failed')
2. Orders by created_at DESC to get the most recent session
3. Limits to 1 result
This prevents participants from seeing an old failed session's status
when they look up the invite code.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The validateSigningSession handler was using parties.length for threshold.n
which returned 0 when parties array was empty. Now correctly uses the
threshold_n value returned from the backend API.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Password is optional - remove the validation that required password
to be non-empty before joining a sign session.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Password field was required to enable the join button, but password
is optional when the share was created without encryption.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add threshold_n to GetSignSessionByInviteCodeResponse interface
- Fix main.ts to use result.threshold_n instead of result.parties?.length
- Add message_hash, joined_count, join_token to GetSignSessionByInviteCode response
- Generate join token for sign session lookup
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add invite_code retrieval in GetSignSessionStatus (backend)
- Add inviteCode to cosign:getSessionStatus response (frontend IPC)
- Add inviteCode to SessionState and display UI in CoSignSession
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fetch keygen session status from backend to get accurate party_index
- Filter out co-managed-party-* (server persistent parties) from signing
- Only temporary/external user parties participate in signing
- For 3-of-5 wallet: 3 user parties sign, 2 co-managed parties are backup only
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use API's participants field instead of parties
- Use API's threshold_t and threshold_n instead of activeCoSignSession
- Show participant status from API response
- Update GetSignSessionStatusResponse interface
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add join_tokens (map[partyID]token) to CreateSignSession response
- Keep join_token for backward compatibility
- Update frontend to use join_tokens[partyId] for initiator auto-join
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
BigInt cannot be serialized by JSON.stringify. Convert gasLimit,
maxFeePerGas, maxPriorityFeePerGas, and value to strings before
storing in sessionStorage.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add complete co-sign functionality for multi-party transaction signing:
Frontend (React):
- CoSignCreate.tsx: Create signing session with share selection
- CoSignJoin.tsx: Join signing session via invite code
- CoSignSession.tsx: Monitor signing progress and results
- Add routes in App.tsx for new pages
Backend (Electron):
- main.ts: Add IPC handlers for co-sign operations
- tss-handler.ts: Add participateSign() for TSS signing
- preload.ts: Expose cosign API to renderer
- account-client.ts: Add sign session API types
TSS Party (Go):
- main.go: Implement 'sign' command for GG20 signing protocol
- integration_test.go: Add comprehensive tests for signing flow
Infrastructure:
- docker-compose.windows.yml: Expose gRPC port 50051
This is a pure additive change that does not affect existing
persistent role keygen/sign functionality.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add KAVA_TESTNET_TX_CONFIG in kava-tx-service.ts
- Add switchNetwork/getNetwork IPC handlers in main.ts
- Add network toggle UI in Settings page
- Show current network (测试网/主网) badge in Layout status bar
- Default to testnet for development
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
listShares returned `participants` but Home.tsx expected `metadata.participants`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Default 64KB buffer was truncating large TSS protocol messages in round 3+
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
session_created event only contains initial co-managed parties,
but session_started event contains ALL participants including
external parties that joined dynamically via invite code.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add new ExecuteWithSessionInfo method to ParticipateKeygenUseCase
for server-party-co-managed to skip duplicate JoinSession call.
- server-party-co-managed already calls JoinSession in session_created phase
- ExecuteWithSessionInfo accepts pre-obtained SessionInfo and skips internal JoinSession
- Refactor common execution logic to private executeWithSessionInfo method
- Update server-party-co-managed to use ExecuteWithSessionInfo on session_started
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create new server-party-co-managed service with two-phase event handling
- Phase 1 (session_created): Store join token and wait
- Phase 2 (session_started): Execute TSS protocol (same timing as service-party-app)
- Add PartyRoleCoManagedPersistent role to isolate from normal keygen/sign
- Update docker-compose.yml with 3 co-managed party instances
- Update deploy.sh service lists
- Modify selectPartiesByCompositionForCoManaged to use new role
This ensures co_managed_keygen sessions use dedicated parties that behave
100% compatible with service-party-app, without affecting existing keygen/sign flows.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Problem:
- co_managed_keygen server-party waits for external party after joining
- No heartbeat sent during wait period (up to 5 minutes)
- session-coordinator has 120 second inactivity timeout
- Server-party marked as timed_out/failed while waiting
Fix:
- Send heartbeat in waitForAllParticipants polling loop
- Add Heartbeat method to MessageRouterClient interface
- Heartbeat every 2 seconds with poll interval
- Heartbeat failure only logs warning, does not block
Generated with Claude Code
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- expires_at 存储为 UTC 时间
- 查询时使用 NOW() AT TIME ZONE 'UTC' 确保时区一致
- 避免因时区差异导致 session 过早被标记为过期
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
api.szaiai.com 被 OSS/CDN 拦截,改用 rwaapi.szaiai.com 直接访问 Kong 网关
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
添加共管钱包 API 路由,将 /api/v1/co-managed/* 请求转发到 account-service (端口 4000)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
添加 50051:50051 端口映射,使开发模式与生产模式保持一致
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
将 proto 文件加载改为延迟加载模式,在 connect() 时才加载,
避免模块加载时 app.isPackaged 还未准备好导致的路径错误。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
bech32 v2.0.0 自带TypeScript类型定义,不需要单独的
@types/bech32 包(该包是针对v1.x版本的)。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
将testConnection从URL解析改为直接使用host:port格式,
与grpc-client.ts的connect方法保持一致。
地址格式: mpc-grpc.szaiai.com:443 (自动检测TLS)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
添加 ProtoPackage 接口定义 proto 包结构类型,避免类型推断错误
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 新增 tsconfig.electron.json 单独编译 Electron 主进程到 dist-electron/
- 更新 package.json main 入口为 dist-electron/main.js
- 更新 build 脚本先编译 electron 再 vite build
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Rewrite build-windows.bat in English to avoid encoding issues
- Remove icon configuration from electron-builder.json (use default)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
将 _loadUnreadNotificationCount() 调用包装在 addPostFrameCallback 中,
延迟到 widget tree 构建完成后执行,避免 Riverpod 报错:
"Tried to modify a provider while the widget tree was building"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
将 008_add_co_managed_wallet_fields.up.sql 改为幂等脚本:
- 使用 DO $$ ... IF NOT EXISTS 检查列是否存在再添加
- 使用 CREATE INDEX IF NOT EXISTS 创建索引
- 使用 DROP CONSTRAINT IF EXISTS 删除约束
这确保迁移脚本可以安全地多次执行,不会因列/索引已存在而失败。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 在创建新token前先撤销该设备的旧token
- 使用upsert替代create避免并发时refresh_token_hash唯一约束冲突
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
将动态 import('@/domain/value-objects') 改为静态 import
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
之前手动重试时如果状态是 generating/pending/deriving 会直接跳过,
导致卡住的钱包无法重新生成。现在增加超时检查(60秒),超时后允许强制重试。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
_checkContractsAndKyc() 方法之前没有调用 _shouldSkipContractCheck(),
导致用户在合同/KYC页面时首次检查仍会弹窗。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
改用 ref.read(appRouterProvider) 替代 GoRouter.of(context),
确保能正确获取到当前的全局路由路径。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
二要素 API (Id2MetaStandardVerify) 返回 440 无权限调用错误
暂时恢复使用三要素验证,保留二要素代码待开通权限后使用
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1. 合同模板:身份证号和联系方式显示完整信息,不再使用星号掩码
2. 签署页面:checkbox 默认不选中,用户阅读到底部后才可点击确认
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
方便排查 WALLET_SERVICE_URL 环境变量是否正确加载
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
添加 /api/v1 前缀以匹配 identity-service 的全局路由配置
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
迁移脚本添加 IF NOT EXISTS 检查,避免重复执行时失败
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 修复 markScrollComplete/acknowledgeContract API 响应处理
(后端返回 success:true 但无 data 时重新获取任务详情)
- 将合同签署页面的 USDT 改成绿积分
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Kafka事件重复消费时,多个消费者同时创建签约任务会导致唯一约束冲突
改用upsert确保幂等性,如果orderNo已存在则返回现有记录
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
打印完整的response和ResultObject字段以便调试
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
修复 ValidationPipe whitelist 模式下属性被过滤的问题
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
后端返回的数据结构是嵌套的 data.data,修复前端解析逻辑以正确读取 phoneVerified 等字段。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
在跳转到实名认证页面前调用 ref.invalidate(kycStatusProvider)
确保手机号验证状态能正确更新
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
使用 context.go() 替代 context.pop(),直接跳转到实名认证页面
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
验证码页面不再隐藏手机号中间数字,改为完整显示
格式: 138 1234 5678
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
JwtAuthGuard 设置 req.user.id,controller 需要使用相同字段名
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 精确计算终点位置:火柴人列右边缘对齐红旗左边缘
- 起点从昵称标签右边4px间距开始
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
memo 中已包含权益类型(如"分享权益:来自用户xxx的认种"),
卡片标题也显示了权益类型,所以只显示"来自用户xxx的认种"部分
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 将昵称移到左侧固定位置,与右边红旗相呼应
- 保持数量标签在火柴人上方,间距2像素
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 将昵称移到左侧固定位置,与右边红旗相呼应
- 缩小数量标签与动画之间的间距
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
将用户名格式从"榴莲皇后x号"改为"榴莲皇后xxx",
其中xxx是2-4字的创意组合,包含前缀、核心词和后缀。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
在"我的"页面可结算板块中,每笔收益现在会显示来源信息(通过 memo 字段)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
为 priority 和 targetType 添加正确的类型断言
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
由于系统尚未实现权限管理功能,暂时将 checkPrivateProfileAccess
始终返回 false,禁止所有用户查看其他用户的手机号、邮箱等隐私信息。
后续实现权限系统后可恢复原有逻辑。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 在流水明细查询中排除冻结/解冻等临时记录
- 将"充值 (KAVA)"统一改为"充值"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
当认种用户没有授权时,不再提前返回,确保 checkAllTeamAutoUpgrade()
始终被调用,以正确检查所有市/省团队的自动升级条件。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 移除单一的共享终点旗帜
- 为每个跑道生成独立的红旗,与火柴人垂直位置对齐
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 移除火柴人容器的水平margin,与页面其他内容保持一致
- 重新计算火柴人位置,正确处理容器边距
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 处理 TransformInterceptor 包装的响应格式 { success, data }
- 正确提取 data 字段中的用户信息
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
当查询火柴人排名时,如果没有评估记录,则实时调用 assessAndRankRegion
创建评估记录,避免用户需要等待凌晨1点的定时任务。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- REWARD_SETTLED 标签从"提取"改为"结算"
- 调整筛选选项顺序:转入/转出放到全部后面,充值绿积分放到最后
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
添加空字符串默认值,确保 locationCode 参数类型为 String
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
用户需要先通过自助申请获得社区授权,才会在'我的'页面显示社区权益考核
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove ^ to prevent npm from installing vulnerable 15.5.x versions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changes:
- Add generic image upload API endpoint (POST /user/upload-image)
- Add uploadImage method in StorageService for backend
- Add uploadImage method in AccountService for frontend
- Add selfApplyStatus and selfApplyAuthorization methods in AuthorizationService
- Replace mock data with real API calls in authorization apply page
- Add API endpoints for self-apply status and self-apply authorization
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change misleading "unexpected" log to correctly indicate idempotent behavior
- Add debug log for completed records being skipped in retry task
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
SetPasswordPage 需要这两个参数才能使用新的 register-by-phone 流程
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
修复构建错误:Property 'registerByPhone' does not exist on type 'UserApplicationService'
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- SYSTEM状态会被识别为冻结账户
- 必须是ACTIVE才能作为有效推荐人
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 添加ts-node依赖用于执行seed.ts
- 在start.sh中添加prisma db seed命令
- 与identity-service保持一致
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- referral-service返回 {valid:bool} 格式
- 移除对 data 字段的依赖
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 从 /referrals/validate?code=X 改为 /referral/validate/X
- 使用 referral-service 的 API (已在 Kong 配置)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
修改 phoneNumber 字段类型从 string 改为 string | null,
以支持钱包重试场景中手机号可能为空的情况。
这个修复解决了 Docker 构建时的 TypeScript 编译错误:
- Type 'string | null' is not assignable to type 'string'
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- 错误状态显示详细错误信息而非通用提示
- 空数据状态明确说明"暂无用户数据,用户注册后会自动同步到此列表"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
将错误的方法名 _loadWalletData 改为正确的 _loadData
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Kong 网关:
- 添加 /api/v1/dashboard 路由到 reporting-service
Admin-Web 前端:
- 修复所有 API endpoints 添加 /v1 前缀
- 确保与 Kong 路由配置一致
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- health 检查列表添加 blockchain-service
- migrate 服务列表添加 blockchain-service
- 帮助文档更新服务列表
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
后端:
- blockchain-service: 新增 revokeMnemonic() 方法和 POST /internal/mnemonic/revoke API
- identity-service: 新增 POST /user/mnemonic/revoke 用户端API
- 挂失后助记词状态变为 REVOKED,无法用于账户恢复
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
扫描区块时检测缓存是否为空,如果为空则自动从数据库重新加载地址缓存,
避免因 Redis 数据丢失导致充值漏检。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
按 Flutter 建议升级 Kotlin 版本以避免兼容性问题
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
sentry_flutter 插件不兼容 Kotlin 2.2.20,降级到稳定版本
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
HOT_WALLET_USERNAME=rwadurian-system-hot-wallet-01
HOT_WALLET_ADDRESS=0x895aaf83C57f807416E3BbBd093d7aB74a6FDd33
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
使用 LayoutBuilder 获取实际容器宽度而不是屏幕宽度
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
"Bash(git commit -m \"$\\(cat <<''EOF''\nchore\\(admin-service\\): 添加系统维护和共管钱包的数据库迁移\n\n添加缺失的 migration 文件,包含:\n- system_maintenances 表 \\(系统维护公告\\)\n- WalletSessionStatus 枚举\n- co_managed_wallet_sessions 表 \\(共管钱包会话\\)\n- co_managed_wallets 表 \\(共管钱包记录\\)\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfix\\(admin-service\\): 修复共管钱包 status 类型不匹配问题\n\n使用 Prisma 生成的类型替代手动定义的接口:\n- PrismaCoManagedWalletSession -> @prisma/client\n- PrismaCoManagedWallet -> @prisma/client\n- status 字段使用 PrismaWalletSessionStatus 枚举类型\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\ndocs: 添加 Service Party App 技术文档\n\n添加分布式共管钱包桌面应用的详细技术文档,包括:\n\n- 应用概述和使用场景\n- 目录结构说明\n- 技术架构和技术栈\n- TSS 子进程架构设计\n- IPC 消息格式定义\n- 核心功能说明\n- 编译与运行指南\n- 安全考虑\n- 系统集成说明\n- 未来扩展规划\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfix\\(admin-web\\): 修复系统维护\"立即激活\"按钮不显示的问题\n\n- 修复 getStatusTag 函数逻辑,未激活状态使用 ''inactive'' 样式而不是 ''expired''\n- 添加更细化的状态判断:维护中、已过期、已计划、未激活、待激活\n- 添加 inactive 标签样式(橙色背景)\n- 现在未激活的维护计划会正确显示\"立即激活\"按钮\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfix\\(migration\\): 使数据库迁移脚本幂等化,支持重复执行\n\n将 008_add_co_managed_wallet_fields.up.sql 改为幂等脚本:\n- 使用 DO $$... IF NOT EXISTS 检查列是否存在再添加\n- 使用 CREATE INDEX IF NOT EXISTS 创建索引\n- 使用 DROP CONSTRAINT IF EXISTS 删除约束\n\n这确保迁移脚本可以安全地多次执行,不会因列/索引已存在而失败。\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(service-party-app\\): 添加 Windows 一键编译脚本\n\n添加 build-windows.bat 脚本,支持:\n- 检查 Node.js 和 Go 环境\n- 编译 TSS 子进程 \\(tss-party.exe\\)\n- 安装 npm 依赖\n- 编译 Electron 应用\n\n使用方法: 双击运行 build-windows.bat\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(./node_modules/.bin/tsc:*)",
"Bash(npm ls:*)",
"Bash(npm run build:win:*)",
"Bash(npm run clean:*)",
"Bash(git cherry-pick:*)",
"Bash(git stash:*)",
"Bash(docker compose build:*)",
"Bash(git log:*)",
"Bash(git tag -a v0.3.0-pre-transfer -m \"$\\(cat <<''EOF''\nPre-transfer development checkpoint\n\nCompleted features:\n- Co-keygen: Multi-party key generation with TSS \\(GG20\\)\n- Service-party-app: Electron desktop application\n - Create shared wallet \\(keygen initiator\\)\n - Join wallet creation \\(keygen participant\\)\n - Wallet management \\(list, export, delete\\)\n - Kava network switch \\(mainnet/testnet\\)\n - EVM address derivation and balance display\n\nNot yet implemented:\n- Co-sign: Multi-party transaction signing\n- Transfer functionality\n\nThis tag marks the stable state before transfer feature development.\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(service-party-app\\): implement co-sign multi-party signing\n\nAdd complete co-sign functionality for multi-party transaction signing:\n\nFrontend \\(React\\):\n- CoSignCreate.tsx: Create signing session with share selection\n- CoSignJoin.tsx: Join signing session via invite code\n- CoSignSession.tsx: Monitor signing progress and results\n- Add routes in App.tsx for new pages\n\nBackend \\(Electron\\):\n- main.ts: Add IPC handlers for co-sign operations\n- tss-handler.ts: Add participateSign\\(\\) for TSS signing\n- preload.ts: Expose cosign API to renderer\n- account-client.ts: Add sign session API types\n\nTSS Party \\(Go\\):\n- main.go: Implement ''sign'' command for GG20 signing protocol\n- integration_test.go: Add comprehensive tests for signing flow\n\nInfrastructure:\n- docker-compose.windows.yml: Expose gRPC port 50051\n\nThis is a pure additive change that does not affect existing\npersistent role keygen/sign functionality.\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(service-party-app\\): add transfer functionality with co-sign integration\n\nAdd complete KAVA transfer feature to the wallet home page:\n\nFrontend \\(React\\):\n- Home.tsx: Add transfer modal with address/amount input, transaction\n confirmation, and co-sign session initiation\n- Home.module.css: Transfer modal styles \\(form, confirm, error states\\)\n- CoSignSession.tsx: Add transaction broadcast after signing completion,\n with block explorer link\n\nUtils:\n- transaction.ts: EIP-1559 transaction building, RLP encoding, Keccak-256\n hashing, nonce/gas fetching, transaction broadcast via JSON-RPC\n\nFlow: Wallet -> Transfer Modal -> Prepare TX -> Confirm -> Co-Sign ->\n Sign Session -> Broadcast -> Block Explorer\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(co-sign\\): add debug logs for auto-join flow in CoSignJoin\n\nAdd console.log statements to trace the auto-join logic:\n- Log loaded shares with sessionId\n- Log auto-select share matching check\n- Log auto-join conditions and share match status\n- Log validateInviteCode results including joinToken\n- Log handleJoinSession parameters\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfix\\(co-sign\\): use keygen session threshold_n for TSS signing\n\n- Query keygen session from mpc_sessions table to get correct threshold_n\n- Pass keygenThresholdN to CreateSigningSessionAuto instead of len\\(parties\\)\n- Return parties list and correct threshold values in GetSignSessionByInviteCode\n- This fixes TSS signing failure \"U doesn 't equal T\" caused by mismatched n values\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfix\\(tss\\): use BuildLocalSaveDataSubset for threshold signing with party subsets\n\nWhen signing with fewer parties than keygen \\(e.g., 2-of-3 signing with only 2 parties\\),\nthe TSS-lib requires filtered save data containing only the participating parties.\n\nWithout this fix, signing fails with \"U doesn 't equal T\" error because:\n- Keygen creates save data for all N parties \\(e.g., 3 parties with indices 0, 1, 2\\)\n- Sign uses only T parties \\(e.g., 2 parties with indices 1, 2\\)\n- TSS-lib internal index validation fails due to mismatch\n\nChanges:\n- pkg/tss/signing.go: Use len\\(sortedPartyIDs\\) for partyCount and call BuildLocalSaveDataSubset\n- tss-party/main.go: Add BuildLocalSaveDataSubset call for Electron app\n- tss-wasm/main.go: Add BuildLocalSaveDataSubset call for WASM builds\n\nThis fix is backward compatible - when all parties participate, the subset equals the original data.\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(android\\): add Android TSS Party app with full API implementation\n\nMajor changes:\n- Add complete Android app \\(service-party-android\\) with Jetpack Compose UI\n- Implement real account-service API calls for keygen and sign sessions:\n - POST /api/v1/co-managed/sessions \\(create keygen session\\)\n - GET /api/v1/co-managed/sessions/by-invite-code/{code} \\(validate invite\\)\n - POST /api/v1/co-managed/sessions/{id}/join \\(join keygen session\\)\n - POST /api/v1/co-managed/sign \\(create sign session\\)\n - GET /api/v1/co-managed/sign/by-invite-code/{code} \\(validate sign invite\\)\n - POST /api/v1/co-managed/sign/{id}/join \\(join sign session\\)\n- Add QR code generation and scanning for session invites\n- Remove password requirement \\(use empty string\\)\n- Add floating action button for wallet creation\n- Add network type aware explorer links \\(mainnet/testnet\\)\n\nNetwork configuration:\n- Change default network to Kava mainnet for both Electron and Android apps\n- Electron: main.ts, transaction.ts, Settings.tsx, Layout.tsx\n- Android: Models.kt \\(NetworkType.MAINNET default\\)\n\nFeatures:\n- Full TSS keygen and sign protocol via gomobile bindings\n- gRPC message routing for multi-party communication\n- Cross-platform compatibility with service-party-app \\(Electron\\)\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(cmd /c \"build-apk.bat help\")",
"Bash(go clean:*)",
"Bash(gomobile bind:*)",
"Bash(GOPROXY=https://proxy.golang.org,direct go get:*)",
"Bash(go mod download:*)",
"Bash(go env:*)",
"Bash(cmd /c \"set GOFLAGS=-mod=mod && go get golang.org/x/mobile/bind && go mod tidy && gomobile bind -v -target=android -androidapi 21 -o ..\\\\app\\\\libs\\\\tsslib.aar .\")",
"Bash(\"/c/Users/dong/go/bin/go1.22.10.exe\" mod tidy)",
"Bash(adb devices:*)",
"Bash(adb logcat:*)",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(android\\): add 5-minute polling timeout mechanism for keygen/sign\n\nImplements Electron''s checkAndTriggerKeygen\\(\\) polling fallback:\n- Adds polling every 2 seconds with 5-minute timeout\n- Triggers keygen/sign via synthetic session_started event on in_progress status\n- Handles gRPC stream disconnection when app goes to background\n- Shows timeout error in UI via existing error mechanism\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(go list:*)",
"Bash(adb install:*)",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(tss\\): add real-time round progress from msg.Type\\(\\) parsing\n\nExtract current round number from tss-lib message type string using\nregex pattern `Round\\(\\\\d+\\)`. This enables real-time progress updates\n\\(1/4, 2/4... for keygen, 1/9, 2/9... for signing\\) instead of only\nshowing completion status.\n\nChanges across all three platforms:\n- tss-wasm/main.go: Add extractRoundFromMessageType\\(\\) and call\n OnProgress with parsed round on each outgoing message\n- service-party-android/tsslib/tsslib.go: Same implementation for\n Android gomobile binding\n- service-party-app/tss-party/main.go: Same implementation for\n Electron subprocess, with isKeygen parameter to distinguish\n keygen \\(4 rounds\\) vs signing \\(9 rounds\\)\n\nSafe fallback: Returns 0 if parsing fails, which doesn''t affect\nprotocol execution - only UI display.\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(android\\): add share export and import functionality\n\nAdd ability to backup wallet shares to files and restore from backups:\n\n- Add ShareBackup data class in Models.kt for backup format\n- Add exportShareBackup\\(\\) and importShareBackup\\(\\) in TssRepository\n- Add export/import state and methods in MainViewModel\n- Add file picker integration in MainActivity using ActivityResultContracts\n- Add import FAB button in WalletsScreen\n- Export saves as .tss-backup file with address and timestamp in filename\n- Import validates backup format and checks for duplicate wallets\n\nThe backup file contains all necessary data to restore a wallet share:\nsessionId, publicKey, encryptedShare, threshold, partyIndex, address.\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(pending-actions\\): add user pending actions system\n\nAdd a fully optional pending actions system that allows admins to configure\nspecific tasks that users must complete after login.\n\nBackend \\(identity-service\\):\n- Add UserPendingAction model to Prisma schema\n- Add migration for user_pending_actions table\n- Add PendingActionService with full CRUD operations\n- Add user-facing API \\(GET list, POST complete\\)\n- Add admin API \\(CRUD, batch create\\)\n\nAdmin Web:\n- Add pending actions management page\n- Support single/batch create, edit, cancel, delete\n- View action details including completion time\n- Filter by userId, actionCode, status\n\nFlutter Mobile App:\n- Add PendingActionService and PendingActionCheckService\n- Add PendingActionsPage for forced task execution\n- Integrate into splash_page login flow\n- Users must complete all pending tasks in priority order\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(npm run type-check:*)",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(settlement\\): implement settle-to-balance with detailed source tracking\n\nAdd complete settlement-to-balance feature that transfers settleable\nearnings directly to wallet USDT balance \\(no currency swap\\). Key changes:\n\nBackend \\(wallet-service\\):\n- Add SettleToBalanceCommand for settlement operations\n- Add settleToBalance method to WalletAccountAggregate\n- Add settleToBalance application service with ledger recording\n- Add internal API endpoint POST /api/v1/wallets/settle-to-balance\n\nBackend \\(reward-service\\):\n- Add settleToBalance client method for wallet-service communication\n- Add settleRewardsToBalance application service method\n- Add user-facing API endpoint POST /rewards/settle-to-balance\n- Build detailed settlement memo with source user tracking per reward\n\nFrontend \\(mobile-app\\):\n- Add SettleToBalanceResult model class\n- Add settleToBalance\\(\\) method to RewardService\n- Update pending_actions_page to handle SETTLE_REWARDS action\n- Add completion detection via settleableUsdt balance check\n\nSettlement memo now includes detailed breakdown by right type with\nsource user accountSequence for each reward entry, e.g.:\n 结算 1000.00 绿积分到钱包余额\n 涉及 5 笔奖励\n - SHARE_RIGHT: 500.00 绿积分\n 来自 D2512120001: 288.00 绿积分\n 来自 D2512120002: 212.00 绿积分\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(withdrawal\\): implement fiat withdrawal with bank/alipay/wechat\n\nAdd complete fiat withdrawal feature that allows users to withdraw\ngreen credits \\(绿积分\\) to their bank card, Alipay, or WeChat account\nwith 1:1 CNY conversion. Key changes:\n\nBackend \\(wallet-service\\):\n- Update Prisma schema with fiat withdrawal fields \\(paymentMethod,\n bankName, bankCardNo, cardHolderName, alipay*, wechat*, review fields\\)\n- Rewrite withdrawal status enum for fiat flow: PENDING → FROZEN →\n REVIEWING → APPROVED → PAYING → COMPLETED \\(or REJECTED/FAILED\\)\n- Add PaymentMethod enum: BANK_CARD, ALIPAY, WECHAT\n- Update WithdrawalOrderAggregate with new fiat withdrawal methods\n- Add review/payment workflow methods in WalletApplicationService\n- Add internal API endpoints for admin withdrawal management\n- Remove blockchain withdrawal event handler \\(no longer needed\\)\n\nFrontend \\(admin-web\\):\n- Add withdrawal review management page at /withdrawals\n- Add tabs for reviewing/approved/paying order states\n- Add withdrawal service and React Query hooks\n- Add types for withdrawal orders and payment methods\n- Add sidebar menu item for withdrawal review\n\nFrontend \\(mobile-app\\):\n- Add withdrawFiat\\(\\) method to WalletService\n- Add PaymentMethod enum with BANK_CARD/ALIPAY/WECHAT\n- Create new WithdrawFiatPage for fiat withdrawal input\n- Create WithdrawFiatConfirmPage with SMS + password verification\n- Add routes for /withdraw/fiat and /withdraw/fiat/confirm\n- Keep existing withdraw/usdt \\(划转\\) pages unchanged\n\nNote: The existing withdraw_usdt_page.dart is for point-to-point\ntransfer \\(划转\\), which is a different feature from fiat withdrawal.\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfix\\(planting\\): draw signature directly on page instead of using form field\n\nThe PDF signature field is only 92x51 points, which causes signatures to\nappear too small or invisible. Changed to use drawImage\\(\\) directly on\nthe page at the field''s position with a larger size \\(150x80 max\\).\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(pnpm exec tsc:*)",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(wallet-service\\): add offline settlement deduction feature\n\nAdd new functionality for admins to automatically deduct all settled\nearnings when creating special deductions with amount=0, marking\neach record to prevent duplicate deductions.\n\n- Add OfflineSettlementDeduction model to track deducted records\n- Add API endpoints for querying unprocessed settlements and executing batch deduction\n- Add mode selection UI in admin-web pending-actions\n- Add offline settlement card display in mobile-app special deduction page\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfix\\(wallet-service\\): convert BigInt to string for JSON serialization in getUnprocessedSettlements\n\nThe entry.id field is BigInt type from Prisma which cannot be JSON serialized directly.\nConvert to string for API response and back to BigInt when storing to database.\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(mobile-app\\): improve empty state display for offline settlement deduction\n\nWhen there are no settlement records to deduct, show a more informative message:\n- If user has balance from deposits/transfers: explain it''s not from earnings\n- If user has no balance: explain there are no settlement records\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(wallet/blockchain/identity\\): implement system account withdrawal feature\n\n- Add SystemWithdrawalApplicationService to handle system account transfers\n- Add SystemWithdrawalController with endpoints for request, query, and account listing\n- Add SystemWithdrawalStatusHandler to process blockchain confirmation/failure events\n- Add SystemWithdrawalRequestedHandler in blockchain-service to execute ERC20 transfers\n- Add getUserByAccountSequence endpoint in identity-service for user lookup\n- Support dynamic memo generation based on actual source account name\n- Dual-sided ledger entries for system account transfers\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(admin-web\\): add system account transfer management page\n\n- Add system-transfer page with transfer form and order history\n- Add SystemWithdrawalService for API calls\n- Add useSystemWithdrawal hooks for React Query integration\n- Add system-withdrawal types definitions\n- Add navigation menu item for system transfer\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(PGPASSWORD=rwa_dev_password psql:*)",
"Bash(where psql:*)",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfix\\(reporting-service\\): 修复面对面结算数据解包问题\n\nwallet-service 返回 { success, data, timestamp } 包装格式,\ngetOfflineSettlementSummary 需要用 response.data.data 解包才能获取真正的数据。\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(wallet-service\\): 添加手续费归集统计的历史数据兼容\n\n当 FEE_COLLECTION 流水为空时,自动从提现订单表查询历史手续费:\n- getFeeCollectionSummary: 从 withdrawal_orders 和 fiat_withdrawal_orders 聚合统计\n- getFeeCollectionEntries: 从两个订单表查询明细列表,支持分页和类型筛选\n- 按月统计使用 UNION ALL 合并两种提现订单数据\n- 明细记录添加备注说明区分来源(区块链/法币)\n\n回滚方式:删除 fallback 代码块和两个私有方法\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(dir /s /b *.yml)",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(mobile-app\\): 添加联系客服功能\n\n在个人中心设置菜单中添加\"联系客服\"入口,点击后显示弹窗,\n用户可以查看客服的QQ号和微信号,并支持一键复制到剪贴板。\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfix\\(wallet-service, admin-web\\): 修复系统账户划转金额类型问题\n\n- wallet-service: 支持 amount 为字符串或数字类型,添加类型转换\n- admin-web: 改进错误处理,正确提取 Axios 错误消息\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(mobile-app\\): 更新客服联系方式\n\n- 客服微信1: liulianhuanghou1\n- 客服微信2: liulianhuanghou2\n- 客服QQ1: 1502109619\n- 客服QQ2: 2171447109\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(wallet-service\\): 添加运营1和积分股池到系统划转账户列表\n\n- 添加 S0000000002 \\(运营1\\) 和 S0000000004 \\(积分股池\\) 到允许转出白名单\n- 更新系统账户名称映射与前端保持一致\n- 为 S0000000006 手续费归集账户添加兼容逻辑,当余额为0时从提现订单表统计历史手续费\n- 优化过期奖励处理,按分配类型分别记录流水便于明细查看\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfix\\(wallet-service\\): 修复系统账户余额统计不一致问题\n\n- 账户余额改为 usdtAvailable + settleableUsdt,与累计收入统计保持一致\n- 解决社区权益进入 settleableUsdt 导致的余额与累计收入不匹配问题\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfix\\(referral-service\\): 修复 Kafka 消费异常被吞掉的问题\n\n- kafka.service.ts: 抛出异常让 KafkaJS 触发重试\n- user-registered.handler.ts: 传播异常到 KafkaService\n\n修复前处理失败的消息不会重试,导致推荐关系可能丢失\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfix\\(leaderboard-service\\): 修复健康检查 API 路径\n\n将 Dockerfile 和 docker-compose.yml 中的健康检查路径从\n/api/health 修改为 /api/v1/health,与实际 API 路由保持一致\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git -C \"c:/Users/dong/Desktop/rwadurian\" commit -m \"$\\(cat <<''EOF''\nfix\\(admin-web\\): 优化授权页面错误提示,显示后端真实错误信息\n\n问题:创建授权失败时只显示\"Request failed with status code 400\"\n用户无法了解失败的真实原因(如用户未种树、授权冲突等)\n\n修复:\n- handleCreate和handleRevoke的catch块优先从err.response.data.message提取后端错误\n- 后端已有完善的错误提示如\"用户尚未认种任何树,无法授权\"\n- 前端现在能正确显示这些提示帮助管理员了解真实情况\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(ssh ceshi@103.39.231.231 \"cd /home/ceshi/rwadurian/backend/api-gateway && docker compose exec kong kong reload 2>/dev/null || docker exec kong kong reload\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfix\\(deploy\\): 修正 Debezium Connect 默认端口为 8084\n\ndocker-compose 中 Debezium Connect 映射到 8084 端口\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfix\\(debezium\\): 修复 outbox connector 配置中的数据库凭证\n\n使用实际的用户名和密码替代环境变量占位符,\n因为 envsubst 不支持带默认值的变量语法\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(ssh -o ProxyCommand=\"ssh -W %h:%p ceshi@103.39.231.231\" ceshi@192.168.1.111 \"docker exec rwa-postgres psql -U rwa_user -d rwa_mining_admin -c \"\"\nSELECT ''synced_users'' as table_name, COUNT\\(*\\) as count FROM synced_users\nUNION ALL SELECT ''synced_contribution_accounts'', COUNT\\(*\\) FROM synced_contribution_accounts\nUNION ALL SELECT ''synced_mining_accounts'', COUNT\\(*\\) FROM synced_mining_accounts\nUNION ALL SELECT ''synced_trading_accounts'', COUNT\\(*\\) FROM synced_trading_accounts\nUNION ALL SELECT ''synced_mining_configs'', COUNT\\(*\\) FROM synced_mining_configs\nUNION ALL SELECT ''synced_circulation_pools'', COUNT\\(*\\) FROM synced_circulation_pools\nUNION ALL SELECT ''synced_system_contributions'', COUNT\\(*\\) FROM synced_system_contributions\nUNION ALL SELECT ''synced_daily_mining_stats'', COUNT\\(*\\) FROM synced_daily_mining_stats\nUNION ALL SELECT ''synced_day_klines'', COUNT\\(*\\) FROM synced_day_klines;\n\"\"\")",
"Bash(ssh -o ProxyCommand=\"ssh -W %h:%p ceshi@103.39.231.231\" ceshi@192.168.1.111 \"docker exec rwa-postgres psql -U rwa_user -d rwa_mining_admin -t -c \"\"\nSELECT ''synced_users'' as tbl, COUNT\\(*\\) FROM synced_users\nUNION ALL SELECT ''synced_contribution_accounts'', COUNT\\(*\\) FROM synced_contribution_accounts\nUNION ALL SELECT ''synced_mining_accounts'', COUNT\\(*\\) FROM synced_mining_accounts\nUNION ALL SELECT ''synced_trading_accounts'', COUNT\\(*\\) FROM synced_trading_accounts;\n\"\"\")",
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(mining-app\\): fix login bugs and connect contribution page to real API\n\nLogin fixes:\n- Add AuthEventBus for global 401 error handling with auto-logout\n- Add route guards with GoRouter redirect to protect authenticated routes\n- Remove setMockUser\\(\\) security vulnerability and legacy login\\(\\) dead code\n- Remove unused AuthInterceptor class\n\nContribution page:\n- Add ContributionRecord entity and model for records API\n- Connect contribution details card to GET /accounts/{id}/records endpoint\n- Display real team stats \\(direct referrals, unlocked levels/tiers\\)\n- Calculate expiration countdown from actual record data\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(dependency of a provider changed\" error when 401 responses triggered\nlogout during provider rebuilds.\n\nNow 401 handling is done through normal exception flow in splash page\nand route guards respond to isLoggedInProvider state changes.\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git -C \"c:\\\\Users\\\\dong\\\\Desktop\\\\rwadurian\" commit -m \"$\\(cat <<''EOF''\nfix\\(mining-app\\): unify color scheme and fix scroll issues\n\n- Update login/register pages to use orange color scheme \\(#FF6B00\\)\n matching the navigation pages design\n- Fix SafeArea bottom: false on all navigation pages since MainShell\n handles bottom safe area via bottomNavigationBar\n- Add AlwaysScrollableScrollPhysics to asset page for consistent scroll\n- Increase bottom padding to 100px on all navigation pages to clear\n the navigation bar\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git -C \"c:\\\\Users\\\\dong\\\\Desktop\\\\rwadurian\" commit -m \"$\\(cat <<''EOF''\nfix\\(mining-app\\): update splash page theme and fix token refresh\n\n- Update splash_page.dart to orange theme \\(#FF6B00\\) matching other pages\n- Change app name from \"榴莲挖矿\" to \"榴莲生态\"\n- Fix refreshTokenIfNeeded to properly throw on failure instead of\n silently calling logout \\(which caused Riverpod ref errors\\)\n- Clear local storage directly on refresh failure without remote API call\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(python3 -c \" import sys content = sys.stdin.read\\(\\) old = '''''' done # 清空 processed_cdc_events 表(因为 migration 时可能已经消费了一些消息) # 这是事务性幂等消费的关键:重置 Kafka offset 后必须同时清空幂等记录 log_info \"\"Truncating processed_cdc_events tables to allow re-consumption...\"\" for db in \"\"rwa_contribution\"\" \"\"rwa_auth\"\"; do if run_psql \"\"$db\"\" \"\"TRUNCATE TABLE processed_cdc_events;\"\" 2>/dev/null; then log_success \"\"Truncated processed_cdc_events in $db\"\" else log_warn \"\"Could not truncate processed_cdc_events in $db \\(table may not exist yet\\)\"\" fi done log_step \"\"Step 9/18: Starting 2.0 services...\"\"'''''' new = '''''' done # 清空 processed_cdc_events 表(因为 migration 时可能已经消费了一些消息) # 这是事务性幂等消费的关键:重置 Kafka offset 后必须同时清空幂等记录 log_info \"\"Truncating processed_cdc_events tables to allow re-consumption...\"\" for db in \"\"rwa_contribution\"\" \"\"rwa_auth\"\"; do if run_psql \"\"$db\"\" \"\"TRUNCATE TABLE processed_cdc_events;\"\" 2>/dev/null; then log_success \"\"Truncated processed_cdc_events in $db\"\" else log_warn \"\"Could not truncate processed_cdc_events in $db \\(table may not exist yet\\)\"\" fi done log_step \"\"Step 9/18: Starting 2.0 services...\"\"'''''' print\\(content.replace\\(old, new\\)\\) \")",
"Bash(git rm:*)",
"Bash(echo \"请在服务器运行以下命令检查 outbox 事件:\n\ndocker exec -it rwa-postgres psql -U rwa_user -d rwa_contribution -c \"\"\nSELECT id, event_type, aggregate_id, \n payload->>''sourceType'' as source_type,\n payload->>''accountSequence'' as account_seq,\n payload->>''sourceAccountSequence'' as source_account_seq,\n payload->>''bonusTier'' as bonus_tier\nFROM outbox_events \nWHERE payload->>''accountSequence'' = ''D25122900007''\nORDER BY id;\n\"\"\")",
// For co_managed_keygen sessions: wallet name and invite code
WalletNamestring`protobuf:"bytes,10,opt,name=wallet_name,json=walletName,proto3" json:"wallet_name,omitempty"`// Wallet name (for co_managed_keygen)
InviteCodestring`protobuf:"bytes,11,opt,name=invite_code,json=inviteCode,proto3" json:"invite_code,omitempty"`// Invite code for participants to join (for co_managed_keygen)
// threshold_n and threshold_t - actual threshold values from session config
// Used for co_managed_keygen sessions where total_parties may differ from threshold_n during joining
ThresholdNint32`protobuf:"varint,10,opt,name=threshold_n,json=thresholdN,proto3" json:"threshold_n,omitempty"`// Total number of parties required (e.g., 3 in 2-of-3)
ThresholdTint32`protobuf:"varint,11,opt,name=threshold_t,json=thresholdT,proto3" json:"threshold_t,omitempty"`// Minimum parties needed to sign (e.g., 2 in 2-of-3)
// MessageRouterClient is the client API for MessageRouter service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// MessageRouter service handles MPC message routing
// This is the ONLY service that server-parties need to connect to.
// All session operations are proxied through Message Router to Session Coordinator.
typeMessageRouterClientinterface{
// RouteMessage routes a message from one party to others
// SessionCoordinatorClient is the client API for SessionCoordinator service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// SessionCoordinator service manages MPC sessions