This POC abstracts a financial risk monitoring dashboard module that I previously built in a production trading system.
Risk managers use it to observe trading exposure, margin usage, and system health in near real time so that they can react quickly to abnormal positions or infrastructure incidents.
All domain data and implementation here are fully desensitized and rewritten with mock data to avoid leaking any commercial secrets from the original system.
- Slow First Paint
- The legacy SPA waited for multiple APIs (risk, trading, ledger, monitoring) before rendering any meaningful content.
- Complex Client-side Orchestration
- The browser was responsible for fan-out/fan-in aggregation across several microservices, leading to complicated state management and duplicated business logic.
- Poor User Experience Under Load
- Under latency spikes or partial outages, users saw blank pages or inconsistent tiles because some APIs failed while others succeeded.
This POC focuses on isolating and re-implementing one core capability from that system:
"Aggregate and serve a consistent, pre-optimized risk view model for the dashboard, with fast first paint and clear degradation behavior."
Risk Aggregation BFF + SSR Dashboard Shell
- The backend is modeled as a Java BFF (Backend-for-Frontend) responsible for:
- Fan-out to multiple downstream sources (simulated here with mock services).
- Aggregation into a single dashboard view model (per account / per book exposure, alerts, health metrics).
- Redis-backed caching for "Top N" rankings.
- The frontend is an Angular SSR dashboard shell that consumes this view model and renders the first screen on the server.
- Concurrent fan-out / fan-in aggregation (Java)
- Implemented with non-blocking IO using Spring WebFlux and Project Reactor's
Mono.zip()for parallel service calls.
- Implemented with non-blocking IO using Spring WebFlux and Project Reactor's
- SSR & Hydration
- The first screen is rendered on the server using Angular SSR, which drastically improves time-to-content even if backend calls are slightly delayed.
- "Top N" calculations
- Risk tiles show "Top N riskiest positions/accounts" backed by Redis Sorted Sets to support O(log N) updates.
The current repository contains a complete implementation including:
- Angular SSR dashboard with D3.js visualizations
- Java BFF with WebFlux-based concurrent aggregation
- Three mock microservices (Risk, Trading, Ledger) with Redis integration
- Docker Compose for one-click deployment
- Primary implementation language for backend: Java
(The BFF is implemented underbff-java/using Spring Boot 3.x + WebFlux for non-blocking concurrent aggregation.)
- Framework: Angular 21+ with SSR (Universal-style
@angular/ssr) - State Management: Signals & RxJS
- Visualization: D3.js for bar charts and data visualization
- Communication: REST API
- Runtime: Java 17/21 & Spring Boot 3.x (WebFlux)
- Concurrency Model: Non-blocking IO (Project Reactor), used for concurrent calls to:
- Risk Service
- Trading Service
- Ledger Service
- Data Access:
- Redis (for cached metrics and "Top N" rankings)
- Mock Services with Redis-backed data storage
- Runtime: Node.js container serving Angular SSR output
- Containerization:
Dockerfile+docker-compose.yml - Services (all Dockerized):
- Dashboard UI (port 4000)
- BFF Java (port 8080)
- Redis (port 6379)
- Mock Risk Service (port 9001)
- Mock Trading Service (port 9002)
- Mock Ledger Service (port 9003)
- Risk dashboards always depend on multiple slow and heterogeneous services.
- Pushing all orchestration to the frontend makes:
- Error handling complex.
- Performance tuning hard (you cannot easily cache partial aggregations).
- A dedicated BFF:
- Centralizes aggregation and caching.
- Presents a single, UI-friendly view model to the frontend.
- Allows independent scaling of aggregation logic (e.g., with WebFlux + backpressure support).
- Risk managers often open the dashboard under time pressure.
- SSR minimizes time-to-first-meaningful-content, even if some backend calls are not yet resolved.
- With Hydration:
- The initial HTML is server-rendered.
- The browser then "takes over" without a visible flicker.
- Ranking "Top N riskiest positions" and other aggregates are:
- Expensive if recomputed from the primary database on each request.
- Easy to maintain incrementally in a cache (e.g., Redis Sorted Sets).
- Separation allows:
- Fast reads for the BFF.
- Tuning of eviction / refresh policies independently of the UI.
- Mocked Data Instead of Real Feeds
- All data is generated locally / in-memory with fake accounts and positions.
- This keeps the POC safe from any data-leak concerns while still demonstrating data-flow and aggregation patterns.
Prerequisites
- Docker
- Docker Compose
Steps
# At repository root
docker-compose up --buildThen open http://localhost:4000 in your browser.
What This Does
- Builds all services (Frontend, BFF, Mock Services)
- Starts Redis for caching
- Exposes ports: 4000 (UI), 8080 (BFF), 9001-9003 (Mock Services)
| Method | Steps |
|---|---|
| View Page Source | Right-click → "View Page Source". You should see pre-rendered HTML with actual data. |
| Disable JavaScript | Chrome DevTools → Settings → Disable JavaScript. Refresh. The page should still display data and charts. |
| curl Command | curl http://localhost:4000 should return HTML with embedded dashboard data. |
Direct API Test
curl http://localhost:8080/api/dashboard | jq .Concurrent Aggregation Verification
time curl -s http://localhost:8080/api/dashboard > /dev/null- With concurrent calls (Mono.zip), total time ≈ max(service latencies) ≈ 100-150ms
- If sequential, would be sum of latencies ≈ 300ms+
Redis Top N Check
docker exec -it dashboard_platform-redis-1 redis-cli
ZREVRANGE top:risky:accounts 0 4 WITHSCORESThis POC was built with assistance from AI tools (primarily Cursor), in line with the challenge's encouragement to leverage AI.
- Where AI Helped
- Drafting and iterating on this
READMEstructure. - Generating boilerplate for Angular SSR setup and Docker files.
- Implementing D3.js visualizations with SSR support.
- Drafting and iterating on this
- What I Did Manually
- Chose the business scenario and module scope based on my real project experience.
- Designed the overall architecture (BFF + SSR + caching).
- Reviewed and adjusted AI-generated content.
All code and documentation in this repository are newly written for this challenge and use mock / synthetic data only.