Project Documentation  ·  v2.0

From Windows IIS
to Raspberry Pi 5
Bare-Metal Linux

A full-stack ASP.NET Core 10 analytics platform migrated from a Windows Server IIS deployment to a Raspberry Pi 5 (16 GB) running Ubuntu bare-metal. Integrates Power BI embedding, Bollinger Band charting, a Go backend API, PostgreSQL, and a dual-LLM Natural Language SQL interface.

Running on .NET 10 ARM64 · Ubuntu Raspberry Pi 5 · 16 GB Go API · PostgreSQL

From the Old World to the New

The same application — now leaner, faster, and running on an ARM64 single-board computer for a fraction of the cost.

▲ Then
🖥️ Hardware Windows Server x86-64
🌐 Web Server IIS (Internet Information Services)
⚙️ Runtime .NET 8 (LTS)
🏗️ Arch x86-64
💿 OS Windows Server
🔄 Deploy IIS Application Pool
🔒 TLS IIS Certificate Binding
Migration
★ Now
🍓 Hardware Raspberry Pi 5 · 16 GB RAM
🚀 Web Server Kestrel (built-in, bare-metal)
⚙️ Runtime .NET 10 (latest)
🏗️ Arch ARM64 (aarch64)
🐧 OS Ubuntu Linux (bare-metal)
🔄 Deploy systemd service + Docker
☁️ TLS Cloudflare Tunnel (zero-trust)
10.0 .NET Version
16 GB RAM · Pi 5
ARM64 Architecture
5050 App Port
8001 Go API Port
7 Controllers

How It All Fits Together

All services co-located on the Raspberry Pi 5. Cloudflare Tunnel handles public-facing TLS termination, forwarding traffic to Kestrel on port 5050.

🌍 Browser / Client HTTPS
☁️ Cloudflare Tunnel Zero-Trust TLS · X-Forwarded-Proto
🔑 Azure AD (Entra) OpenID Connect · MSAL
🍓 Raspberry Pi 5 · 16 GB · Ubuntu ARM64
⚡ ASP.NET Core 10 — Kestrel EmbeddedCore · Port 5050 · Razor MVC
📊 Power BI API Microsoft Cloud · Embed Tokens
🐹 Go Stock API Port 8001 · Bollinger · Events
🐘 PostgreSQL stocks_mart · dbt pipeline
🤖 Ollama (Local LLM) qwen2.5-coder:7b · NL→SQL
🌐 OpenRouter (Cloud LLM) deepseek-chat · NL→SQL

Built With

A pragmatic mix of Microsoft and open-source tooling, all running natively on ARM64 Linux.

.NET 10
ASP.NET Core 10.0
Web framework — Razor MVC, Kestrel, built-in DI and middleware pipeline.
🐹
Go
Stock API Microservice
Separate HTTP server on port 8001. Serves Bollinger band data, market events, forex, and observatory analytics.
🐘
PostgreSQL
Npgsql 10.0.2
Primary data store for stock market data. Accessed via dbt-managed stocks_mart materialized views.
📊
Power BI
Microsoft.PowerBI.Api 5.1.0
Embedded analytics. Service Principal authentication, V2 embed tokens, workspace and report enumeration.
🔑
Azure AD (Entra)
Microsoft.Identity.Web 4.6.0
OpenID Connect SSO for protected workspaces. MSAL token acquisition for Power BI service principal.
📈
Plotly.js
v2.27.0 · CDN
Interactive charting for NL→SQL query results. Supports line, bar, candlestick, and bar_h chart types.
🤖
Ollama
qwen2.5-coder:7b (local)
Local LLM inference for Natural Language → SQL generation. Runs on-device, no data sent to cloud.
🌐
OpenRouter
deepseek/deepseek-chat
Cloud LLM alternative for NL→SQL. Supports side-by-side comparison against local Ollama output.
☁️
Cloudflare Tunnel
Zero-Trust Ingress
Securely exposes the Pi to the internet without opening inbound ports. Handles TLS, forwards headers via X-Forwarded-Proto.
🎨
Bootstrap 5
Responsive UI
Grid system and components, overridden with a custom dark theme using CSS variables — cyan, gold and green accents.
🔧
dbt
Data Build Tool
Manages the stock data transformation pipeline, producing materialized views in dbt_stocks.stocks_mart.
🍓
Raspberry Pi 5
16 GB · ARM64 · Ubuntu
All services — ASP.NET Core, Go API, PostgreSQL, Ollama — run bare-metal on a single ARM64 board.

Views & Features

All pages share the same dark orbital theme with CSS variables, system sans-serif font, and responsive Bootstrap layout.

Power BI HomeController
Method Route Description
GET / Animated orbital carousel — entry point to Power BI workspaces.
GET /ws Workspace browser — orbital carousel listing all Power BI workspaces. Lock badge on protected workspaces.
GET /rkg/{workspaceId} Report browser — lists all reports within a workspace.
GET /rkg/{workspaceId}/{reportId} Embedded report — full-screen Power BI iframe with collapsible page navigator. 🔒 Auth required for PROD
Stocks & Markets BollingerController
Method Route Description
GET /bollinger/observatory Market observatory — aggregated view of sectors, countries, and asset performance.
GET /bollinger/magnificent7 Magnificent 7 dashboard — AAPL, MSFT, GOOGL, AMZN, NVDA, META, TSLA side-by-side.
GET /bollinger Bollinger Bands — dual split-chart view with configurable ticker, period (1M–5Y), MA period, and std dev.
GET /bollinger/cryptomarkets Crypto markets — live coin list panel with price chart and volume overlay.
GET /events Historical events — overlays major market events on stock price charts.
GET /elections Election cycles — stock performance around presidential election dates.
Natural Language → SQL NlSqlController 🔒 Auth required
Method Route Description
GET /nlsql NL→SQL interface — chat-style input, example picker, Ollama/OpenRouter/Both provider selector, live SQL display, tabular results, and optional Plotly chart.
Documentation Static HTML
Method Route Description
GET /docs/dbt_pipeline_diagram.html dbt pipeline diagram — visual overview of the stock data transformation pipeline.
GET /docs/project-overview.html This page — project overview, migration story, architecture, and endpoint reference.

Backend Routes

The ASP.NET Core app proxies all data requests to the Go microservice on port 8001. The NL→SQL controller exposes its own JSON endpoints for the browser to call directly.

Stock Data Proxy /bollinger/* → Go :8001 proxy
Method Route Description
GET /bollinger/countries G20 countries available in the stock database.
GET /bollinger/sectors?country= Market sectors, optionally filtered by country.
GET /bollinger/tickers?country=&sector= Ticker list filtered by country and/or sector.
GET /bollinger/data?ticker=&days=&period=&stddev= Bollinger band OHLC + band data. Default: days=365, period=20, stddev=2.0.
GET /bollinger/indices Major market indices (S&P 500, NASDAQ, etc.).
GET /bollinger/forex Forex currency pairs and rates.
GET /bollinger/crypto Cryptocurrency price data.
GET /bollinger/observatory/totals Summary totals for the observatory dashboard.
GET /bollinger/observatory/daily Daily market activity snapshot.
GET /bollinger/observatory/sectors Sector-level aggregated performance.
GET /bollinger/observatory/countries Country-level aggregated performance.
GET /bollinger/observatory/assets Asset-class breakdown from the observatory.
GET /bollinger/events/list List of catalogued market events.
GET /bollinger/events/data?ticker=&start_date=&end_date= Stock price data for a ticker around a specific event window.
GET /bollinger/elections/list List of tracked election dates by country.
GET /bollinger/elections/data?ticker=&days_before=730 Price data centred on election dates for a given ticker.
NL → SQL API NlSqlController · JSON 🔒 Auth required
Method Route Description
GET /nlsql/modelinfo Returns configured LLM model names for Ollama and OpenRouter.
POST /nlsql/generate LLM inference — converts a natural language question to SQL.
Body: { question, history[], provider }
POST /nlsql/query Database execution — runs a validated SELECT against PostgreSQL. Max 500 rows.
Body: { sql }

Running Services

All services co-located on the Raspberry Pi 5, managed by systemd.

ASP.NET Core 10 LIVE
Main web application. Razor MVC with Kestrel. Handles authentication, Power BI embedding, view rendering, and API proxying.
Port5050
ArchARM64 · Ubuntu
Managedsystemd
🐹 Go Stock API LIVE
Microservice written in Go. Provides all Bollinger band calculations, observatory data, events, elections, forex, and crypto endpoints directly from PostgreSQL.
Port8001
DBPostgreSQL · stocks_mart
Managedsystemd / Docker
🐘 PostgreSQL LIVE
Primary database. Stores stock prices, technical indicators (MA, MACD, Bollinger), and stock metadata. Fed by an automated dbt pipeline from external data sources.
Schemadbt_stocks.stocks_mart
DriverNpgsql 10.0.2
NL→SQLread-only · 500 row cap
🤖 Ollama LOCAL
Local LLM inference engine running on-device. Used for NL→SQL generation without sending data to the cloud. Model: qwen2.5-coder:7b.
Modelqwen2.5-coder:7b
Privacyfully local · no cloud
🌐 OpenRouter CLOUD
Cloud LLM gateway. Used as a secondary provider for NL→SQL, or in "Both" mode for side-by-side comparison against local Ollama.
Modeldeepseek/deepseek-chat
ModeOllama · OpenRouter · Both
📊 Power BI (Microsoft) CLOUD
Embedded analytics platform. Service Principal with MSAL token acquisition. Embed V2 tokens support both standard and paginated (RDL) reports.
AuthService Principal · AAD
TokenEmbed V2 · auto-refresh
ProtectedPROD workspace (OIDC)
☁️ Cloudflare Tunnel LIVE
Secure zero-trust tunnel from Cloudflare's edge to the Pi. No inbound firewall ports required. Handles TLS termination and sets X-Forwarded-Proto for ASP.NET Core's HTTPS redirect logic.
Ingresscloudflared · systemd
TLSedge-terminated · HTTPS