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>
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>
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>
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>
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>
- 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>
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>
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>
## 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>
- 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>
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>
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>
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>
- 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>
- 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>
- 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>
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>
- 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>
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>
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>
- 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>
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>
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>
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>
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>
- 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>
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>
- 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>
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>
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>
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>
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>
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>
- 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>
- 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>
- 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>
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>
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>
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>
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>
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>
- 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>
- 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>
- 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>
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>
## 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>
## 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>
- 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>
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>
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>
- 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>
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>
- 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>
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>
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>
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>
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>
- 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>
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>
- 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>
- 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>
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>
- 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>
- 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>
- 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>
- 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>
- 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>
- 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>
- 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>
- 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>
- 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>
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>
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>
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>
- 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>
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>
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>
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>
- 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>
- 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>
- 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>
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>
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>
- 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>
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>
- 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>
- 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>
- 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>
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>
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>
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>
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>
- 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>
- 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>
- 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>
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>
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>
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>
- 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>
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>
- 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
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>
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>
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>
- 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.
- 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
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>
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>
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>
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>
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>
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>
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>
- 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
- 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
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>
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>
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>
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>
- 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>
- 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>
- 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
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
- 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
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>