Effective contribution should equal theoretical total (totalTrees * 22617)
since it includes all parts: personal 70% + operation 12% + province 1% +
city 2% + level 7.5% + bonus 7.5% = 100%.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add totalTrees field from syncedAdoption aggregate
- Rename fields: networkLevelPending, networkBonusPending
- Stats card: show level pending and bonus pending separately
- Add new stats card for total trees count
- Price overview: 2-row layout showing all contribution metrics
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add networkPendingContribution and networkBonusPendingContribution to API
- Display combined pending contribution (teamLevel + teamBonus) in stats card
- Replace 'total contribution' with 'pending contribution' in price overview
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add networkTotalContribution field to dashboard API response
- Display total hashrate alongside effective hashrate in stats cards
- Update price overview to show both effective and total contribution
- Change grid from 3 to 4 columns in price overview
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add handler for CONTRIBUTION_CREDITED events from mining-wallet-service
to sync user wallet data to synced_user_wallets table.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Return usdtAvailable, usdtFrozen, pendingUsdt, settleableUsdt,
settledTotalUsdt, expiredTotalUsdt instead of old field names
- Query SyncedUserWallet table for GREEN_POINTS wallet data
- Use miningAccount.availableBalance for pendingUsdt
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update getUserMiningRecords to call mining-service API instead of
returning empty records. This enables the admin dashboard to display
actual user mining records.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
NestJS matches routes in definition order. The :category/:key route was
matching mining/status before the specific mining routes. Moved mining
routes before the parameter routes to fix routing.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add debug logging to trace mining service calls
- Return error object instead of null when data is missing
- Include error message in response for debugging
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add GET and POST /configs/transfer-enabled endpoints to control
the transfer switch. Routes are placed before :category/:key to
avoid being matched as path parameters.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Frontend expects flat DashboardStats and RealtimeData interfaces.
Transform backend nested response to:
- totalUsers, adoptedUsers, networkEffectiveContribution, etc.
- currentMinuteDistribution, activeOrders, pendingTrades, etc.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
System initialization is now handled by seed scripts and CDC sync,
so the manual initialization UI is no longer needed.
Removed:
- Frontend: initialization page and sidebar menu item
- Backend: InitializationController and InitializationService
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change controller path from /audit-logs to /audit to match frontend
- Transform response to frontend expected format (items, totalPages, etc.)
- Map admin.username to adminUsername field
- Add keyword query parameter support
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add ReportsController with /reports/daily endpoint that maps the
dashboard service data to the format expected by the frontend.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change SystemAccountsService to read from syncedWalletSystemAccount and
syncedWalletPoolAccount tables instead of local tables. This fixes the
issue where the frontend shows "暂无数据" despite data being synced.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Revert the previous change that removed the status filter. The stats
should only count adoptions with MINING_ENABLED status, as only those
are active for mining. The issue is likely that the status field in
synced_adoptions table doesn't have the correct value.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The adoption stats were showing 0 because the synced_adoptions table
contains status values directly from 1.0 system (PAID, POOL_INJECTED, etc.)
rather than MINING_ENABLED. Since contribution-service doesn't update the
status after calculating contributions, we now count all synced adoptions.
Changes:
- Remove status filter in getAdoptionStatsForUsers
- Remove status filter in getUserDetail adoption queries
- Remove status filter in getUserAdoptionStats for referral tree
- Add order count display in user detail page
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Backend:
- Add personalOrders and teamOrders to adoption stats
- Return order count alongside tree count in user list API
Frontend:
- Add personalAdoptionOrders and teamAdoptionOrders to UserOverview type
- Display format: "树数量(订单数)" e.g. "6(3单)"
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Only count adoptions with status='MINING_ENABLED' when calculating:
- Personal adoption count (user list)
- Team adoption count (user list)
- Personal adoption stats (user detail)
- Direct referral adoptions (user detail)
- Team adoptions (user detail)
- Referral tree adoption stats
This fixes incorrect adoption counts that included pending/unconfirmed orders.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The outbox_events table uses outbox_id as the primary key column name
(mapped from id in Prisma). When Debezium captures changes, the message
contains outbox_id field, not id. This caused all events to have
undefined eventId, resulting in duplicate detection treating all events
as duplicates after the first one.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add comments explaining unique key composition:
- CDC events: (source_topic, offset) = Kafka topic + message offset
- Outbox events: (source_service, event_id) = service name + outbox ID
- Fix contribution-service migration:
- Extend source_service column from VARCHAR(50) to VARCHAR(100)
- Set source_service as NOT NULL to match schema
- Use snake_case for index name consistency
- Clarify that offset/event_id are NOT database auto-increment IDs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use Prisma $transaction with Serializable isolation level
- Insert idempotency record FIRST, then execute business logic
- Unique constraint violation (P2002) indicates duplicate event
- All operations atomic - either fully commit or fully rollback
- Modified all handlers to accept transaction client parameter
- Removed old non-atomic isEventProcessed/recordProcessedEvent methods
This ensures 100% data consistency for CDC synchronization, which is
critical for financial data where any error is catastrophic.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use (sourceTopic, eventId) as composite unique key in processed_events
- Add sourceTopic to ServiceEvent for globally unique idempotency key
- Wrap all handlers with withIdempotency() for duplicate event detection
- Fix ID collision issue between different service outbox tables
This implements the industry-standard CDC exactly-once semantics pattern.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Delete incorrect TEAM_BONUS records (where account_sequence !=
source_account_sequence) on each container startup after migrations.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use treeCount * contributionPerTree from adoption record to calculate
the actual distribution amounts (70%, 12%, 1%, 2%, 15%) instead of
deriving from contribution_records table.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
TEAM_BONUS should only be given to the adopter themselves, not to their
uplines. This migration deletes all TEAM_BONUS records where
account_sequence != source_account_sequence.
Also updates contribution_accounts totals in contribution-service.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add distributionSummary Text column to synced_adoptions table for storing
distribution details calculated during contribution calculation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changes:
1. contribution-service:
- Add distributionSummary field to SyncedAdoption schema
- Store distribution summary after contribution calculation
2. mining-admin-service:
- Add distributionSummary field to SyncedAdoption schema
- Calculate actual distribution from contribution_records table
- Return distribution details in planting ledger API
3. mining-admin-web:
- Display distribution details in planting ledger table
- Show: 70%(amount) personal, 12%(amount) operation,
1%(amount) province, 2%(amount) city, 15%(amount) team
- Show team distribution breakdown (distributed vs unallocated)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Switch to Prisma's "prisma" relation mode to handle CDC event ordering issues.
This mode emulates foreign key relations at the Prisma Client layer instead of
creating database-level FK constraints, which is the recommended approach for
CDC scenarios where event arrival order cannot be guaranteed.
Reference: https://www.prisma.io/docs/orm/prisma-schema/data-model/relations/relation-mode
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
CDC events arrive asynchronously and order is not guaranteed.
Child records (referrals, accounts) may arrive before parent (users).
This follows CDC best practices: destination tables should not have FK constraints.
Reference: https://estuary.dev/blog/cdc-done-correctly/
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add synced_contribution_records table for tracking contribution ledger
- Add synced_network_progress table for tracking network-wide stats
- Revert Dockerfile to use prisma migrate deploy
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change Dockerfile to use `prisma db push` instead of `migrate deploy`
- Add publish steps for contribution records and network progress in full-reset
- This ensures new tables are created automatically when schema changes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add isHeartbeatMessage to detect heartbeat messages (only have ts_ms field)
- Skip processing for heartbeat messages to avoid unnecessary warnings
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add isDebeziumOutboxEvent to detect outbox table CDC messages
- Add handleDebeziumOutboxEvent to extract service event from payload.after
- Fix CDC consumer not recognizing events from contribution-service outbox
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix updateContribution to properly update levelXPending and bonusTierXPending fields
- Add NetworkAdoptionProgress and DailyContributionRate tables for tracking contribution coefficient
- Create ContributionRateService for dynamic rate calculation (base 22617, +0.3% per 100 trees after 1000)
- Add ContributionRecordSynced and NetworkProgressUpdated events for CDC sync
- Add admin endpoints for network progress query and contribution records publishing
- Update mining-admin-service to sync contribution records and network progress
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>