Case study
Angular Dashboard
A federated financial analytics dashboard remote with live simulated institution metrics, PrimeNG UI, Angular Signals, and period/institution filters.
Overview
- Role
- Sole engineer — architecture, remote app, host integration
- Timeline
- 2026
- Status
- Demo
- Case study path
- /projects/angular-dashboard
Problem
The portfolio needed a live product surface that demonstrates micro-frontend integration—not just a static screenshot. The dashboard had to ship as an independently buildable Angular app while still mounting inside the host under a stable route, without forcing the resume site and the demo UI into one deployable monolith.
Goals
- Expose a remote route module the host can load at runtime
- Keep the dashboard deployable and developable on its own port
- Showcase live financial monitoring UX with simulated real-time updates and filters
- Avoid blocking host SSR/prerender when the remote is unavailable
Key features
- Micro-frontend route exposure (`./routes`)
- Runtime remote module loading from the host
- Analytics-style stat cards
- Period switching (30d / 90d / 12m)
- CSS bar chart for visitor trends
- Responsive dashboard layout
Architecture
Runtime composition flow — top is the entry surface, bottom is the leaf dependency.
- Personal Website (Angular host)
- Native Federation (remoteEntry)
- Angular Dashboard (remote app)
- In-component mock metrics (period maps)
Host owns shell routing and branding; the remote owns the dashboard UI and demo data.
Technology
Each choice below includes the engineering reason it was selected for this project.
Angular
Why selected: Matches the host stack so shared Angular packages can be singletons under federation, and the remote can expose typed route modules cleanly.
TypeScript
Why selected: Keeps period keys, stat cards, and chart series type-safe as the demo data model grows.
Native Federation
Why selected: Loads the remote at runtime from a manifest URL, which is the actual skill under demonstration—independent builds with a composed UX.
CSS (component styles)
Why selected: Self-contained BEM-style styles keep the remote visually coherent when federated without depending on the host Tailwind pipeline.
Mock period data maps
Why selected: Deterministic in-memory datasets make the period switcher demonstrable without standing up an analytics API for a portfolio showcase.
Engineering challenges
Concrete problems and the solutions that shipped.
Challenge 1
How to load the Angular dashboard independently while keeping it integrated with the portfolio?
Solution
Build the dashboard as a Native Federation remote that exposes `./routes`, then mount it from the host at `/projects/dashboard` via `loadRemoteModule`.
Challenge 2
Host SSR/prerender fails or hangs if it eagerly resolves a browser-only remote.
Solution
Guard remote loading with a `typeof window` check, return empty child routes during SSR, and mark `/projects/dashboard` as client render mode.
Challenge 3
Remote styling must not break when the host theme/Tailwind context differs.
Solution
Keep dashboard styles local to the remote component with its own CSS variables aligned to the brand primary, instead of importing host utilities.
Architecture decisions
Decision · reason · alternative · trade-off for each major fork in the road.
Decision
Native Federation remote instead of embedding the dashboard in the host
- Reason
- Independent build, deploy, and iteration cycle for the showcase app.
- Alternative
- Single monolithic Angular application with a dashboard feature module
- Trade-off
- More deployment and runtime complexity; remote availability becomes an ops concern.
Decision
In-component mock metrics instead of a real analytics API
- Reason
- Fast, deterministic demos with zero backend dependency for portfolio visits.
- Alternative
- Wire a real metrics backend or third-party analytics API
- Trade-off
- Numbers are illustrative; the engineering story is integration, not production telemetry.
Decision
Client-only render mode for the federated route
- Reason
- Avoids SSR coupling to a remote that may be offline in local or preview environments.
- Alternative
- Server-render with Node federation always required
- Trade-off
- First paint for the demo route is browser-driven; SEO value of the live demo is low anyway.
Performance
Demo / estimated metricsNo production Lighthouse capture is checked into the repo for the federated route. Figures below describe the intended demo profile.
Remote serve port
4201
Local federation target
Production remote
/mfe/angular-dashboard/
Same-origin remoteEntry on host deploy
Data source latency
~0 ms
In-memory maps; no network fetch
Chart rendering
CSS bars
No Chart.js runtime in the remote UI
SSR for demo route
Skipped
Client render mode by design
Lessons learned
What held up in practice, what did not, and what the next iteration should change.
What worked
- Exposing routes (not a single component) keeps the remote composable if child routes appear later
- Manifest-driven remote URLs make local vs deployed targets swappable via env/config
- Aligning remote primary color with the host brand reduces visual dissonance after federation
What didn't
- Assuming the remote would always be reachable during host SSR
- Relying on host Tailwind inside the remote without a shared design-system build
What would be improved
- Shared design tokens package consumed by host and remotes
- Optional real API adapter behind the same period-switching interface
What I learned
- Federation is as much about failure modes and SSR boundaries as it is about happy-path module loading
- Demo data models should stay intentionally small so the integration story stays readable
Future improvements
Next engineering increments if this surface continues to evolve.
- Real analytics API behind the existing period interface
- Authentication-gated demo modes
- Real-time metric updates
- Response caching / stale-while-revalidate for API-backed views
- Additional micro-frontend remotes beyond the dashboard
Technical stack
Compact summary for scanning.
Code notes
Short excerpts that illustrate integration points discussed above.
async function loadDashboardRoutes(): Promise<Routes> {
if (typeof window === 'undefined') {
return [];
}
const m = await loadRemoteModule('angular-dashboard', './routes');
return m.DASHBOARD_ROUTES;
}