Commit Graph

595 Commits

Author SHA1 Message Date
hailin 8cea0e7998 fix(reward): change sourceOrderId to sourceOrderNo string type
Fixes BigInt conversion error when consuming planting.order.paid events.
The orderId from planting-service is a string format like PLT1765391584505Q0Q6QD,
not a numeric value.

Changes:
- reward-source.vo.ts: sourceOrderId (bigint) → sourceOrderNo (string)
- reward-calculation.service.ts: updated all method signatures
- reward-application.service.ts: updated distributeRewards params
- event-consumer.controller.ts: removed BigInt() conversion
- prisma schema: changed column type to VarChar(50)
- mapper/repository: updated field names accordingly
- Removed incompatible prisma.config.ts (Prisma 7.x format)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 11:12:58 -08:00
hailin 6b10b15492 chore(identity): temporarily disable device registration check
Allow same device to create multiple accounts for testing purposes.
Original validation code is commented out and can be restored later.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 11:07:21 -08:00
hailin 9e6fc04344 fix(reward): register EventConsumerController to enable Kafka consumption
EventConsumerController was not registered in KafkaModule, causing
@MessagePattern('planting.order.paid') to never be subscribed.
This resulted in reward-service having empty memberAssignment.

Also added forwardRef to resolve circular dependency between
ApplicationModule and InfrastructureModule.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 10:36:55 -08:00
hailin 4972e56ad2 fix(reward): correct health check path to /api/v1/health
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 10:16:57 -08:00
hailin adc063eb7a fix(authorization): add Kafka microservice for @EventPattern to work
authorization-service uses @EventPattern('planting-events') to consume
planting events but was missing connectMicroservice() configuration.
Without this, the service could not receive planting events, causing:
- Province team benefits (20 USDT) not distributed
- City team benefits (40 USDT) not distributed
- Community benefits (80 USDT) not distributed
- Monthly assessment data not updated

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 10:08:55 -08:00
hailin f36fc0e8b7 fix(services): add Kafka microservice for @MessagePattern to work
The @MessagePattern decorator requires connectMicroservice() to work.
Without this configuration, services could not consume Kafka messages
via @MessagePattern, causing events to be lost.

Fixed services:
- planting-service: ACK consumption
- identity-service: event consumption
- reward-service: event consumption

blockchain-service already had this configured.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 09:57:07 -08:00
hailin 70d1a8bfb8 fix(referral): add idempotency check for Kafka event processing
- Add processed_events table to track handled events
- Check eventId before processing planting.created events
- Skip duplicate events and still send ACK to stop retries

This prevents data accumulation when Kafka events are redelivered
due to ACK failures or consumer timeouts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 09:38:13 -08:00
hailin 3714edb30b feat(wallet): add detailed logging for freeze-for-planting API
Added comprehensive logging to track:
- Request parameters (userId, amount, orderId)
- Wallet balance information
- Balance check results
- Freeze operation status

This helps debug the 400 error when planting-service calls wallet-service.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 08:38:36 -08:00
hailin 22c32031af feat(authorization): add community assessment progress to profile page
Backend:
- Add initialTargetTreeCount, currentTreeCount, monthlyTargetTreeCount
  fields to AuthorizationDTO and AuthorizationResponse
- Query TeamStatistics to populate current tree count in getUserAuthorizations

Frontend:
- Update AuthorizationResponse to parse new progress fields
- Replace hardcoded community assessment values with real API data
- Show authorization status: red (unauthorized), orange (pending), green (active)
- Display progress bar and target requirements based on benefit status

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 06:44:13 -08:00
hailin e5e2793337 feat(planting): add payment reliability improvements
## wallet-service
- Add freeze/confirm/unfreeze API endpoints for planting deduction
- Add deductFrozen method to wallet-account aggregate
- Add PLANT_FREEZE and PLANT_UNFREEZE ledger entry types
- Add idempotency check in deductForPlanting
- Fix test files to include accountSequence parameter

## planting-service
- Add PaymentCompensation model and migration
- Add payment-compensation.repository.ts
- Add payment-compensation.service.ts (background job for retry)
- Add HTTP retry mechanism with exponential backoff
- Refactor payOrder to use freeze → transaction → confirm flow
- Create compensation record on unfreeze failure

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 06:31:54 -08:00
hailin 68182fd0a3 feat(referral): add personal/team planting counts to direct referral list
- Backend: batch query TeamStatistics to get each direct referral's
  personalPlantingCount and teamPlantingCount
- Updated DTO and query interfaces with new fields
- Frontend: parse and display "个人/团队" counts in profile page

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 05:57:46 -08:00
hailin 13f670e9dd fix(referral): fix direct referral list display and count issues
1. Return accountSequence instead of userId for direct referral list display
2. Create missing team statistics record when referrer doesn't have one

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 04:58:16 -08:00
hailin 12116ff164 feat(blockchain): add deposit repair service and controller
Add internal APIs to diagnose and repair historical deposit issues:
- GET /internal/deposit-repair/diagnose - Query unnotified deposits
- POST /internal/deposit-repair/repair/:depositId - Repair single deposit
- POST /internal/deposit-repair/repair-all - Batch repair all pending deposits
- POST /internal/deposit-repair/reset-failed-outbox - Reset failed outbox events

The repair service creates new outbox events for CONFIRMED deposits
that were never notified to wallet-service.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 02:19:46 -08:00
hailin 30aa11c6c6 fix(referral): fix EventAckMessage type casting
Cast ackMessage to Record<string, unknown> for KafkaService compatibility.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 22:31:12 -08:00
hailin 807dc8705d fix(referral): add EventAckPublisher to InfrastructureModule
- Refactor EventAckPublisher to use KafkaService instead of ClientKafka
- Add kafka/index.ts export file
- Register EventAckPublisher in InfrastructureModule providers and exports

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 22:29:54 -08:00
hailin dfa21c0280 feat(mobile): integrate PlantingService with real API
- Add PlantingService for planting order management
  - createOrder: Create new planting order
  - selectProvinceCity: Select province and city
  - confirmProvinceCity: Confirm province/city selection
  - payOrder: Pay for order
  - getOrder/getMyOrders: Query orders
  - cancelOrder: Cancel unpaid orders
- Register PlantingService in DI container
- Update planting_quantity_page to create order before navigation
- Update planting_location_page to call real API endpoints
- Fix referral-service event-ack.publisher to use KafkaService

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 22:28:36 -08:00
hailin ba5b6141a3 fix(planting-service): improve outbox event confirmation accuracy
- markAsConfirmed now uses aggregateId + eventType for precise matching
- Prevents accidentally confirming multiple events for the same order
- EventAckController passes eventType to markAsConfirmed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 22:16:23 -08:00
hailin 8de7a668f0 fix(referral): remove LeaderboardCacheService dependency
Leaderboard functionality has been moved to leaderboard-service.
Remove the dependency and set leaderboardRank to null.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 22:13:57 -08:00
hailin 49fc68297b fix(blockchain): fix TypeScript compilation errors
- Fix brokers type narrowing issue in deposit-ack-consumer.service.ts
- Add Prisma.InputJsonValue type cast for payload in outbox-event.repository.impl.ts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 22:11:28 -08:00
hailin 2bf5ca933e refactor(referral): remove legacy leaderboard code
Remove duplicate leaderboard functionality from referral-service.
All leaderboard features should now go through leaderboard-service.

Removed files:
- api/controllers/leaderboard.controller.ts
- api/dto/leaderboard.dto.ts
- application/queries/get-leaderboard.query.ts
- infrastructure/cache/leaderboard-cache.service.ts
- Related test files

Modified:
- TeamStatisticsService: removed getLeaderboard() and getUserRank()
- Module registrations updated

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 22:05:48 -08:00
hailin 594f7880c3 fix(gateway): remove duplicate /leaderboard route from referral-service
The /api/v1/leaderboard route was duplicated in both referral-service
and leaderboard-service. Since leaderboard-service is the dedicated
ranking service with more features (daily/weekly/monthly rankings,
virtual accounts, snapshots), all leaderboard requests should be
routed to leaderboard-service.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 22:00:22 -08:00
hailin 181eeafb2c fix(authorization-service): fix KafkaModule dependency injection
- Add ClientsModule with KAFKA_SERVICE registration
- Add EventAckPublisher to KafkaModule providers/exports
- Move EventConsumerController to AppModule (has access to repositories)

Resolves: Nest can't resolve dependencies of EventConsumerController

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 21:55:10 -08:00
hailin 3f622eb13c feat(gateway): add missing API routes to Kong configuration
Add routes for APIs that were implemented but missing from Kong:
- /api/v1/backup-share (backup-service)
- /api/v1/virtual-accounts (leaderboard-service)
- /api/v1/export (reporting-service)
- /api/v1/analytics (presence-service)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 21:53:55 -08:00
hailin 52ddad1000 fix(api-gateway): correct Kong routes and add missing globalPrefix
- Kong: change /api/v1/plantings to /api/v1/planting (match controller)
- reward-service: add missing app.setGlobalPrefix('api/v1')

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 21:51:58 -08:00
hailin 075c9aaa48 feat(blockchain): implement Outbox Pattern for reliable event delivery
Implement Outbox Pattern with consumer ACK to ensure 100% reliable event
delivery between blockchain-service and wallet-service:

blockchain-service:
- Add OutboxEvent model to Prisma schema with status tracking
- Create outbox repository interface and implementation
- Modify deposit-detection.service to write events to outbox
- Add outbox-publisher.service with cron jobs for publishing/retry
- Add deposit-ack-consumer.service to receive ACK from wallet-service
- Add publishRaw method to event-publisher.service

wallet-service:
- Modify deposit-confirmed.handler to send ACK after successful processing
- Add wallet.deposit.credited topic mapping for ACK events

Event flow:
1. Deposit detected → written to outbox (status: PENDING)
2. Outbox publisher sends to Kafka → status: SENT
3. wallet-service processes and sends ACK → status: ACKED
4. Events without ACK are retried with exponential backoff

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 21:47:31 -08:00
hailin f04f8ed6ce chore(prisma): add missing migration_lock.toml files
Added migration_lock.toml for planting-service, reward-service,
referral-service, and authorization-service to ensure Prisma
can properly track migration provider.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 21:39:20 -08:00
hailin 014ad9d19f feat(planting): implement Outbox Pattern with consumer acknowledgment (B方案)
Implement reliable event delivery using Outbox Pattern with consumer confirmation:

## planting-service (Producer)
- Add OutboxEvent table with status: PENDING → SENT → CONFIRMED
- Add OutboxRepository with transaction support and timeout handling
- Add OutboxPublisherService with polling, timeout check, and retry
- Add EventAckController to receive consumer confirmations
- Update UnitOfWork to save outbox events atomically with business data
- Update PlantingApplicationService to use outbox pattern
- Update PoolInjectionService to use outbox pattern

## Consumer Services
- Add EventAckPublisher to reward-service, referral-service, authorization-service
- Update event handlers to send acknowledgment after successful processing

## Event Flow
1. Business data + outbox events saved in same transaction
2. OutboxPublisher polls and sends to Kafka, marks as SENT
3. Consumer processes event and sends ack to planting.events.ack
4. EventAckController receives ack and marks as CONFIRMED
5. Timeout check resets SENT→PENDING for retry (max 5 times)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 21:32:16 -08:00
hailin b98844abe4 feat(db): add Prisma migrations for wallet-service and planting-service
- Add initial migration for wallet-service (wallet_accounts, ledger_entries, deposit/settlement/withdrawal orders)
- Add initial migration for planting-service (planting_orders, fund_allocations, positions, batches, events)
- Both services now have migrations that will be automatically applied on container startup via `prisma migrate deploy`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 20:30:23 -08:00
hailin bb048bb104 feat(gateway): add wallet service routes for profile page
Add /api/v1/wallet route to Kong gateway to support:
- GET /wallet/my-wallet
- POST /wallet/claim-rewards
- POST /wallet/settle
- POST /wallet/withdraw
- GET /wallet/withdrawals
- GET /wallet/ledger/my-ledger

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 20:16:24 -08:00
hailin 243105f97f fix(guide): use fitWidth to prevent image stretching + add debug logs
- Change BoxFit.cover to BoxFit.fitWidth for guide page images
- Add screen info logging (resolution, pixel ratio, aspect ratio)
- Add detailed avatar loading logs in frontend and backend
- Log avatarUrl from DB and API response during recovery

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 18:36:43 -08:00
hailin a3c0d3948d debug: add detailed logging for avatar loading
Added debug logs in:
- ProfilePage._loadUserData() - local storage data
- ProfilePage._loadMeData() - API response and sync conditions
- ProfilePage._buildAvatarContent() - avatar rendering decision
- UserApplicationService.getMe() - backend avatarUrl value

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 18:24:13 -08:00
hailin 7f2511227f fix(identity-service): regenerate avatar if missing during account recovery
When recovering account via mnemonic or phone, check if avatarUrl is null
and regenerate a new random avatar SVG if needed. This fixes the bug where
users see no avatar after recovering their account.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 18:07:36 -08:00
hailin 2ed1658c16 fix(admin-service): exclude /downloads from API prefix
Downloads route was getting /api/v1 prefix, making it inaccessible at /downloads

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 07:44:53 -08:00
hailin 4b4b09f046 fix(docker): add BASE_URL env for admin-service
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 07:31:32 -08:00
hailin 424fa3514f fix(admin-service): add BASE_URL for APK download URLs
Set BASE_URL to public API gateway address so mobile app can download
APK files from correct URL instead of localhost.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 07:30:16 -08:00
hailin 96804e560b fix(gateway): add /downloads route for APK file downloads
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 07:27:57 -08:00
hailin 917f0f4ee1 fix(gateway): add /api/app/version route for mobile update check
Mobile app was calling /api/app/version/check but this route was not
configured in Kong gateway. Added admin-mobile-version route to forward
these requests to admin-service.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 07:17:01 -08:00
hailin eceb927d54 fix(admin-service): relax changelog and minOsVersion validation
- Changelog: allow empty value, return default "No changelog provided"
- MinOsVersion: allow empty value and single number format (e.g., "24" -> "24.0")

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 07:09:03 -08:00
hailin 58a359d9b3 fix: changelog default value and referrals map syntax
- admin-service: provide default empty string for optional changelog
- profile page: fix map literal syntax for referrals list

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 07:00:02 -08:00
hailin 586dfda8f7 fix(admin): support 4-segment version in domain layer & make changelog optional
- VersionName value object now accepts x.y.z.w format
- changelog field is now optional in upload version DTO
- profile page: ensure expired section has full width

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 06:54:55 -08:00
hailin 4307d1eb91 fix(admin): support 4-segment version number format (x.y.z.w)
Allow version names like 1.0.0.4 in addition to the standard x.y.z format.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 06:41:46 -08:00
hailin 2e6f22e9d8 fix(blockchain): read token decimals from contract instead of hardcoding
The balance display was incorrect because decimals were hardcoded to 18,
but USDT uses 6 decimals. Now reads decimals() from the ERC20 contract.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 06:10:36 -08:00
hailin addcfa56e4 feat(blockchain): switch to testnet mode 2025-12-09 04:05:24 -08:00
hailin 3f2922cca6 fix(mpc-service): reduce rebalanceTimeout from 5min to 1min
sessionTimeout remains at 5 minutes (needed for long MPC operations),
but rebalanceTimeout only affects joining consumer group, not processing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 03:40:14 -08:00
hailin 6ab3f92813 fix(mpc-service): don't block HTTP server startup during Kafka rebalance 2025-12-09 03:31:26 -08:00
hailin 0546cff708 revert: restore Kafka session timeout to 5 minutes 2025-12-09 03:28:28 -08:00
hailin 429f8d5991 Revert "fix(mpc-service): don't block startup on Kafka consumer rebalance"
This reverts commit c924d3aad2.
2025-12-09 03:26:05 -08:00
hailin c924d3aad2 fix(mpc-service): don't block startup on Kafka consumer rebalance 2025-12-09 03:25:07 -08:00
hailin 1eca8b3af8 fix(mpc-service): reduce Kafka session timeout from 5min to 30s 2025-12-09 03:24:00 -08:00
hailin c05722bbb3 fix(mpc-service): enable shutdown hooks for graceful Kafka disconnect
Root cause: When mpc-service restarts, the old Kafka consumer doesn't
properly disconnect, causing the broker to wait for sessionTimeout
(~5 minutes) before completing rebalance. This blocks app startup.

Solution: Enable NestJS shutdown hooks with app.enableShutdownHooks().
This ensures onModuleDestroy() is called on SIGTERM/SIGINT, which calls
consumer.disconnect() and allows immediate rebalance on next startup.

Also reverted the "don't await consumer.run()" workaround since the
proper fix is graceful shutdown.

Sources:
- https://github.com/tulios/kafkajs/issues/807
- https://kafka.js.org/docs/consuming

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 03:12:33 -08:00
hailin af896db36c fix(mpc-service): don't await consumer.run() to prevent app startup blocking
consumer.run() never resolves as it runs continuously. Awaiting it
blocks onApplicationBootstrap which prevents app.listen() from being
called, causing the service to never start listening on port 3006.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 03:04:48 -08:00
hailin 40c78a471d fix(mpc-service): use docker-entrypoint.sh instead of inline script
- Restore Dockerfile to use external docker-entrypoint.sh file
- The inline echo script caused issues on Linux (start.sh not created properly)
- Change from prisma migrate deploy to prisma db push for schema flexibility

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 02:54:11 -08:00
hailin 781721a659 feat(withdrawal): implement withdrawal order and fund allocation system
- Add SystemAccount domain in authorization-service for managing regional/company accounts
- Implement fund allocation service in planting-service with multi-tier distribution
- Add WithdrawalOrder aggregate in wallet-service with full lifecycle management
- Create internal wallet controller for cross-service fund allocation
- Add Kafka event publishing for withdrawal requests
- Implement unit-of-work pattern for transactional consistency
- Update Prisma schemas with withdrawal order and system account tables

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 02:35:27 -08:00
hailin 001b6501a0 feat(deposit): add deposit balance API and Kafka consumer for deposit events
Blockchain Service:
- Add /api/v1/deposit/balances endpoint to query on-chain USDT balances
- Add JWT authentication (passport, passport-jwt)
- Add JwtStrategy, JwtAuthGuard, Public decorator

Wallet Service:
- Add Kafka consumer for blockchain.deposits topic
- Add DepositConfirmedHandler to process deposit events and update wallet balance

Infrastructure:
- Add JWT_SECRET env var to blockchain-service in docker-compose.yml
- Add blockchain-service routes to Kong API Gateway

Frontend:
- Fix deposit_service.dart API path (remove duplicate /api prefix)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 02:29:31 -08:00
hailin d0487c4a7e feat(profile): integrate referral and authorization APIs for profile page
- Add Kong routes for identity-service /me, referral-service, and authorization-service
- Create AuthorizationService in Flutter for fetching user authorizations
- Extend ReferralService with getMyReferralInfo() and getDirectReferrals() methods
- Update profile_page.dart to display real team stats from APIs
- Fix authorization-service JWT strategy to accept identity-service token format
- Add decimal.js dependency to authorization-service
- Add prisma migration file for authorization-service

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 01:57:39 -08:00
hailin 5a5e360e73 docs(identity): update KAVA address format comments to EVM 2025-12-08 23:05:47 -08:00
hailin b9f3482b17 fix(identity): update KAVA address validation to EVM format
KAVA now uses EVM-compatible 0x addresses instead of Cosmos bech32 format.
DST continues to use Cosmos bech32 format (dst1...).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 23:04:14 -08:00
hailin 5d671bf5ec feat(referral): integrate referral system with identity-service and mobile-app
## Backend Changes

### referral-service
- Add accountSequence field to ReferralRelationship aggregate for cross-service user identification
- Add findByAccountSequence() method to repository interface and implementation
- Update CreateReferralRelationshipCommand to accept accountSequence and inviterAccountSequence
- Modify ReferralService to support looking up inviter by accountSequence
- Update event handler to listen to identity.UserAccountAutoCreated and identity.UserAccountCreated topics
- Add initial database migration with all tables including accountSequence field
- Update DTO and controller to support new parameters

### identity-service
- Add inviterSequence field to MeResult interface
- Update getMe() method to return inviterSequence from user account
- Update MeResponseDto to include inviterSequence field

## Frontend Changes (mobile-app)

### API & Storage
- Add /me endpoint constant in api_endpoints.dart
- Add inviterSequence key in storage_keys.dart
- Add MeResponse and WalletAddressInfo classes in account_service.dart
- Add getMe() method to fetch complete user info including inviter
- Add getInviterSequence() method to retrieve from local storage

### Profile Page
- Update profile_page.dart to load referrer info from API
- Add _loadMeData() method to call getMe() API
- Display inviterSequence (referrer serial number) dynamically

## Flow Summary
1. User creates account with optional inviterReferralCode
2. identity-service validates and saves inviterSequence
3. identity-service publishes UserAccountAutoCreated/UserAccountCreated event
4. referral-service listens and creates referral relationship using inviterAccountSequence
5. Mobile app calls GET /me to display inviter info in profile page

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 22:37:06 -08:00
hailin cf7230457f feat(blockchain-service): KAVA EVM address derivation and system accounts support
## Address Derivation Changes
- Change KAVA from Cosmos bech32 (kava1...) to EVM format (0x...)
- KAVA now uses same EVM address as BSC for deposit monitoring
- Add KAVA to evmChains set for automatic monitoring registration

## Database Schema Updates (Migration: 20241208000000)
- MonitoredAddress: add address_type, account_sequence, system_account_type,
  system_account_id, region_code columns
- DepositTransaction: add address_type, account_sequence, system_account_type,
  system_account_id columns
- Make user_id nullable for system account support
- Create recovery_mnemonics table for account recovery
- Add indexes: idx_account_sequence, idx_type_active, idx_system_account_type,
  idx_deposit_account, and recovery_mnemonics indexes

## New Features
- Withdrawal request handler and Kafka consumer
- Test USDT deployment scripts for KAVA and BSC
- Smart contracts for TestUSDT token

## Infrastructure Updates
- Update mappers for new schema fields
- Update application and infrastructure modules

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 21:45:34 -08:00
hailin 78304801f5 feat(identity): change username format to '榴莲女皇x号'
- Replace random username generation with fixed format
- Username now uses accountSequence: '榴莲女皇{序列号}号'
- Keep random durian-themed SVG avatar generation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 20:16:11 -08:00
hailin 3c2144ad7c feat(deposit): add accountSequence correlation and testnet support
blockchain-service:
- Add accountSequence to monitored_addresses and deposit_transactions
- Support BSC/KAVA testnet via NETWORK_MODE environment variable
- Add chain config service with testnet RPC endpoints
- Update deposit detection with accountSequence propagation

wallet-service:
- Add accountSequence to wallet_accounts and ledger_entries
- Fix JWT strategy to match identity-service token format
- Update deposit handling with accountSequence correlation
- Add repository methods for accountSequence-based queries

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 10:26:01 -08:00
hailin 6b85401d5c fix(mnemonic): fix recovery-by-mnemonic using hash verification instead of address matching
## Problem
MPC wallet addresses have no cryptographic relationship with recovery mnemonics,
so address-based verification always failed for account recovery.

## Solution
Changed mnemonic verification from address matching to hash-based verification:
- Mnemonic acts as identity credential, verified by hash stored in blockchain-service
- Uses accountSequence to lookup stored mnemonic hash for verification

## Changes

### blockchain-service
- recovery-mnemonic.adapter.ts:
  - generateMnemonic() now async, uses bcrypt (rounds=12) for secure hashing
  - verifyMnemonic() now async, supports both bcrypt and legacy SHA256 hashes
  - Added backward compatibility for existing SHA256 hashed mnemonics
- mnemonic-verification.service.ts:
  - await verifyMnemonic() for async bcrypt comparison
- address-derivation.service.ts:
  - await generateMnemonic() for async bcrypt hashing
- package.json: added bcrypt dependency

### identity-service
- user-application.service.ts:
  - Changed recoverByMnemonic() to use verifyMnemonicByAccount (hash verification)
  - Added rate limiting: 5 failed attempts per hour per accountSequence
  - Uses Redis to track failed verification attempts
- redis.service.ts:
  - Added incr() and expire() methods for rate limiting
  - Added updateKeygenStatusAtomic() with Lua script for atomic state transitions
- mpc-keygen-completed.handler.ts:
  - Uses atomic Redis update to prevent race conditions
- blockchain-wallet.handler.ts:
  - Uses atomic Redis update for completed status

## Security Improvements
- bcrypt with 12 rounds for mnemonic hashing (anti-brute-force)
- Rate limiting prevents brute force attacks on mnemonic recovery
- Atomic Redis operations prevent race conditions in wallet creation flow

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 09:02:24 -08:00
hailin d983525aa5 fix(wallet): resolve account creation and wallet status query issues
This commit fixes three critical bugs that prevented the wallet creation
flow from completing successfully:

1. mpc-service: extraPayload not included in Kafka messages
   - KeygenCompletedEvent's extraPayload (containing userId, accountSequence,
     username, derivedAddresses) was being set dynamically but not serialized
   - identity-service received events without userId and skipped processing
   - Fix: Merge extraPayload into the published payload in event-publisher

2. mpc-service: KAFKA_BROKERS hostname mismatch
   - mpc-service used KAFKA_BROKERS=rwa-kafka:29092
   - Kafka advertises itself as kafka:29092 in cluster metadata
   - During consumer group rebalance, mpc-service couldn't connect to
     the coordinator address returned by Kafka
   - Fix: Use kafka:29092 to match Kafka's advertised listener

3. blockchain-service: recovery_mnemonics table missing
   - RecoveryMnemonic model exists in schema.prisma but not in migration
   - prisma migrate deploy found no pending migrations
   - Address derivation failed with "table does not exist" error
   - Fix: Use prisma db push instead of migrate deploy to sync schema

Tested: E2E flow now completes successfully
- POST /user/auto-create creates account
- MPC keygen completes and publishes event with extraPayload
- blockchain-service derives addresses and saves recovery mnemonic
- GET /user/wallet returns status=ready with 3 addresses and mnemonic

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 07:57:17 -08:00
hailin 43016e9ee8 fix(prisma): remove redundant migrations and duplicate indexes
- mpc-service: remove duplicate index idx_ms_username on mpc_shares.username
  (keep only unique index uq_ms_username since username is unique)
- identity-service: remove redundant migration 20241206000000_add_device_hardware_info
  (fields already exist in initial migration 20241204000000_init)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 07:08:24 -08:00
hailin 1bfbaa06f1 feat(mnemonic): propagate accountSequence through MPC keygen flow (DDD)
Changes across all three services to properly associate recovery mnemonics
with account sequence numbers instead of user IDs, following DDD principles:

identity-service:
- Add accountSequence to MpcKeygenRequestedEvent payload
- Pass accountSequence when publishing keygen request
- Remove direct access to recoveryMnemonic table (now in blockchain-service)
- Call blockchain-service for mnemonic backup marking
- BlockchainWalletHandler no longer saves mnemonic (stored in blockchain-service)

mpc-service:
- Add accountSequence to KeygenRequestedPayload interface
- Pass accountSequence through to blockchain-service when deriving addresses
- Include accountSequence in KeygenCompleted event extraPayload

blockchain-service:
- Add accountSequence to derive-address API and internal interfaces
- Add accountSequence to KeygenCompletedPayload extraPayload
- Add PUT /internal/mnemonic/backup API for marking mnemonic as backed up
- Store recovery mnemonic with accountSequence association

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 01:08:27 -08:00
hailin e95dc4ca57 refactor(mnemonic): move recovery_mnemonics to blockchain-service (DDD)
- Add RecoveryMnemonic model to blockchain-service with accountSequence
- Add MnemonicVerificationService for mnemonic verification logic
- Update verify-mnemonic-hash endpoint to accept accountSequence
- Remove PrismaService dependency from identity-service handler
- identity-service now calls blockchain-service for mnemonic verification

This follows DDD principles: blockchain-service owns all mnemonic-related
data and operations, identity-service only handles account identity.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 00:54:25 -08:00
hailin 0311ecf498 fix(mnemonic): use hash verification instead of address derivation for account recovery
The mnemonic recovery now uses stored hash comparison via blockchain-service
instead of trying to derive addresses from mnemonic (which never matched
because MPC wallet addresses are not derived from mnemonics).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 00:44:47 -08:00
hailin 1a5bafec1a fix: add api/v1 prefix to BLOCKCHAIN_SERVICE_URL 2025-12-08 00:09:54 -08:00
hailin 3df55fcd6a fix: add BLOCKCHAIN_SERVICE_URL=http://blockchain-service:3012 for mnemonic verification 2025-12-08 00:04:39 -08:00
hailin 56de1bff83 revert: remove BLOCKCHAIN_SERVICE_URL override, use default port 3000 2025-12-07 23:57:59 -08:00
hailin a7a7b6b8f6 fix(services): add BLOCKCHAIN_SERVICE_URL to identity-service
Fix mnemonic verification by connecting to blockchain-service on port 3012

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 23:50:55 -08:00
hailin 2613a601b4 chore: update MinIO credentials in .env.example files
Sync MINIO_SECRET_KEY default value with MinIO server config

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 23:22:45 -08:00
hailin b1e51bd73b fix: change MINIO_PUBLIC_URL from cdn to minio.szaiai.com
CDN domain has nginx host header issue, use minio.szaiai.com directly

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 22:26:30 -08:00
hailin 91c8bba80d fix(identity-service): configure MinIO to connect to external server
- Update MINIO_ENDPOINT from localhost to 192.168.1.100 (Server A)
- Add MinIO environment variables to docker-compose.yml
- Set MINIO_PUBLIC_URL to https://cdn.szaiai.com for CDN access
- Add MinIO config section to backend/services/.env.example

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 22:22:55 -08:00
hailin 2256ff69bf fix(minio): use HTTP-only nginx config for initial install
Remove SSL configuration from nginx config file. SSL will be added
automatically by certbot when running ./install.sh --ssl

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 22:18:23 -08:00
hailin 97ef204f7c docs(minio): clarify nginx installation steps
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 22:02:15 -08:00
hailin 81cd90eae0 fix(identity): add StorageService to InfrastructureModule in app.module.ts
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 21:53:06 -08:00
hailin 0989d914de chore(identity): update package-lock.json for minio and multer
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 21:42:16 -08:00
hailin 550a3dba06 feat(identity): add avatar upload with MinIO storage
- Add StorageService for MinIO object storage operations
- Add upload-avatar API endpoint with file validation
- Support jpg, png, gif, webp formats (max 5MB)
- Auto-update user profile after avatar upload

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 21:38:35 -08:00
hailin 6bf23fc8d3 docs(minio): add setup guide documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 21:14:30 -08:00
hailin ea6ede598d feat(infrastructure): add MinIO object storage configuration
- Add docker-compose.yml for MinIO with auto-initialization
- Add deploy.sh script with comprehensive management commands
- Add nginx reverse proxy configuration for S3 API and console
- Configure default buckets: avatars, documents, resources, backups
- Add CDN caching support for public resources

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 21:12:57 -08:00
hailin c1670d2439 feat(mnemonic): add recovery mnemonic generation and backup confirmation
Backend (blockchain-service):
- Add RecoveryMnemonicAdapter to generate 12-word BIP39 mnemonic
- Generate mnemonic when wallet addresses are derived (linked to public key)
- Include mnemonic in WalletAddressCreated event

Backend (identity-service):
- Add RecoveryMnemonic table with revocation/replacement support
- Save encrypted mnemonic to database on WalletAddressCreated event
- Add PUT /user/mnemonic/backup API to mark mnemonic as backed up
- Clear plaintext mnemonic from Redis after backup confirmation

Frontend (mobile-app):
- Update markMnemonicBackedUp() to call backend API
- Fix verify_mnemonic_page validation logic:
  - Checkbox checked → pass directly
  - Not checked → must select correct word

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 12:32:10 -08:00
hailin 8e9eb0ef19 fix(identity): add device_info columns to user_devices migration
- Add device_info JSONB column for storing complete device info
- Add platform, device_model, os_version, app_version columns
- Add screen_width, screen_height, locale, timezone columns
- Add idx_platform index

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 11:42:55 -08:00
hailin 29f2dc0524 fix(identity): remove address from updateProfile and fix deviceInfo type
- Remove dto.address parameter from updateProfile controller
- Remove address property from updateProfile service
- Fix deviceInfo JSON serialization for Prisma InputJsonValue type

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 11:29:51 -08:00
hailin 79345a20cf fix(identity): update migration to TEXT avatar and remove province/city/address
- Change avatar_url column from VARCHAR(500) to TEXT
- Remove province_code, city_code, address columns from user_accounts
- Remove idx_province_city index

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 11:28:09 -08:00
hailin 2705812826 refactor(identity): remove province/city/address fields
- Remove provinceCode, cityCode, address from UserAccount aggregate
- Remove ProvinceCode, CityCode value objects
- Remove UserLocationUpdatedEvent domain event
- Update Prisma schema to drop province/city/address columns
- Update repository, mapper, handlers, services and DTOs
- Clean up tests and factory files

Province/city should belong to adoption-service as transaction data,
not identity-service user data.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 11:23:26 -08:00
hailin fbec0b9112 feat(identity): store complete deviceInfo JSON from frontend
- Add deviceInfo JSON field to UserDevice table (Prisma schema)
- Update DeviceInfo value object to use deviceInfo instead of HardwareInfo
- Update repository to save complete JSON with redundant fields for queries
- Update mapper to read deviceInfo from database
- Update aggregate and handlers to pass deviceInfo through
- Allow any fields in DeviceNameInput interface with index signature

100% preserve original device info JSON from frontend without extraction

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 11:08:37 -08:00
hailin 592f13e939 refactor(identity-service): 简化DeviceNameDto为接收任意JSON对象
- 将DeviceNameDto从class改为interface
- 使用@IsObject()验证,允许前端传递任意设备信息字段
- 添加index signature允许扩展字段
- 后端只提取需要的字段存储到数据库

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 10:59:45 -08:00
hailin 0c7f9b6da9 feat(identity-service): 扩展DeviceNameDto支持更多设备信息字段
添加以下可选字段:
- brand: 品牌
- manufacturer: 厂商
- device: 设备名
- product: 产品名
- hardware: 硬件名
- sdkInt: SDK版本(Android)
- isPhysicalDevice: 是否真机

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 10:58:47 -08:00
hailin 657b66c9e5 fix: 修复钱包API路径和avatarUrl字段长度问题
- identity-service: avatarUrl字段从VarChar(2000)改为Text类型
- mobile-app: 修复getWalletInfo API路径从/user/$id/wallet改为/user/wallet
- mobile-app: 添加userWallet端点常量

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 10:53:40 -08:00
hailin 51be55d315 feat(reward): 补全10种认种奖励分配规则
新增4种系统费用类权益:
- COST_FEE: 成本费 400 USDT → 成本账户(userId=2)
- OPERATION_FEE: 运营费 300 USDT → 运营账户(userId=3)
- HEADQUARTERS_BASE_FEE: 总部社区基础费 9 USDT → 总部社区(userId=1)
- RWAD_POOL_INJECTION: RWAD底池注入 800 USDT → 底池账户(userId=4)

原有6种用户权益类保持不变:
- SHARE_RIGHT: 分享权益 500 USDT
- PROVINCE_AREA_RIGHT: 省区域权益 15 USDT + 1%算力
- PROVINCE_TEAM_RIGHT: 省团队权益 20 USDT
- CITY_AREA_RIGHT: 市区域权益 35 USDT + 2%算力
- CITY_TEAM_RIGHT: 市团队权益 40 USDT
- COMMUNITY_RIGHT: 社区权益 80 USDT

总计: 400 + 300 + 9 + 800 + 500 + 15 + 20 + 35 + 40 + 80 = 2199 USDT

同时更新seed脚本创建4个系统账户

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 09:19:20 -08:00
hailin 667ca1527a feat(blockchain-service): add Prisma migration files
Add initial migration 20241207000000_init with all database tables:
- monitored_addresses
- deposit_transactions
- block_checkpoints
- transaction_requests
- blockchain_events

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 09:08:31 -08:00
hailin 54d3533c18 feat(services): add infra-clean and infra-reset commands
- infra-clean: Remove infrastructure containers and volumes (DELETES DATA)
- infra-reset: Clean and reinstall infrastructure (DELETES DATA)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 08:56:36 -08:00
hailin bfddd203ca feat(services): add --no-cache option to rebuild-svc command
Usage: ./deploy.sh rebuild-svc <name> --no-cache

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 08:46:00 -08:00
hailin fdb3c132de feat(services): add infrastructure management commands to deploy.sh
Add commands for managing infrastructure services separately:
- infra-up: Start postgres, redis, zookeeper, kafka
- infra-down: Stop infrastructure services
- infra-restart: Restart infrastructure
- infra-status: Show infrastructure status with health checks
- infra-logs: View infrastructure service logs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 08:32:30 -08:00
hailin 3dc0fb15d8 feat(blockchain-service): add Prisma migration for init schema
- Create migration 20241207000000_init with all 5 tables
- Tables: monitored_addresses, deposit_transactions, block_checkpoints, transaction_requests, blockchain_events
- Mark migration as applied to existing database

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 08:23:14 -08:00
hailin 0c00382a98 fix: convert deploy.sh CRLF to LF and add executable permission
- Convert Windows CRLF line endings to Unix LF for all deploy.sh files
- Add executable permission to all deploy.sh scripts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 07:01:13 -08:00
hailin e76adcbe8d . 2025-12-07 14:56:13 +00:00
hailin b25a893d37 docs(config): update .env.example files for production deployment
- Update all .env.example files with production topology documentation
- Add network configuration for Server A (119.145.15.38/192.168.1.100) and Server B (192.168.1.111)
- Document service ports and connection URLs for all microservices
- Add architecture diagrams in comments for easy reference
- Include security notes and key generation commands

Files updated:
- backend/services/.env.example (main config)
- backend/services/identity-service/.env.example
- backend/services/mpc-service/.env.example
- backend/services/blockchain-service/.env.example
- backend/mpc-system/.env.example
- backend/api-gateway/.env.example
- backend/infrastructure/.env.example

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 04:55:21 -08:00
hailin ab8852907d fix(mpc-service): increase Kafka consumer session timeout
- Increase sessionTimeout from 30s to 5 minutes
- Increase heartbeatInterval from 3s to 10s
- Add rebalanceTimeout of 5 minutes
- This prevents consumer from being kicked out during long MPC keygen operations

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 03:58:40 -08:00
hailin 493a76117a fix(identity-service): ensure BlockchainWalletHandler is initialized
- Add BlockchainEventConsumerService to InfrastructureModule
- Add BlockchainWalletHandler and MpcKeygenCompletedHandler to ApplicationModule
- Inject event handlers into UserApplicationService to force NestJS initialization
- This ensures onModuleInit is called for event handlers, enabling Kafka event consumption

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 03:46:55 -08:00
hailin 106137224a fix(identity-service): add BlockchainEventConsumerService to InfrastructureModule
The consumer was not being initialized because it was not registered in the module.
2025-12-07 03:30:26 -08:00
hailin bad6ba2232 fix(mpc-service): use @unique on username field for Prisma upsert compatibility 2025-12-07 02:19:17 -08:00
hailin 84e653d284 fix(mpc-service): add /api/v1 prefix to blockchain-service calls
blockchain-service uses global API prefix, need to include it in URLs.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 02:11:57 -08:00
hailin 845dd857b0 fix(mpc-service): add BLOCKCHAIN_SERVICE_URL config
Configure correct blockchain-service URL (port 3012) for address derivation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 02:08:43 -08:00
hailin 3925b19229 fix(mpc-service): use JWT auth instead of X-API-Key
mpc-account-service expects JWT Bearer tokens, not X-API-Key header.
Added JWT token generation and use MPC_JWT_SECRET env var.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 02:02:17 -08:00
hailin 7588c9efb7 fix(mpc-service): use explicit container names for rwa services
When mpc-service joins mpc-system network, 'postgres' resolves to mpc-postgres.
Use explicit names (rwa-postgres, rwa-redis, rwa-kafka) to avoid conflicts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 01:55:52 -08:00
hailin 63e543933f fix(mpc-service): connect to mpc-system network
- Changed MPC URLs from 192.168.1.111 to Docker internal names
- Added mpc-system_mpc-network to mpc-service for cross-network communication

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 01:52:25 -08:00
hailin 2ae174692e fix(mpc-service): use correct env var name MPC_ACCOUNT_SERVICE_URL
Changed from MPC_SYSTEM_URL to MPC_ACCOUNT_SERVICE_URL to match docker-compose config.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 01:48:02 -08:00
hailin 3332124250 fix(identity-service): change dynamic import to static import
Dynamic imports with path aliases (@/domain/events) don't work at runtime.
Changed to static import to fix module resolution error.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 01:40:46 -08:00
hailin 742cc21395 fix(identity-service): extend avatar_url column to 2000 chars
SVG avatars can be up to 745+ characters, exceeding the previous 500 char limit.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 01:31:44 -08:00
hailin 34fc008f9d fix(blockchain-service): add global API prefix and increase healthcheck start_period
- Add app.setGlobalPrefix('api/v1') to main.ts so health endpoint
  is at /api/v1/health consistent with other services
- Increase healthcheck start_period to 60s to allow time for
  Prisma migrations on first startup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 01:20:35 -08:00
hailin be6abd3034 fix(blockchain-service): standardize Dockerfile with other services
- Use node:20-slim instead of alpine for OpenSSL compatibility
- Add startup script with prisma migrate/push
- Increase healthcheck start-period to 60s
- Add non-root user for security

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 01:17:55 -08:00
hailin 1125dd98ef fix(blockchain-service): auto-create database and run migrations on startup
- Add rwa_blockchain to init-databases.sh script
- Change Dockerfile CMD to run prisma db push before starting app

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 01:14:50 -08:00
hailin e20e3cb7af fix(blockchain-service): add openssl and curl for Prisma and healthcheck 2025-12-07 01:09:25 -08:00
hailin 9eb2d5a206 fix(blockchain-service): import DomainModule for ConfirmationPolicyService 2025-12-07 01:06:45 -08:00
hailin 3af4234c89 feat: add blockchain-service to root docker-compose.yml 2025-12-07 00:58:23 -08:00
hailin dba9d16074 . 2025-12-07 00:40:19 -08:00
hailin 6451cd6fc3 refactor: unify docker-compose configs to use shared infrastructure
All microservices now use the shared rwa-network and connect to:
- rwa-postgres: Shared PostgreSQL database server
- rwa-redis: Shared Redis cache
- rwa-kafka: Shared Kafka message broker

Each service's docker-compose.yml now only defines the application
container and uses `networks: external: true` to connect to the
shared infrastructure defined in the root docker-compose.yml.

This prevents duplicate infrastructure containers and ensures all
services can communicate via Kafka and share the same Redis/PostgreSQL.

Services updated:
- admin-service
- backup-service
- blockchain-service
- identity-service
- leaderboard-service
- mpc-service
- presence-service

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 00:35:56 -08:00
hailin ce281b0657 fix(blockchain-service): install @scure/bip39 dependency
Add @scure/bip39 package for mnemonic-based address derivation.
Package.json already had the dependency listed but node_modules was missing it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 00:25:27 -08:00
hailin bbd8a701a8 fix(blockchain-service): add @scure/bip39 dependency 2025-12-07 00:20:49 -08:00
hailin fcb949c799 fix(identity-service): remove WalletGeneratorService from app.module.ts 2025-12-07 00:15:08 -08:00
hailin 852073ae11 refactor: move mnemonic verification from identity-service to blockchain-service
- Add /internal/verify-mnemonic API to blockchain-service
- Add /internal/derive-from-mnemonic API to blockchain-service
- Create MnemonicDerivationAdapter for BIP39 mnemonic address derivation
- Create BlockchainClientService in identity-service to call blockchain-service
- Remove WalletGeneratorService from identity-service
- Update recover-by-mnemonic handler to use blockchain-service API

This enforces proper domain boundaries - all blockchain/crypto operations
are now handled by blockchain-service.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 00:11:06 -08:00
hailin a181fd0d2d fix(mpc-service): change healthcheck from wget to curl
Docker compose healthcheck was using wget which is not installed in the
node:20-slim image. Changed to use curl and corrected endpoint path.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 23:42:48 -08:00
hailin 5e93bbac33 fix(mpc-service): convert docker-entrypoint.sh line endings from CRLF to LF 2025-12-06 23:34:40 -08:00
hailin 54b9a66041 fix(backup-service): convert deploy.sh line endings from CRLF to LF 2025-12-06 23:29:58 -08:00
hailin 0ab1bf0dcc feat(mpc-service): add blockchain-service client for address derivation
- Add BlockchainClientService to call blockchain-service /internal/derive-address
- Call derive addresses after keygen completes with MPC public key
- Include derived addresses (BSC, KAVA, DST) in keygen completed event

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 23:27:30 -08:00
hailin cf308efecf refactor(identity-service): remove deposit/blockchain code, belongs to wallet-service
- Remove DepositController, DepositService, BlockchainQueryService
- Deposit address and balance queries should be in wallet-service
- identity-service now only handles user identity

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 23:22:06 -08:00
hailin 9ae26d0f1f refactor(identity-service): replace direct RPC with blockchain-service API calls
- Remove ethers.js direct RPC connection to blockchain
- Add HTTP client to call blockchain-service /balance API
- Add ConfigService for BLOCKCHAIN_SERVICE_URL configuration
- Enforce proper microservice boundaries

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 23:07:46 -08:00
hailin 383a9540a0 refactor: move backup-service client from identity-service to mpc-service
Architecture change: delegate share storage is now handled by mpc-service.
- identity-service no longer calls backup-service directly
- mpc-service calls backup-service after keygen completion
- This follows proper domain boundaries (MPC domain handles share storage)

Flow:
1. identity-service publishes mpc.KeygenRequested
2. mpc-service calls mpc-system for keygen
3. mpc-service stores delegate share to backup-service
4. mpc-service publishes mpc.KeygenCompleted
5. identity-service updates user wallet address

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 22:56:35 -08:00
hailin f4f0466616 fix(mpc-service): convert deploy.sh line endings from CRLF to LF
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 22:45:35 -08:00
hailin 32c806b90c fix(identity-service): add MpcEventConsumerService to app.module.ts
The InfrastructureModule was defined inline in app.module.ts, not using
the separate infrastructure.module.ts file. Added MpcEventConsumerService
to the inline module definition.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 22:36:01 -08:00
hailin 417f580df8 fix(identity-service): add MpcEventConsumerService to InfrastructureModule
Add missing MpcEventConsumerService provider to fix NestJS dependency injection error.
MpcClientService requires MpcEventConsumerService but it was not registered in the module.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 22:15:35 -08:00
hailin 10e4fa4a5f fix(identity-service): convert deploy.sh line endings from CRLF to LF
Fix bash interpreter error caused by Windows-style CRLF line endings

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 22:03:46 -08:00
hailin 39804aa981 fix(mobile-app): update share link domain to rwaapi.szaiai.com
Changed invite share URLs from rwa-durian.app to rwaapi.szaiai.com

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 21:15:55 -08:00
hailin 2e815cec6e feat: move address derivation from identity-service to blockchain-service
- Add Cosmos address derivation (bech32) to blockchain-service
  - KAVA: kava1... format
  - DST: dst1... format
  - BSC: 0x... EVM format

- Create MpcEventConsumerService in blockchain-service to consume mpc.KeygenCompleted events

- Create BlockchainEventConsumerService in identity-service to consume blockchain.WalletAddressCreated events

- Simplify identity-service MpcKeygenCompletedHandler to only manage status updates

- Add CosmosAddress value object for Cosmos chain addresses

Event flow:
1. identity-service -> mpc.KeygenRequested
2. mpc-service -> mpc.KeygenCompleted (with publicKey)
3. blockchain-service consumes mpc.KeygenCompleted, derives addresses
4. blockchain-service -> blockchain.WalletAddressCreated (with all chain addresses)
5. identity-service consumes blockchain.WalletAddressCreated, saves to user account

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 21:08:21 -08:00
hailin 50388c1115 feat(blockchain-service): implement complete blockchain service with DDD + Hexagonal architecture
- Domain layer: ChainType, EvmAddress, TxHash, TokenAmount, BlockNumber value objects
- Domain events: DepositDetected, DepositConfirmed, WalletAddressCreated, TransactionBroadcasted
- Aggregates: DepositTransaction, MonitoredAddress, TransactionRequest
- Infrastructure: Prisma ORM, Redis cache, Kafka messaging, EVM blockchain adapters
- Application services: AddressDerivation, DepositDetection, BalanceQuery
- API: Health, Balance, Internal controllers with Swagger documentation
- Deployment: Docker, docker-compose, deploy.sh, health-check scripts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 20:54:58 -08:00
hailin 6150617c14 docs: update blockchain-service guide with address derivation responsibilities
- Add public key → address derivation as primary responsibility
- Add AddressDerivationAdapter for EVM/Cosmos address derivation
- Add WalletAddressCreated event definition
- Add MPC event consumption (mpc.KeygenCompleted)
- Add MpcKeygenCompletedHandler for processing keygen events
- Add section 17: MPC integration event flow with diagrams
- Update document version to 1.2.0

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 20:02:50 -08:00
hailin 23043d5d79 feat: add detailed debug logging for MPC Kafka event flow
- Add comprehensive [INIT], [CONNECT], [PUBLISH], [RECEIVE], [HANDLE] logs
  to identity-service and mpc-service Kafka services
- Add KeygenStarted event for tracking keygen progress
- Add MpcKeygenCompletedHandler to process keygen completion events
- Fix topic routing for MPC events between services

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 19:49:06 -08:00
hailin 289691dc3c fix: align mpc-service migration with schema and fix identity-service compile errors
- Update mpc-service migration to match new gateway mode schema (mpc_wallets, mpc_shares)
- Remove old MySQL migrations (party_shares, session_states, share_backups)
- Fix MpcSignature type to use string format (64 bytes hex: R + S)
- Add persistence layer conversion functions for DB compatibility
- Fix method names in domain services (checkDeviceNotRegistered, generateNextUserSequence)
- Update wallet generator interface to use delegateShare instead of clientShareData

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 18:42:48 -08:00
hailin ba91a89b16 feat(wallet-service): add Redis caching for wallet queries
- Add ioredis dependency for Redis connectivity
- Create Redis service and module with DB 1 configuration
- Implement WalletCacheService for wallet data caching (60s TTL)
- Integrate cache-aside pattern in getMyWallet query
- Add cache invalidation on all wallet mutations:
  - handleDeposit, deductForPlanting, addRewards
  - claimRewards, settleRewards

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 18:37:13 -08:00
hailin c459387c42 feat: add event-driven communication between identity-service and mpc-service
Replace synchronous HTTP polling with Kafka event-driven model for MPC operations:

- Add MPC event consumer service in mpc-service for keygen/signing requests
- Add keygen-requested and signing-requested event handlers
- Add MPC event consumer in identity-service for completion events
- Extend mpc-client.service with async event-driven methods
- Support backward compatibility via MPC_USE_EVENT_DRIVEN env var

Topics: mpc.KeygenRequested, mpc.SigningRequested, mpc.KeygenCompleted,
        mpc.SigningCompleted, mpc.SessionFailed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 18:17:44 -08:00
hailin 17fd663fe3 refactor: improve auto-create API semantics and use real device ID
Frontend (account_service.dart):
- Use Android ID instead of random UUID for deviceId
- Add DeviceHardwareInfo class with full hardware details
- Remove provinceCode/cityCode from CreateAccountRequest
- Simplify to: deviceId (required), deviceName (optional JSON), inviterReferralCode (optional)

Backend (identity-service):
- Rename validateDeviceId() to checkDeviceNotRegistered() for clarity
- Rename generateNext() to generateNextUserSequence() for semantics
- Update error message: "该设备已创建过账户"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 18:05:11 -08:00
hailin bc82f58549 feat: add infrastructure components for observability and service discovery
Add modular infrastructure stack with:
- Consul: service discovery and configuration center
- Jaeger: distributed tracing
- Loki + Promtail: log aggregation
- Prometheus: metrics collection with alert rules
- Grafana: unified visualization dashboard

All components are optional and can be enabled on-demand using Docker profiles.
No changes required to existing microservices.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 17:51:29 -08:00
hailin 9c36e6772b refactor: simplify mpc-service to gateway mode
mpc-service 重新定位为网关服务,转发请求到 mpc-system:
- 简化 Prisma schema:只保留 MpcWallet 和 MpcShare
- 添加 delegate share 存储(keygen 后保存用户的 share)
- 保留六边形架构结构,清理不再需要的实现
- 删除旧的 command handlers、queries、repository 实现
- 简化 infrastructure module,只保留 PrismaService

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 17:16:14 -08:00
hailin d652f1d7a4 feat: add MPC coordinator service and keygen/signing API
- Add MPCController with keygen and sign endpoints
- Add MPCCoordinatorService to coordinate with mpc-system
- Add MpcWallet, MpcShare, MpcSession entities for data storage
- Update identity-service mpc-client to call mpc-service

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 16:03:17 -08:00
hailin 9fc41cfa53 fix: add keygen index to sorted index mapping for signing session
When signing with a subset of parties (e.g., party-1 and party-3 in 2-of-3),
the TSS library creates a sorted array of party IDs. Messages contain the
original keygen party index, but we need to map it to the sorted array index.

This fixes the 'invalid FromPartyIndex' error when signing with non-consecutive
party indices.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 11:04:19 -08:00
hailin f769c7eebf test: update signing test username 2025-12-06 10:54:22 -08:00
hailin ac4d9283dc fix: preserve original PartyIndex from keygen for signing sessions
- Add PartyIndex field to protobuf ParticipantInfo message
- Pass original PartyIndex from account shares to session coordinator
- Use original PartyIndex instead of loop variable when creating participants
- This fixes TSS signing failures when non-consecutive parties are selected
2025-12-06 10:45:05 -08:00
hailin 1d507a7afd test: update signing test to use wallet with configured parties 2025-12-06 10:34:14 -08:00
hailin 8dd1c50eb9 fix: update test username for signing parties API test 2025-12-06 10:29:30 -08:00
hailin 1044cfe635 fix: correct signing parties count validation to T+1 (required signers for TSS) 2025-12-06 10:20:21 -08:00
hailin 47a98da4e4 test: add signing parties API test script 2025-12-06 10:18:19 -08:00
hailin 93eab1931e test: update wallet username
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 10:08:17 -08:00
hailin dbe630dbd6 fix: add wait time before TSS protocol to prevent race condition
Wait 500ms after subscribing to messages to ensure all parties have
completed subscription before starting TSS protocol. This prevents
broadcast messages from being lost when some parties haven't subscribed yet.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 10:04:10 -08:00
hailin 0e8dff0371 test: update wallet username for signing test
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 10:01:56 -08:00
hailin 98731cc133 debug: add more logging to message broker for broadcast diagnostics
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 09:57:34 -08:00
hailin c257ad1639 test: update test_signing.go with new wallet username
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 09:52:58 -08:00
hailin 378970048b debug: add TSS signing debug logs to diagnose stuck issue
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 09:41:31 -08:00
hailin f70ece0d4f test: update test_signing.go to use current wallet username
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 09:33:58 -08:00
hailin fd74bc825a chore: add detailed logging for keygen_session_id tracing
Add logging at key points to trace keygen_session_id flow:
- Account Handler: log keygen_session_id when creating signing session
- Session Coordinator: log keygen_session_id in CreateSession and JoinSession
- Message Router: log keygen_session_id when proxying JoinSession
- Server Party: log keygen_session_id when joining session

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 09:21:19 -08:00
hailin a1b2b760ab feat(migration): add keygen_session_id column to mpc_sessions table
For sign sessions, this column stores the reference to the keygen session
whose key shares should be used for signing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 09:16:31 -08:00
hailin 3d176e1132 feat: complete keygen_session_id implementation for signing sessions
- Regenerate protobuf Go code with KeygenSessionId fields
- Session Coordinator correctly parses, stores, and returns keygen_session_id
- Message Router Client parses keygen_session_id in JoinSession response
- participate_signing.go uses keygen_session_id for precise share lookup
- Database schema already includes keygen_session_id column

This fixes the signing issue where wrong keyshares were loaded for multi-account scenarios.
2025-12-06 08:57:30 -08:00
hailin 23eff00d76 feat: add KeygenSessionID to MPCSession entity
- Add KeygenSessionID field to MPCSession struct for tracking which keygen's shares to use
- This is the first step in完整的修复流程
2025-12-06 08:40:38 -08:00
hailin 382386733d feat: add keygen_session_id to signing session flow
- Add keygen_session_id field to CreateSessionRequest and SessionInfo protobuf
- Modify CreateSigningSessionAuto to accept and pass keygenSessionID
- Update Account Handler to pass account's keygen_session_id when creating signing session
- This enables parties to load the correct keyshare by session ID
2025-12-06 08:39:40 -08:00
hailin 7660868a38 fix(account): select t+1 parties for threshold signing
TSS threshold semantics: for threshold parameter t, the required number of signers is t+1.
For 2-of-3 with t=2, we need 2+1=3 signers (all parties must participate).

Previous error: 't+1=3 is not satisfied by the key count of 2'
Fix: Changed from selecting t parties to selecting t+1 parties.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 07:46:32 -08:00
hailin 0ea64e02ae fix(account): use only threshold_t parties for signing instead of all active parties
For 2-of-3 threshold signing, only 2 parties should participate in signing, not all 3. This fixes the 'failed to calculate Bob_mid' error that occurred when all parties tried to sign.

Changes:
- Modified CreateSigningSession to select exactly threshold_t parties when no signing config exists
- For 2-of-3: now selects 2 parties instead of all 3
- Added logging to show party selection details

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 07:35:03 -08:00
hailin 672b6e1630 feat(schema): make email field optional in accounts table
Only username is required, all other fields (email, phone, public_key, etc.) are now optional.

Changes:
- Modified 001_init_schema.up.sql to remove NOT NULL constraints
- Added partial unique index for email (only for non-NULL values)
- Created migration 006_make_email_optional for existing databases
- Set default status to 'active'

This allows automatic account creation from keygen without requiring user info.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 07:16:34 -08:00
hailin eb63b9341b fix(tss): correct threshold signing to support t-of-n properly
Previously, signing incorrectly required all n parties from keygen to participate. For 2-of-3 threshold, it required all 3 parties instead of just 2.

Root cause: tss.NewParameters was using len(currentSigners) instead of the original n from keygen.

Changes:
- Added TotalParties field to SigningConfig to store original n from keygen
- Modified participate_signing.go to read threshold_n from database
- Updated tss.NewParameters to use TotalParties instead of current signer count
- Added logging to show t, n, and current_signers

For 2-of-3: threshold_t=2, threshold_n=3, any 2 parties can now sign.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 07:16:24 -08:00
hailin 6fdd2905b1 test(signing): add signing session test script
Created test_signing.go to test MPC signing functionality:
- Generates JWT token for authentication
- Creates SHA-256 hash of test message
- Calls POST /api/v1/mpc/sign API
- Tests signing with persistent parties (non-delegate mode)

Usage: go run test_signing.go

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 06:58:54 -08:00
hailin e786219f37 debug(keygen): add detailed logging for message flow tracking
Added comprehensive debug logging to track message conversion and
party index mapping in keygen protocol:

1. Log party index map construction with all participants
2. Log received MPC messages before conversion
3. Log when messages are dropped due to unknown sender
4. Log successful message conversion and TSS forwarding
5. Show known_parties map when dropping messages

This will help identify why delegate party receives messages but
doesn't process them during keygen.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 06:45:23 -08:00
hailin 5344af465b fix(server-party): fix context leak in GetPendingMessages acknowledgment
Fixed the acknowledgment goroutine in GetPendingMessages to use parent
context instead of context.Background(), preventing orphan goroutines
that can't be cancelled.

This completes all context bug fixes:
- server-party-api event handler (commit 450163a)
- server-party event handler (commit 99ff3ac)
- message acknowledgment in SubscribeMessages (commit 450163a)
- message acknowledgment in GetPendingMessages (this commit)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 06:42:07 -08:00
hailin 99ff3ac130 fix(server-party): use parent context in event handler for proper cancellation
- Fixed server-party event handler to use parent context with timeout
- Prevents orphan goroutines when session fails or party exits
- Consistent with server-party-api fix
2025-12-06 06:39:23 -08:00
hailin 450163a94d fix(context): use parent context instead of Background() to allow proper cancellation
- Fixed delegate party event handler to use parent context with timeout
- Fixed message acknowledgment to use parent context
- Prevents orphan goroutines when session fails or party exits
- Resolves system crash after delegate party failure
2025-12-06 06:36:34 -08:00
hailin 3adc091140 fix(docker): add PARTY_ROLE environment variable for server-party-api
Add PARTY_ROLE=delegate environment variable to server-party-api service
to fix nil pointer dereference when determining party role during keygen.

Without this variable, the party defaults to "persistent" role which tries
to access keyShareRepo (nil for delegate parties), causing a panic.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 06:00:28 -08:00
hailin 13e81e37c9 fix(db): update repository to save and load delegate_party_id field
Update session repository to properly handle delegate_party_id column:
- Add delegate_party_id to Save method INSERT and UPDATE statements
- Add DelegatePartyID field to sessionRow struct
- Update FindByUUID, FindByStatus, FindExpired, FindActive SELECT queries
- Update scanSessions method to scan and pass delegate_party_id
- Remove placeholder empty string, now loads actual value from database

This completes the delegate party functionality by ensuring the delegate party ID
is persisted and retrieved correctly from the database.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 05:52:34 -08:00
hailin 391448063f feat(db): add delegate_party_id column to mpc_sessions table
Add delegate_party_id column to track which party is acting as delegate
(generates and returns user share instead of storing it).

Changes:
- Add delegate_party_id VARCHAR(255) column with default empty string
- Add partial index for faster lookups when delegate party is present
- Include up and down migrations

This fixes the issue where delegate party selection worked but the delegate_party
field was not being returned in API responses due to missing database column.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 05:50:01 -08:00
hailin 36e1359f43 fix(session-coordinator): pass PartyComposition from gRPC request to use case
Fixed critical bug where PartyComposition (persistent/delegate party counts) was being sent
by account-service in gRPC request but was not being extracted and passed to the CreateSession
use case, causing delegate party selection to fail.

Changes:
- Extract PartyComposition from protobuf request and pass to CreateSessionInput
- Add logging for party composition values in gRPC handler
- Return delegate_party_id and selected_parties in CreateSessionResponse
- Load session after creation to get delegate party ID

This fixes the issue where require_delegate=true had no effect and all parties selected
were persistent parties instead of 2 persistent + 1 delegate.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 05:38:38 -08:00
hailin c5d3840835 fix(docker-compose): add ACCOUNT_SERVICE_ADDR to session-coordinator
- Add ACCOUNT_SERVICE_ADDR environment variable pointing to account-service:8080
- Fixes "connection refused" error when session-coordinator tries to auto-create account after keygen
- Session-coordinator can now properly call account service to create account records

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 05:21:06 -08:00
hailin b8d66921e0 feat(docker-compose): add PARTY_ID to server-party-api configuration
- Add explicit PARTY_ID environment variable for delegate party
- Set PARTY_ID=delegate-party for server-party-api service
- This ensures the delegate party properly registers to Message Router party pool
- Enables delegate party selection for keygen sessions with require_delegate=true

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 05:17:03 -08:00
hailin 5f12404be4 fix: remove dynamic participant join to fix concurrent party_index assignment
- Remove dynamic participant addition in JoinSession
- Participants must be pre-created in CreateSession
- Add ErrPartyNotInvited error for unauthorized join attempts
- Fix Redis adapter to include version parameter in ReconstructSession
- This fixes VSS verification failures caused by inconsistent party indices
2025-12-06 04:54:40 -08:00
hailin b72268c1ce feat(mpc-system): implement optimistic locking for session updates
Implement version-based optimistic locking to prevent concurrent update conflicts
when multiple parties simultaneously report completion during keygen operations.

Changes:
- Add version column to mpc_sessions table (migration 004)
- Add Version field to MPCSession entity
- Define ErrOptimisticLockConflict error
- Update SessionPostgresRepo.Update() to check version and increment on success
- Add automatic retry logic (max 3 attempts) to ReportCompletionUseCase
- Update Save and all query methods (FindByStatus, FindExpired, etc.) to handle version field

This replaces pessimistic locking (FOR UPDATE) with optimistic locking using
the industry-standard pattern: WHERE version = $n and checking rowsAffected.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 04:16:32 -08:00
hailin 63e00a64f5 fix(test): update JWT secret to match .env configuration
Fixed JWT secret in test_create_session.go to use the same secret key
as configured in .env file, resolving 401 Unauthorized errors during
keygen session creation tests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 03:54:12 -08:00
hailin 77fa40d27f test(logger): set Development=true to test if it affects debug logging
Changed Development from false to true to test if this is preventing
debug logs from being output. Development mode may affect how the
logger handles different log levels.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 03:41:50 -08:00
hailin 47dd2d1cb5 test(logger): add internal debug test immediately after Build()
Added Log.Debug() and Log.Info() calls immediately after Build()
to test if the logger can output debug logs right after creation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 03:41:00 -08:00
hailin 3a247562ea debug(logger): add AtomicLevel tracking to diagnose level changes
Added debug output to track:
1. AtomicLevel value when created
2. AtomicLevel value after Build()
3. Log.Level() value after Build()

This will help identify if Build() or something else is changing the level.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 03:32:45 -08:00
hailin bfe129da51 test(logger): add debug log test to verify debug level works
Added test debug log immediately after logger initialization.
If debug logging is working, we should see this message.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 03:23:24 -08:00
hailin bac623f63c debug(logger): add detailed debug output for level initialization
Added println statements to trace:
1. Level value after UnmarshalText
2. Logger level after Build()

This will help diagnose why debug level is not being applied.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 03:16:05 -08:00
hailin ac1858a19e fix(logger): remove init() function that was overriding config level
Problem: Logger was always using info level despite MPC_LOGGER_LEVEL=debug
Root cause: The init() function in logger.go was calling InitProduction()
which created a zap.NewProduction() logger with hardcoded info level.
This happened before main() called logger.Init(cfg), so the config was
being ignored.

Solution:
1. Removed init() function to prevent early logger initialization
2. Added zap.ReplaceGlobals() in Init() to ensure config takes effect
3. Removed unused "os" import

References:
- https://pkg.go.dev/go.uber.org/zap
- https://stackoverflow.com/questions/57745017/

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 03:07:30 -08:00
hailin 32e3970f34 debug: add logger level debug output 2025-12-06 02:56:26 -08:00
hailin 5764f3d50d chore: set logger level to debug for debugging 2025-12-06 02:42:04 -08:00
hailin e321501c32 chore: set default environment to development for debug logging 2025-12-06 02:37:36 -08:00
hailin 6df7355abe fix: add username field to keygen request 2025-12-06 02:35:03 -08:00
hailin ac64c2d012 fix: add Authorization header to test_create_session.go 2025-12-06 02:33:59 -08:00
hailin fb9c85f883 debug(coordinator): add detailed logging to track concurrent update issue
Add comprehensive debug logs to:
1. report_completion.go - log all participant statuses at key points
2. session_postgres_repo.go - log before/after each participant update

This will help identify why server-party-1 status remains 'invited'
despite successfully reporting completion.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 02:11:28 -08:00
hailin 380bf46fb6 fix(coordinator): add row-level locking to prevent concurrent update conflicts
Problem:
Multiple parties reporting completion simultaneously caused lost updates
because each transaction would read the full session, modify their
participant status, then update ALL participants - causing last-write-wins
behavior.

Solution:
Add SELECT ... FOR UPDATE locks on both mpc_sessions and participants
tables at the start of the Update transaction. This serializes concurrent
updates and prevents lost updates.

Lock order:
1. Lock session row (FOR UPDATE)
2. Lock all participant rows for this session (FOR UPDATE)
3. Perform updates
4. Commit (releases locks)

This ensures that concurrent ReportCompletion calls are fully serialized
and each participant status update is preserved.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 01:58:05 -08:00
hailin aab88834f9 fix(coordinator): prevent lost updates in concurrent participant status changes
Fix critical concurrency bug where simultaneous ReportCompletion calls from
multiple parties could cause lost database updates. Changed from UPSERT-all
to UPDATE-individual pattern to ensure each participant status update is
atomic and won't be overwritten by concurrent transactions.

Before: All participants were UPSERTed in single transaction, causing
last-commit-wins behavior that lost earlier status updates.

After: Each participant is UPDATEd individually using UPDATE...WHERE, then
INSERT only if row doesn't exist. This prevents concurrent updates to
different participants from conflicting.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 01:35:38 -08:00
hailin 00b48bab50 fix(coordinator): handle all participant states in ReportCompletion with proper state transitions
- Add switch-case to handle Invited, Joined, and Ready states
- Auto-transition Invited -> Joined -> Ready -> Completed
- Auto-transition Joined -> Ready -> Completed
- Auto-transition Ready -> Completed
- Return error for invalid states (Failed, Completed, etc.)
- Fixes 'cannot transition to completed status' error
- Applies to all parties including server-party-api
2025-12-06 01:09:49 -08:00
hailin 4e14212147 fix(coordinator): auto-transition participant to Ready before Completed
ReportCompletion was failing with "cannot transition to completed status"
because participants were in Joined state trying to transition directly to
Completed, which violates the state machine flow: Joined -> Ready -> Completed.

Changes:
- Check participant status before marking as Completed
- Auto-transition Joined -> Ready if needed
- Then transition Ready -> Completed
- Add debug logging for auto-transition

This fixes the error seen during keygen completion.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 00:33:22 -08:00
hailin 8e683064ed chore: regenerate coordinator proto with party_index field
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 00:11:24 -08:00