AI-powered brand analytics for retail & consumer goods
Retail Pulse is an AI-powered brand intelligence platform that uses agentic AI to analyze depletion trends, shipment dynamics, and field sentiment for retail & CPG brands. A multi-agent system powered by the Microsoft AI Framework (MAF) and Model Context Protocol (MCP) reasons over natural-language questions, delegates to specialist agents, and calls MCP tools to fetch data, streaming every step back to the browser with full distributed tracing.
Key differentiator: Retail Pulse is tenant-configurable. Define your company, brands, regions, and theme in a single tenant.yaml file and the entire platform adapts. No code changes required.
Built with: .NET Aspire, Microsoft AI Framework (MAF), Model Context Protocol (MCP), React + Vite, Azure Bot Framework, Azure API Management (AI Gateway).
| Project | Purpose |
|---|---|
| RetailPulse.AppHost | Aspire orchestrator - wires McpServer → Api → TeamsBot → Frontend |
| RetailPulse.Api | Minimal API + AI agent (Azure OpenAI via APIM), SignalR telemetry hub |
| RetailPulse.McpServer | MCP tool host - SQLite-backed depletions, shipments, sentiment (read + write) |
| RetailPulse.Contracts | Shared DTOs + tenant config model |
| RetailPulse.ServiceDefaults | OTel, health checks, resilience defaults |
| RetailPulse.TeamsBot | Microsoft Agents SDK - calls API, renders adaptive cards |
| RetailPulse.Web | React/Vite/TypeScript dashboard - Fluent UI, Recharts, SignalR |
- Tenant config (
tenant.yaml) drives everything - prompts, data seeding, UI branding. Loaded byFileTenantProvider, injected into system prompts. - AI Gateway - APIM fronts Azure OpenAI/Foundry with token limiting, metrics, managed identity auth. Deployed via Bicep.
- Real-time telemetry - SignalR hub broadcasts agent spans to the frontend. Dashboard shows live tool calls, agent thoughts, and timing.
- MCP tools - SQLite-backed retail metrics (depletions, shipments, field sentiment) shaped by tenant brands/regions. Agent can read and write data via
UpdateMetricstool. - Foundry delegation - can hand off to persistent Azure AI Foundry agents for deeper analysis.
- Frontend - single-page dashboard with ChatPanel, suggested retail prompts (grocery, QSR, home improvement, office supply, furniture), chart rendering, and span timeline.
Retail Pulse is designed for industries using a Three-Tier distribution model (manufacturer → distributor → retailer). The AI agent can detect pipeline clogs - where shipments and sell-through diverge - and correlate them with field sentiment data.
- .NET 10 SDK
- Node.js 20+
- An OpenAI API key (or Azure OpenAI endpoint)
git clone https://github.com/swigerb/retail-pulse.git
cd retail-pulseThe repo ships with a sample tenant.yaml for Apex Retail Group, a fictional multi-category retail conglomerate with 12 brands across 6 categories. To customize for your own brand, see the Tenant Configuration Guide.
dotnet user-secrets set "OpenAI:ApiKey" "<your-api-key>" --project src/RetailPulse.ApiTo use Azure OpenAI directly (bypassing APIM), also set the endpoint:
dotnet user-secrets set "OpenAI:Endpoint" "<your-azure-openai-endpoint>" --project src/RetailPulse.Api
# Install frontend dependencies (first time only)
cd src/RetailPulse.Web && npm install && cd ../..
# Start the full stack
dotnet run --project src/RetailPulse.AppHostNavigate to http://localhost:5173 and start asking questions!
Try these queries (using the Apex Retail Group sample tenant):
🥃 Spirits:
- "How is Sierra Gold Tequila performing in the Northeast?"
- "Analyze the shipment pipeline for Ridgeline Bourbon in the Midwest"
🛒 Grocery:
- "How are FreshMart depletions trending in the Northeast this quarter?"
- "Compare Harvest Table vs FreshMart sell-through rates by region"
🍔 Quick-Serve Restaurants:
- "How is Apex Grill performing in the Southwest this quarter?"
- "Compare Coastline Tacos vs Apex Grill depletions across all regions"
🏠 Home Improvement:
- "Show me Pinnacle Hardware depletion stats in the Midwest for Q1"
- "How is Summit Outdoor performing in the Southeast vs West Coast?"
📎 Office Supply:
- "How are ClearDesk depletions trending in the Northeast this quarter?"
🛋️ Furniture:
- "Show me Urban Living depletion trends across all regions this quarter"
- "Compare Foundry Home vs Urban Living performance in the West Coast"
📈 Chart Rendering (test all chart types):
- "Create a line chart showing Sierra Gold Tequila depletion trends across all regions" → line chart
- "Show me a bar chart comparing depletion velocity for all spirits brands in the Northeast" → bar chart
- "Create a pie chart showing market share breakdown for our grocery brands nationally" → pie chart
- "Show a grouped bar chart comparing FreshMart and Harvest Table across all regions" → grouped bar
- "Create a donut chart of Apex Grill's variant mix in the Southwest" → donut chart
- "Show a horizontal bar chart ranking all brands by depletion growth rate" → horizontal bar
- "Create a table showing depletion stats for all home improvement brands by region" → table
- "Show a gauge chart for Pinnacle Hardware's inventory health in the Midwest" → gauge
# Windows
.\deploy\deploy.ps1
# Linux/Mac
./deploy/deploy.shRetail Pulse reads tenant.yaml at the repo root to configure the entire platform:
company: "Apex Retail Group"
industry: "Multi-Category Retail"
brands:
- name: "Sierra Gold Tequila"
category: "Spirits"
variants: ["Blanco", "Reposado", "Añejo", "Extra Añejo"]
priceSegment: "Premium"
- name: "FreshMart"
category: "Grocery"
variants: ["Organic Produce", "Bakery", "Deli", "Frozen"]
priceSegment: "Standard"
- name: "Apex Grill"
category: "Quick-Serve Restaurant"
variants: ["Burgers", "Chicken", "Breakfast", "Beverages"]
priceSegment: "Standard"
# ... 12 brands across 6 categories
regions:
- "Northeast"
- "Southeast"
- "Midwest"
- "Southwest"
- "West Coast"
- "Pacific Northwest"
theme:
primaryColor: "#1B4D7A"
accentColor: "#E8A838"The included Apex Retail Group sample tenant demonstrates a multi-category retail conglomerate with 12 brands across 6 categories:
| Category | Brands |
|---|---|
| 🥃 Spirits | Sierra Gold Tequila, Ridgeline Bourbon, Summit Vodka |
| 🛒 Grocery | FreshMart, Harvest Table |
| 🍔 Quick-Serve Restaurants | Apex Grill, Coastline Tacos |
| 🏠 Home Improvement | Pinnacle Hardware, Summit Outdoor |
| 📎 Office Supply | ClearDesk |
| 🛋️ Furniture | Urban Living, Foundry Home |
All brands operate across 6 regions: Northeast, Southeast, Midwest, Southwest, West Coast, and Pacific Northwest. See the Tenant Configuration Guide for full schema reference and examples for different industries.
| Layer | Technology | Version | Purpose |
|---|---|---|---|
| Orchestration | .NET Aspire | 13.3.0 | Service discovery, health checks, dashboard |
| Runtime | .NET | 10 | Backend services |
| Agent | Microsoft AI Framework (MAF) | — | AI agent with tool calling |
| Model | GPT-5.4-mini (via APIM AI Gateway) | — | Reasoning and natural language |
| Tools | Model Context Protocol (MCP) | — | Standardized tool access |
| Data | SQLite (Microsoft.Data.Sqlite) | — | Mutable tenant-seeded metrics store |
| Frontend | React + Vite + TypeScript | 19 / 8 / 6 | Interactive dashboard |
| UI Components | Fluent UI React | 9.x | Design system |
| Real-time | SignalR | 10.x | Live telemetry streaming |
| Multi-Agent | Azure AI Foundry Agent Service | — | Foundry-hosted Shipment Specialist (optional) |
| Observability | OpenTelemetry + Aspire Dashboard | — | Distributed traces, metrics, logs |
| Monitoring | Azure Application Insights | — | Production telemetry and traces |
| Gateway | Azure API Management | — | Token metering, rate limiting, audit |
| Testing | xUnit + Vitest | — | Backend + frontend tests |
retail-pulse/
├── tenant.yaml # Tenant configuration (brands, regions, theme)
├── RetailPulse.slnx # Solution file
├── src/
│ ├── RetailPulse.AppHost/ # Aspire 13.3.0 orchestrator
│ ├── RetailPulse.Api/ # Agent API service
│ │ ├── Agents/ # MAF agent implementation
│ │ ├── Caching/ # MCP response cache (DelegatingHandler)
│ │ ├── Consensus/ # Multi-agent council orchestration
│ │ ├── Health/ # Readiness/liveness health checks
│ │ ├── Hubs/ # SignalR telemetry hub (session-scoped groups)
│ │ ├── Middleware/ # Exception handling, correlation ID, security headers, auth
│ │ ├── Prompts/ # PromptTemplateEngine (tenant hydration)
│ │ ├── Security/ # Audit log, security services
│ │ ├── Telemetry/ # Custom business metrics (OpenTelemetry)
│ │ ├── Tools/ # MCP tool wrappers
│ │ ├── Validation/ # Input validation (ChatRequestValidator)
│ │ └── prompts.yaml # Agent prompt configuration (tenant-templated)
│ ├── RetailPulse.McpServer/ # MCP server (data tools)
│ │ ├── Tools/ # MCP tool definitions (parameterized queries)
│ │ └── Data/ # SQLite-backed tenant-driven metrics
│ ├── RetailPulse.Contracts/ # Shared models (immutable config, ChartSpec, etc.)
│ │ └── ValueObjects/ # BrandName, Region, SessionId
│ ├── RetailPulse.ServiceDefaults/ # Shared Aspire defaults (OTel, health, resilience)
│ ├── RetailPulse.TeamsBot/ # Microsoft Teams bot (JWT-validated, Adaptive Cards)
│ └── RetailPulse.Web/ # React/Vite/TypeScript frontend
│ ├── src/components/ # ChatPanel, SpanTimeline, Charts, ErrorBoundary
│ └── src/hooks/ # SignalR connection, telemetry
├── tests/
│ ├── RetailPulse.Tests/ # xUnit + integration tests (1815 passing)
│ ├── RetailPulse.LoadTests/ # NBomber load test scenarios
│ └── RetailPulse.Benchmarks/ # BenchmarkDotNet performance suite
├── deploy/ # Deployment & infrastructure
│ ├── deploy.ps1 / deploy.sh # One-click local deployment scripts
│ ├── apim-ai-gateway/ # APIM AI Gateway Bicep (main.bicep, policy.xml)
│ ├── foundry-agent/ # Foundry agent deployment
│ └── generate-traffic.ps1 # Load testing
├── infra/ # Azure infrastructure (Bicep, used by azd)
│ ├── main.bicep # Subscription-scoped orchestrator
│ └── modules/ # App Insights, Container Apps Env, App Service
├── azd-hooks/ # Azure Developer CLI lifecycle hooks
├── azure.yaml # Azure Developer CLI project file
├── ai-gateway-dev-portal/ # AI Gateway Dev Portal (APIM observability)
└── docs/ # Documentation
Retail Pulse can be deployed as a Microsoft Teams bot with Adaptive Card responses, SSO authentication, and chart visualizations rendered inline.
See Teams Setup Guide for step-by-step instructions.
Charts are rendered client-side. The LLM emits structured ChartSpec JSON and each client renders natively:
- Web UI - Interactive Recharts SVG charts
- Teams - Native Adaptive Card chart elements
9 chart types: line, bar, grouped bar, stacked bar, horizontal bar, pie, donut, gauge, and table. See Chart Rendering Guide.
Route all LLM calls through Azure API Management for token metering, rate limiting, and governance. See AI Gateway Integration.
Deploy a specialist agent to Azure AI Foundry for Three-Tier Distribution pipeline analysis. Disabled by default - the app runs fully without it using a local analyzer. See Architecture.
Retail Pulse implements enterprise-grade patterns:
- Resilience — Circuit breaker (5 failures/30s), retry with exponential backoff + jitter, dead-letter queue
- Observability — Correlation IDs, custom OpenTelemetry metrics, SLO/SLI definitions, health checks
- Security — CSP/HSTS/X-Frame-Options headers, input validation, SHA256 hash-chain audit log
- Performance — MCP response cache, keyword fast-path routing, lightweight council voting, cache warming
- API Versioning —
/api/v1/chatwith Sunset header on legacy endpoint - Testing — 1815+ unit/integration/contract/E2E tests, load tests, mutation testing, benchmarks
See the complete demo script for a step-by-step presentation guide (~10 minutes).
The fastest way to deploy Retail Pulse to Azure:
azd auth login
azd upThis deploys:
- Backend (API, McpServer, TeamsBot) → Azure Container Apps
- Frontend (React/Vite) → Azure App Service (Node 20 LTS)
- Monitoring → Application Insights + Log Analytics
See docs/deployment-azd.md for full documentation.
The deploy/apim-ai-gateway/ directory contains Bicep templates to deploy Azure API Management as an AI Gateway fronting Azure OpenAI:
cd deploy/apim-ai-gateway
.\deploy-apim-api.ps1This deploys:
- main.bicep — APIM instance with managed identity
- policy.xml — Token metering, rate limiting, content safety policies
- role-assignment.bicep — RBAC for APIM → Azure OpenAI access
- a2a-api.bicep / mcp-api.bicep — Agent-to-agent and MCP API definitions
# Windows
.\deploy\deploy.ps1
# Linux/Mac
./deploy/deploy.shNote: Deployment scripts use user secrets for all credentials — no API keys are stored in source.
- Bicep outputs do not expose secrets or APIM subscription keys
- Diagnostic settings (App Insights, Log Analytics) are deployed alongside resources
- Application Insights connection strings are configured in the AppHost, not checked into
appsettings.json
The CI pipeline runs on every push and PR to main:
| Job | What it does |
|---|---|
| build | Restore, build, test (.NET 10) with coverage |
| frontend | npm ci, build, vitest |
| security | Check for vulnerable NuGet packages |
| lint | Verify code style (dotnet format --verify-no-changes) |
# Full backend build + test
dotnet build RetailPulse.slnx
dotnet test RetailPulse.slnx --verbosity quiet
# Frontend
cd src/RetailPulse.Web && npm run build && npx vitest run
# Load tests (optional)
cd tests/RetailPulse.LoadTests && dotnet run -c Release
# Benchmarks (optional)
dotnet run -c Release --project tests/RetailPulse.Benchmarks| Area | Implementation |
|---|---|
| API Authentication | Auth middleware on all API endpoints |
| Teams Bot | JWT token validation on incoming activities |
| MCP Server | Parameterized SQL queries (no string interpolation) |
| SignalR | Telemetry scoped to session groups (no cross-session leakage) |
| Secrets | App Insights keys in AppHost only; user secrets for API keys |
| Frontend | CSP headers, URL scheme validation in Adaptive Cards |
| Sessions | 2-hour TTL with automatic eviction via SessionManager |
| Config | Immutable config classes (IReadOnlyList) with input validation |
The SignalR TelemetryHub streams agent execution spans to connected clients in real time. Clients join session-scoped groups so telemetry is isolated per conversation.
What gets streamed:
- Agent thought process and reasoning steps
- MCP tool calls with arguments and results
- Token usage and cost estimates (per-model pricing in
appsettings.json) - Timing data for each span
The React dashboard renders these as an interactive span timeline alongside the chat panel.
| Setting | User Secret Key | Default |
|---|---|---|
| API Key | OpenAI:ApiKey |
(required) |
| LLM Endpoint | OpenAI:Endpoint |
APIM gateway URL |
| API Version | OpenAI:ApiVersion |
2025-03-01-preview |
| MCP Server URL | McpServer:BaseUrl |
http://localhost:5200 |
| Foundry Enabled | FoundryAgent:Enabled |
false |
| Foundry Project Endpoint | FoundryAgent:ProjectEndpoint |
(set by deploy script) |
| Foundry Agent Name | FoundryAgent:ShipmentAgentName |
Distribution Analysis Specialist |
| App Insights | APPLICATIONINSIGHTS_CONNECTION_STRING |
(set in AppHost) |
All tenant configuration lives in tenant.yaml at the repo root. Changes take effect on restart — no code changes required.
| Key | Purpose |
|---|---|
company / industry |
Company identity, injected into agent system prompts |
brands[] |
Brand definitions with category, variants, and price segment |
regions[] |
Geographic regions for data segmentation |
channels[] |
Distribution channels (On-Premise, Off-Premise, E-Commerce) |
theme |
UI branding (primary/accent colors, logo, font) |
distribution |
Distribution model config (Three-Tier, distributor types) |
| Service | Port | URL |
|---|---|---|
| React Frontend | 5173 | http://localhost:5173 |
| Retail Pulse API | 5100 | http://localhost:5100 |
| MCP Server | 5200 | http://localhost:5200 |
| Teams Bot | 5300 | http://localhost:5300 |
| Aspire Dashboard | dynamic | See terminal output for login URL |
1815+ tests passing across xUnit (.NET), Vitest (frontend), load tests, and benchmarks. Covers agent telemetry, chart/tool behavior, prompt config, tenant validation, simulated metrics, session management (TTL eviction), SignalR session-group broadcasting, Teams Adaptive Card builders, and performance profiling.
# Run all .NET tests
dotnet test
# Run frontend tests
cd src/RetailPulse.Web && npm testSee Testing Guide for manual testing options and test scenarios.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT - see LICENSE for details.
This project is for demonstration purposes. All data is fictional, seeded from tenant.yaml, and does not represent actual business data.

