Skip to content

Comments

Feature/asset service#201

Open
guymoyo wants to merge 94 commits intoself-servicefrom
feature/asset-service
Open

Feature/asset service#201
guymoyo wants to merge 94 commits intoself-servicefrom
feature/asset-service

Conversation

@guymoyo
Copy link
Collaborator

@guymoyo guymoyo commented Feb 9, 2026

No description provided.

guymoyo and others added 30 commits February 8, 2026 15:07
…frontend

Implements the asset-service (Java/Spring Boot) middleware for tokenized
real-world asset trading, plus the asset-manager-app (React) admin frontend.

Backend: 8 Flyway migrations, 8 JPA entities, 9 REST controllers, Redis
distributed trade locks, market hours enforcement (8AM-8PM WAT), order book
matching, WAP portfolio tracking, OHLC pricing, and Fineract integration
for currency/product/account provisioning.

Frontend: Dashboard, Create Asset wizard (5-step), Asset Details, Order Book
management, Pricing, Inventory, and Market Settings pages.

Includes Docker/K8s manifests, GitOps GL accounts (47,48,65,73,87), payment
types, and comprehensive API documentation for the customer app team.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove multi-level order book in favor of a simpler single-price
execution model. Assets now use one admin-set price with spread
applied for buy (price + spread) and sell (price - spread).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…cash account

- Remove annualYield field (unused in business logic) from entity, DTOs,
  services, frontend forms, and dashboard/detail displays
- Auto-derive treasuryCashAccountId from treasury client's active XAF
  savings account during asset provisioning instead of requiring manual
  selection
- Add V9 migration to drop annual_yield column and make
  treasury_cash_account_id nullable
- Simplify create-asset form by removing cash account dropdown

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…guide

Rewrite BUY example as "buy 10 DTT" for cleaner math, add glossary
explaining Treasury, DTT, Spread, and account structure diagram.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ount

Previously the full amount (cost + fee) was sent to the issuer's treasury,
then a GL journal entry tried to reclassify the fee. Now fees go directly
to a dedicated fee collection account via separate Fineract transfers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The sell response example showed gross amount (24500) instead of net
amount (24378) that the user actually receives after fee deduction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Record price history immediately on set-price (charts update instantly)
- Add POST /api/admin/assets/{id}/mint to increase total supply
- Improve error message when company has no active XAF account
- Remove redundant GET /api/prices/all (GET /api/assets already has prices)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… and batch transfers

BUY/SELL endpoints now only require assetId + units. The backend
extracts user identity from JWT, auto-resolves XAF accounts, creates
asset accounts on first buy, and executes all transfer legs atomically
via Fineract Batch API (enclosingTransaction=true) for automatic
rollback on failure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…gResponse

HoldingResponse was a strict subset of PositionResponse built from the
same data. Remove the redundant DTO, /api/portfolio/holdings endpoint,
and holdings array from the portfolio summary. The frontend now uses
positions for all views.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… admin role security

All multi-step Fineract account lifecycle operations (create → approve → activate
→ optional deposit) now use provisionSavingsAccount() with Batch API and
enclosingTransaction=true for automatic rollback on failure.

- Add provisionSavingsAccount() to FineractClient using Batch API with
  cross-request references ($.1.savingsId)
- Refactor createAsset() to use atomic provisioning (replaces 4 sequential calls)
- Refactor resolveOrCreateUserAssetAccount() to use atomic provisioning
- Secure /api/admin/** endpoints with ASSET_MANAGER role in SecurityConfig

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix auth bypass: getOrder() now verifies order belongs to requesting user
- Fix NPE: null-safe spread/fee defaults in BUY and SELL execution paths
- Fix unsafe JWT fallback: throw exception instead of hashCode() collision risk
- Fix race condition: atomic SQL UPDATE for circulating supply instead of
  read-modify-write
- Fix WAP precision: use scale=4 instead of scale=0 for avg_purchase_price
- Fix DI bypass: inject AssetCatalogService instead of manual instantiation
- Add validation: @PositiveOrZero, @SiZe on UpdateAssetRequest + @Valid
- Add fail-fast: startup validation for fee-collection-account-id
- Add safe Redis parsing: catch malformed cache with DB fallback
- Add explicit error: throw on negative units instead of silent max(0) clamp
- Add V10 migration: indexes on trade_log.order_id, user_positions.asset_id,
  and avg_purchase_price precision upgrade
- Restrict CORS default from wildcard to localhost dev origins

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ry resilience

Add ErrorBoundary and ErrorFallback components for graceful crash recovery.
Add extractErrorMessage helper for human-readable API error messages.
Wire isError/refetch into all hooks and views with retry UI.
Add step-by-step form validation to create-asset wizard.
Guard manual price inputs with Number.isFinite check.
Configure QueryClient defaults (staleTime, retry, refetchOnWindowFocus).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ardening

Address 22 issues found during asset service audit:

Backend critical fixes:
- Fix inventory race condition with lock-then-verify pattern (double-sell prevention)
- Add XAF balance check before buy to prevent cryptic batch transfer failures
- Fix cost basis to include trading fees for accurate P&L calculation
- Re-fetch authoritative price inside lock to prevent stale pricing
- Add fee collection account null guard to prevent NPE
- Add Redis resilience in PricingService and TradeLockService (local fallback)
- Add JWT subject null safety check
- Fix N+1 query with @entitygraph on OrderRepository
- Differentiate HTTP status codes (404/422/502) in GlobalExceptionHandler
- Optimize FineractTokenProvider WebClient initialization
- Externalize GL account IDs via AssetServiceConfig
- Add V11 migration for performance indexes
- Tune HikariCP connection pool settings

Backend tests:
- TradingServiceTest (7 tests: buy/sell, idempotency, market closed, inventory, funds)
- PortfolioServiceTest (4 tests: WAP, cost basis, P&L, negative units guard)
- PricingServiceTest (4 tests: cache hit/miss, Redis down, malformed cache)
- JwtUtilsTest (5 tests: extract subject/userId, null/missing claims)

Frontend hardening:
- Add AuthGuard for route protection with OAuth/basic redirect
- Add error boundaries (errorComponent) on all routes
- Add field-level form validation with inline error display
- Add axios response interceptor with 401 redirect and 5xx retry
- Add cache invalidation on all mutations
- Add loading/disabled states and confirmation dialogs on action buttons

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…dening

- Fix InsufficientInventoryException 3-arg constructor mismatch
- Fix Keycloak role extraction (nested realm_access.roles parsing)
- Strip Fineract IDs from public API (AssetPublicDetailResponse)
- Gate insecure SSL behind app.fineract.ssl-verify property
- Add @transactional to executeBuy/executeSell
- Fix stale asset reference in executeSell lock (re-fetch pattern)
- Bound rate limit maps with scheduled eviction + max cap
- Use JWT sub claim for stable per-user rate limiting
- Clean up stuck EXECUTING orders in stale order scheduler
- Prevent OHLC data wipe on restart via @PostConstruct init
- Fix description size mismatch (2000 -> 1000 in UpdateAssetRequest)
- Wire AssetMetrics into TradingService and TradeLockService

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…depth hardening

Reorder Fineract batch transfers to execute LAST (after all local DB writes)
to prevent inconsistent state on partial failure. Add transaction timeout,
required idempotency keys, DTO validation caps, admin pagination, @PreAuthorize
defense-in-depth, and robustness improvements.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… dark mode, GitOps

Backend: add circuit breaker (Resilience4j), Redis health indicator, audit
logging aspect, idempotency validation, configurable rate limits, pagination
guards, and timezone in market status. Add 15 unit/integration tests across
5 new test files.

Frontend: add price history chart (recharts), CSV inventory export, dark mode
toggle, table skeletons, aria-labels, ErrorBoundary navigation reset, settings
page, and logout confirmation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix rate limiter JWT spoofing: use token hash instead of unverified sub claim
- Fix TradeLockService: add 5s timeout on local fallback locks, detect Redis failover on release
- Add treasury account null validation in both executeBuy and executeSell
- Add circulating supply DB constraints (CHECK >= 0, <= total_supply) and JPQL guards
- Wrap all 3 schedulers in try-catch to prevent thread death on exceptions
- Add aria-labels, role attributes, and aria-pressed to frontend tables and filters

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tion

- Add ID tiebreaker sort to all paginated queries for deterministic ordering
- Add ARIA attributes, ESC key handler, focus management to ConfirmDialog
- Fix usePricing cache invalidation to also invalidate asset/catalog queries

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Re-enable JWT authentication and user authorization that were disabled,
fix critical security gaps in callback validation and CORS, add withdrawal
reversal logic, distributed token caching via Redis, request correlation
IDs, optimistic locking retry, and step-up auth scaffolding.

Critical: re-enable JWT auth, uncomment user authorization checks
High: CinetPay fail-closed validation, withdrawal reversals, step-up auth
Medium: require idempotency key, tighten CORS, Redis token cache, remove ngrok URLs
Low: correlation ID filter, @retryable on callbacks, WebClient correlation propagation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…de preview

- Consolidate 12 Flyway migrations into single V1__create_schema.sql
  (not yet in production, eliminates inconsistent V9 drop-column issue)
- Fix @MockBean import: mock.bean -> mock.mockito in test files
- Fix TypeScript error in Pricing.view.tsx tooltip formatter
- Add trade preview endpoint for price quotes without execution

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…etheus

- Add app.security.permit-all-admin toggle to SecurityConfig for Docker
  dev (permits /api/admin/** without JWT when enabled, default false)
- Add EditAssetDialog and MintSupplyDialog components
- Wire mint supply and edit asset actions in asset details page
- Add micrometer-registry-prometheus dependency for metrics endpoint

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… fallback

- Add createAsset, inventory, marketSettings keys to reusable i18n
  (en + fr) so sidebar shows labels instead of raw translation keys
- Add "Admin" fallback for displayName when OAuth userinfo returns
  empty user (Docker dev without OAuth2 Proxy)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Change all 7 admin/staff apps to use /oauth2/sign_out?rd=/logout
instead of redirecting back to their own base path. The gateway
/logout endpoint handles Keycloak session termination via top-level
navigation, then redirects to /home/.

Basic auth mode now redirects to /home/ (portal) instead of app base.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…reate client form

Allow users to choose between Person and Entity when creating a client.
The form dynamically shows firstname/lastname for persons or a single
entity name field for entities, sending the appropriate legalFormId to Fineract.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Make spread optional via spread-collection-account-id config. When set,
spread is applied to execution price and swept to a dedicated account.
When not set, spread is disabled entirely (execution price = base price).

SELL now shows 2 user-visible transactions (gross credit + fee debit)
for fee transparency symmetric with BUY. Spread sweep is internal.

Also includes: missing header handler, InsufficientInventoryException
extends TradingException, MarketHoursService locale fix, and new tests
(integration, provisioning, favorites, trade lock, test data factory).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…50 tests)

Replace 3 commented-out test files with working tests and add new integration test suite.
Covers PaymentService (23 unit), PaymentController (10), CallbackController (8), and
full end-to-end flows with H2 (10 integration). Also adds configurable rate limiter toggle
for test profile and excludes target/ from biome checks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…cleanup

Verify user ownership on idempotency key lookups to prevent cross-user
order detail leakage (409 on mismatch). Replace blind FAILED marking of
stuck EXECUTING orders with NEEDS_RECONCILIATION status, WARN logging,
and a Prometheus counter for ops alerting. Add price change warning log
and multi-XAF-account warning during provisioning.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…diation (48 issues)

Address 48 identified issues across security, logic, robustness, and code quality:

P0 - Security Critical:
- Remove X-External-Id header impersonation vector (authorization bypass)
- Default SSL verification to true with @PostConstruct warning
- Remove sensitive token/credential logging from FineractTokenProvider and FineractConfig
- Fix CORS wildcard default to safe localhost origins

P1 - High Priority Logic:
- Fix registration race condition: rely on Keycloak 409 instead of check-then-act
- Improve rollback reliability with error logging and metrics for orphaned resources
- Add KYC review race condition guards (status pre-condition checks)
- Add per-userId lock striping for Keycloak attribute updates
- Replace unbounded ConcurrentHashMap with Caffeine cache (5-min TTL, 10K max)
- Fix rate limit bucket growth with MAX_BUCKETS cap and scheduled cleanup
- Implement actual daily/monthly transaction limit enforcement from Fineract data
- Add CONFLICT/UNAUTHORIZED HTTP status mappings

P2 - Robustness:
- Add input validation: @SiZe, @past, @pattern, @Valid on nested address DTO
- Fix document name collision: UUID instead of System.currentTimeMillis()
- Add transaction pagination to AccountController
- Implement actual KYC document status from Fineract API (was TODO)
- Fix TokenProvider creating RestClient on every refresh

P3 - Code Quality:
- Add KYC review audit trail (capped at 20 entries in Keycloak attributes)
- Remove insecure password defaults from application.yml
- Handle more_info_required status with info request message in response
- Store customer address in Fineract during registration

Metrics:
- Expand RegistrationMetrics with 12 metric categories covering registration,
  KYC uploads/reviews, rate limiting, Fineract/Keycloak calls, cache hit/miss,
  transaction limit violations, and rollback failures

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Phase 1: Extract PhoneNumberUtils shared utility from 3 provider clients
- Phase 2: Pessimistic locking (SELECT FOR UPDATE) on all 4 callback handlers
  to prevent race conditions on concurrent webhook delivery
- Phase 3: Constant-time HMAC comparison (MessageDigest.isEqual) in
  StepUpAuthService and CinetPayClient; MTN subscription key validation
  on callbacks; null payload guards; notifToken column (V3 migration)
- Phase 4: Fix BigDecimal intValue→longValue for amounts >2.1B in Orange
  and CinetPay clients; extract ReversalService with @retryable(3x) and
  @recover fallback for withdrawal reversals
- Phase 5: JWT subject extraction for rate limit identification; callback
  rate limiting (100/min per IP); configurable currency per provider;
  CinetPay unknown payment method → FAILED instead of silent MTN default;
  Tomcat request size limits (1MB form, 2MB swallow)
- Phase 6: Stale transaction cleanup scheduler (configurable, default 30min)
  with @ConditionalOnProperty toggle and Micrometer metrics

All 60 tests pass (unit, controller, integration, scheduler, utility).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add full bond lifecycle support including:
- BONDS category and MATURED status with V3 migration
- 7 bond fields on Asset entity (issuer, ISIN, maturity, interest rate,
  coupon frequency, next coupon date, validity date)
- Bond validation in provisioning (issuer, maturity, frequency checks)
- Validity date enforcement: BUY blocked after expiry, SELL always allowed
- MaturityScheduler: daily auto-transition to MATURED status
- InterestPaymentScheduler: daily XAF coupon payments to bond holders
  via Fineract account transfers (not token-based interest)
- Admin coupon history endpoint with InterestPayment audit entity
- 5 bond-specific Prometheus metrics
- Frontend: bond creation wizard step, bond info card, coupon history
  table, MATURED badge styling
- All 93 backend tests pass, frontend builds clean

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
guymoyo and others added 30 commits February 18, 2026 09:22
…nt for all asset categories

Replace validityDate/expectedLaunchDate with subscriptionStartDate/subscriptionEndDate
mandatory for all categories (not just bonds). BUY orders are blocked outside the
subscription window with SUBSCRIPTION_NOT_STARTED and SUBSCRIPTION_ENDED error codes.
Add capitalOpenedPercent field for equity offerings (e.g. RENAPROV Finance S.A.).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…factor UI

Store treasury client display name at creation time via new
getClientDisplayName API call, and derive savings product name from
asset name. The detail page now shows human-readable names prominently
with IDs underneath in a dedicated "Fineract Integration" card. The
create wizard regroups supply/subscription fields with clear sub-headings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When OAuth tokens expire, XHR requests get 302-redirected to Keycloak
which the browser blocks as CORS errors. Detect these network errors in
OAuth mode and redirect to the login flow instead of retrying or failing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add GET /api/assets/{id}/recent-trades returning the last 20 executed
trades (anonymous, no user info) for an asset. Wires the existing
TradeLogRepository query and RecentTradeDto through AssetCatalogService.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enhance the portfolio API with category allocation breakdown, estimated
annual yield (total return from unrealized gains + bond coupon income),
and portfolio value history via daily scheduled snapshots at 20:30 WAT.

Also fixes pre-existing GlAccountResolver mock issue in integration tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…n forecast

Update all three doc files with features added since the initial docs:
- README: add portfolio_snapshots table and PortfolioSnapshotScheduler
- Customer API Guide: add recent trades feed, portfolio history with
  charting, updated portfolio response (allocations, yield, category
  count), updated asset listing with bond fields and subscription dates
- Admin Guide: add coupon forecast and manual trigger endpoints, bond
  updatable fields, portfolio snapshots scheduler description

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a bond matures, admins can now trigger principal redemption to pay
face value to all holders and return asset units to treasury. Includes
retry support for partial failures, REDEEMED status lifecycle, and a fix
for the final coupon being missed on maturity day.

Backend: POST /api/admin/assets/{id}/redeem endpoint, PrincipalRedemption
entity with V7 migration, redemption history GET endpoint, widened coupon
scheduler query to include MATURED bonds.

Frontend: Redeem Bond button on MATURED bonds, RedemptionHistoryTable
component, REDEEMED status badge (purple).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… code review

Critical: Orange callback auth validation (notif_token), balance check race
condition (Fineract-authoritative), idempotency TOCTOU (INSERT WHERE NOT EXISTS).
High: CinetPay GL account mapping via phone prefix detection, PROCESSING state
cleanup with provider polling, callback amount verification.
Medium: MTN token cache switched to Redis, phone normalization consolidated,
rate limiter eviction and client ID improvements, safe balance extraction.
Low: callback failure metrics, MTN validation fail-closed, daily transaction
limits enforcement, stale PROCESSING polling fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…egration

Create a separate e2e-tests module that boots asset-service against real
Testcontainers infrastructure (PostgreSQL, Redis, Fineract) with no mocking.
Covers stock lifecycle, bond coupons/maturity/redemption, treasury verification,
error scenarios, and Fineract reconciliation across 18 scenarios in 5 feature files.

Also add exec classifier to asset-service spring-boot-maven-plugin so the
original JAR can be used as a compile dependency by downstream modules.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Align Redis trade lock TTL (45s) with transaction timeout (30s) to
  prevent lock expiry mid-transaction causing concurrent trade races
- Replace sequential executeBatchTransfers with Fineract Batch API
  (POST /batches?enclosingTransaction=true) for atomic all-or-nothing
  transfers
- Move fee withdrawal + journal entry into the atomic batch to prevent
  orphaned Fineract state when fee operations fail after transfers succeed
- Extract common BUY/SELL logic into unified executeTrade() with strategy
  pattern (TradeStrategy sealed interface), eliminating ~150 lines of
  duplication

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…batch IDs on orders

Local lock fallback timeout was hardcoded to 5s, too short for 30s transactions.
Now configurable (default 40s) via asset-service.trade-lock.local-fallback-timeout-seconds.
Also stores Fineract batch request IDs on Order entity for admin reconciliation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…assing)

Asset-service fixes:
- Add sequential fallback in FineractClient when batch API returns 501
  for unsupported endpoints (e.g. accounttransfers)
- Add AssetRepository.updateStatus() @Modifying query to avoid Hibernate
  full-entity save overwriting circulatingSupply after adjustCirculatingSupply()
- Fix PrincipalRedemptionService to use updateStatus() instead of save()

E2E test fixes:
- Replace JwtDecoder bean override with embedded JWKS HTTP server for
  reliable JWT validation in tests
- Remove duplicate Surefire cucumber.features/glue config that caused
  every scenario to run twice
- Add Fineract Financial Activity Account 200 (LIABILITY_TRANSFER) mapping
- Fix BigDecimal parsing (Number.intValue() instead of getInt())
- Fix coupon trigger field name (holdersPaid not paid)
- Add direct MaturityScheduler invocation for bond maturity testing
- Fix empty-body parsing for activate/halt/resume endpoints

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…review

- Remove insecure SSL trust manager (now opt-in via SSL_INSECURE env var)
- Fix empty subscription key bypass in MTN callback validation
- Add dead-letter queue for failed withdrawal reversals with admin API
- Distribute rate limiting via Redis INCR+EXPIRE with in-memory fallback
- Add callback IP whitelisting filter (disabled by default, per-provider)
- Configure per-provider timeouts (MTN 60s, Fineract 15s, others 30s)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Spring Boot Maven plugin uses <classifier>exec</classifier>, producing
*-exec.jar as the runnable JAR. The Dockerfile was copying *.jar which
picked up the plain (non-executable) library JAR, causing "no main manifest
attribute" at container startup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… payment suites

Add payment-gateway-service E2E suite (14 scenarios) with WireMock for
external providers (MTN MoMo, Orange Money, CinetPay) and expand
asset-service coverage with 25 new scenarios for catalog, portfolio,
pricing, favorites, admin, and trade preview endpoints. Restructure
into two isolated Cucumber suites with separate Surefire executions
to avoid Flyway migration conflicts between service JARs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ract

The DTO serialized `timestamp` in JSON but the frontend expected `capturedAt`,
causing "Invalid Date" on the price history page.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The hourly scheduler was recording identical prices every hour,
bloating the price_history table. Now compares with the last
recorded price and only saves when the price actually changed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Utilization was rounding to 0.0% for small values like 0.01%.
Also added title tooltip on TVL column header to explain the abbreviation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Bid/Ask prices with spread calculation
- Position limits, lock-up periods
- Notification system with preferences
- Treasury shortfall detection
- Income distribution for non-bonds
- Asset delisting with forced buyback
- Automated reconciliation
- Frontend UI for all new features
- Prometheus metrics and Swagger docs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three new features for platform observability and investor experience:

- Admin Dashboard: aggregated summary endpoint with asset counts, 24h trading
  volume, order health, and reconciliation status. Frontend stat cards on
  the dashboard page with 30s auto-refresh.

- Persistent Audit Log: extends existing AOP aspect to persist admin actions
  to a new audit_log table. Covers all 4 admin controllers. Filterable
  endpoint and dedicated /audit-log page with paginated table.

- Portfolio Income Calendar: projects coupon, dividend, rent, and other
  income events across a user's portfolio. New /api/portfolio/income-calendar
  endpoint and dedicated /income-calendar page with monthly bar chart,
  event list, and type breakdown.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… delisting

Completes income distribution support for non-bond assets and adds
several trading safeguards and lifecycle management features:

- Income Distribution: periodic payouts (dividend, rent, harvest yield,
  profit share) for non-bond assets using current market price formula.
  Includes scheduler, forecast service, and income benefit projections.

- Exposure Limits: per-asset max position %, max order size, and daily
  trade limit with soft-check in preview and hard-check on execution.

- Lock-up Period: configurable holding period preventing early selling
  after purchase to prevent pump-and-dump.

- Delisting: graceful asset removal with DELISTING grace period for
  voluntary selling, followed by forced buyback at redemption price.

- Amount-Based Trade Preview: accepts XAF amount (not just units),
  computes max purchasable units including fees and remainder.

- E2E tests and admin guide documentation for all new features.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… remove unused imports

Add /audit-log and /income-calendar to routeTree.gen.ts so TanStack
Router recognizes the new pages. Remove unused AdminDashboardResponse
type imports from dashboard files that caused TS6133 build errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The AuditLog entity requires a persistent table for the AOP aspect to
write admin action records. Without this migration Hibernate validation
fails on startup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…come calendar

Add comprehensive test coverage for three recently implemented features:
- 3 unit tests for AdminDashboardService (empty/populated/24h cutoff)
- 8 unit tests for IncomeCalendarService (bonds, income assets, aggregation)
- 14 BDD/Cucumber scenarios across 3 new feature files
- Add income distribution fields to CreateAssetRequest DTO for demo script support
- Fix pre-existing test failures: NotificationLogRepository JPQL type mismatch,
  missing mocks in TradingServiceTest and AdminAssetControllerTest
- Add income field support to asset detail and edit UI components

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ayment history

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… fixes, and admin alerts

- Add order filtering with status, asset, search, date range params (native SQL query)
- Add order detail endpoint with fineractBatchId and idempotency key
- Add asset options endpoint for filter dropdowns
- Fix single-asset reconciliation trigger (was running full reconciliation)
- Add GL-level treasury cash negative check to reconciliation
- Add AdminAlertEvent for admin broadcast notifications on stuck orders and critical discrepancies
- Add admin notification endpoints (list + unread count)
- Frontend: filter bar, detail slide-over panel, admin alert badge
- Update ADMIN-GUIDE.md sections 15-17
- Add E2E tests for order resolution and reconciliation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ing)

- Fix TradePreviewRequest validation: move @positive check into isValid() so
  amount-based previews (units=null) don't fail validation
- Fix exposure-limits blocker names to match backend (ORDER_SIZE_LIMIT_EXCEEDED,
  POSITION_LIMIT_EXCEEDED)
- Fix multi-asset reconciliation by storing per-symbol asset IDs in StockTradingSteps
- Lower test balance from 5M to 100K in 4 feature files to match fee-inclusive costs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…action details

- Show "Managed by {treasuryClientName}" below asset name in detail header
- Make Treasury Client, Asset Account, and Cash Account IDs clickable
  links to the account-manager app (via VITE_ACCOUNT_MANAGER_URL env var)
- Add "Details" column to account-manager transaction table showing
  transfer descriptions and notes (e.g. "Asset purchase: XYZ")

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Expand ADMIN-GUIDE.md Section 16 with step-by-step procedures for
investigating and correcting each discrepancy type: SUPPLY_MISMATCH,
POSITION_MISMATCH, and TREASURY_CASH_NEGATIVE. Includes Fineract API
calls, SQL queries, root cause analysis, and order resolution guidance.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Catalogs all 18 feature domains with endpoints, business rules, and
configuration — covering asset lifecycle, trading, bonds, income
distribution, reconciliation, and more.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants