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>