# methos237/dealer-portal-ai-assistant architecture

> Architecture diagram of the GitHub repository methos237/dealer-portal-ai-assistant, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-30). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/methos237/dealer-portal-ai-assistant
- Repository: https://github.com/methos237/dealer-portal-ai-assistant

## Overview

The product is a multi-tenant RV dealer portal with an embedded, citation-producing assistant. Dealers sign in, browse units and documents, file warranty claims or parts orders, and view reports; assistant answers stream from retrieved documents and live portal tools, while draft writes require confirmation in the browser. The graph includes ingestion and the separate Microsoft 365 MCP connector as documented capabilities. Several web and API subsystems are represented by their tree paths because their implementation excerpts were not provided; edges rely on the README or indexed references where noted.

Main entry points: [`web/src/app/(portal)`](https://github.com/methos237/dealer-portal-ai-assistant/tree/master/web/src/app/(portal)) (Portal web app), [`api/src/DealerPortal.Api/Endpoints/PortalEndpoints.cs`](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/api/src/DealerPortal.Api/Endpoints/PortalEndpoints.cs) (Portal endpoints), [`assistant/app/chat.py`](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/assistant/app/chat.py) (Assistant API), [`assistant/app/agent.py`](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/assistant/app/agent.py) (Agent and tool loop)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_portal["Dealer portal"]
  node_browser["Portal web app"]
  node_portal_features["Units, claims, orders"]
  node_offline_drafts["Offline claim drafts<br/>[DraftReplayer.tsx]"]
  node_report_ui["Reports UI<br/>[page.tsx]"]
  node_assistant_ui["Assistant panel<br/>[AssistantPanel.tsx]"]
end

subgraph group_api["Portal API"]
  node_api_routes["Portal endpoints<br/>[PortalEndpoints.cs]"]
  node_api_auth["Identity and tenancy<br/>[CurrentUser.cs]"]
  node_portal_db[("Portal database<br/>[PortalDbContext.cs]")]
  node_api_reports["Report service<br/>[PowerBiClient.cs]"]
  node_portal_mcp["Portal MCP tools<br/>[PortalTools.cs]"]
end

subgraph group_assistant["AI assistant"]
  node_assistant_api["Assistant API<br/>[chat.py]"]
  node_assistant_auth["Caller validation<br/>[auth.py]"]
  node_agent["Agent and tool loop<br/>[agent.py]"]
  node_retrieval["Hybrid retrieval<br/>[retrieval.py]"]
  node_rag_store[("RAG document index<br/>[retrieval.py]")]
end

subgraph group_knowledge["Knowledge ingestion"]
  node_ingestion["Document ingestion<br/>[ingest.py]"]
  node_scheduled_ingest["Ingestion trigger<br/>[function_app.py]"]
end

subgraph group_integrations["External integrations"]
  node_m365_mcp["M365 MCP server<br/>[server.ts]"]
  node_graph_connector["SharePoint connector<br/>[graph.ts]"]
  node_fabric_connector["Fabric query tools<br/>[powerbi.ts]"]
  node_entra["Microsoft Entra ID"]
  node_claude["Claude model"]
  node_postgres[("PostgreSQL with pgvector")]
  node_sharepoint["SharePoint libraries"]
  node_fabric["Fabric semantic model"]
end

node_dealer(("Dealer user"))
node_browser_client(("Browser client"))
node_mcp_client(("Claude Desktop / Code"))

node_dealer -->|"uses"| node_browser
node_browser -->|"signs in"| node_entra
node_browser -->|"presents"| node_portal_features
node_browser -->|"calls with token"| node_api_routes
node_browser -->|"streams chat"| node_assistant_api
node_browser -->|"stores offline"| node_offline_drafts
node_offline_drafts -->|"replays writes"| node_api_routes
node_browser -->|"shows reports"| node_report_ui
node_api_routes -->|"uses caller context"| node_api_auth
node_api_routes -->|"reads and writes"| node_portal_db
node_api_auth -->|"scopes queries"| node_portal_db
node_report_ui -->|"requests summary"| node_api_reports
node_api_reports -->|"queries DAX"| node_fabric
node_api_routes -->|"exposes tools"| node_portal_mcp
node_mcp_client -->|"calls tools"| node_portal_mcp
node_assistant_api -->|"validates caller"| node_assistant_auth
node_assistant_api -->|"runs turn"| node_agent
node_agent -->|"retrieves chunks"| node_retrieval
node_retrieval -->|"queries hybrid index"| node_rag_store
node_assistant_api -->|"checks index metadata"| node_postgres
node_agent -->|"streams model calls"| node_claude
node_agent -->|"calls with user token"| node_portal_mcp
node_assistant_auth -->|"resolves dealer"| node_api_routes
node_scheduled_ingest -->|"triggers indexing"| node_ingestion
node_ingestion -->|"embeds and upserts"| node_rag_store
node_scheduled_ingest -->|"fetches document changes"| node_sharepoint
node_mcp_client -->|"connects over MCP"| node_m365_mcp
node_m365_mcp -->|"registers document tools"| node_graph_connector
node_graph_connector -->|"browses and reads"| node_sharepoint
node_m365_mcp -->|"registers query tool"| node_fabric_connector
node_fabric_connector -->|"executes DAX"| node_fabric

click node_browser "https://github.com/methos237/dealer-portal-ai-assistant/tree/master/web/src/app/(portal)"
click node_portal_features "https://github.com/methos237/dealer-portal-ai-assistant/tree/master/web/src/app/(portal)"
click node_offline_drafts "https://github.com/methos237/dealer-portal-ai-assistant/blob/master/web/src/components/DraftReplayer.tsx"
click node_report_ui "https://github.com/methos237/dealer-portal-ai-assistant/blob/master/web/src/app/(portal)/reports/page.tsx"
click node_assistant_ui "https://github.com/methos237/dealer-portal-ai-assistant/blob/master/web/src/components/AssistantPanel.tsx"
click node_api_routes "https://github.com/methos237/dealer-portal-ai-assistant/blob/master/api/src/DealerPortal.Api/Endpoints/PortalEndpoints.cs"
click node_api_auth "https://github.com/methos237/dealer-portal-ai-assistant/blob/master/api/src/DealerPortal.Api/Auth/CurrentUser.cs"
click node_portal_db "https://github.com/methos237/dealer-portal-ai-assistant/blob/master/api/src/DealerPortal.Api/Data/PortalDbContext.cs"
click node_api_reports "https://github.com/methos237/dealer-portal-ai-assistant/blob/master/api/src/DealerPortal.Api/Reports/PowerBiClient.cs"
click node_portal_mcp "https://github.com/methos237/dealer-portal-ai-assistant/blob/master/api/src/DealerPortal.Api/Mcp/PortalTools.cs"
click node_assistant_api "https://github.com/methos237/dealer-portal-ai-assistant/blob/master/assistant/app/chat.py"
click node_assistant_auth "https://github.com/methos237/dealer-portal-ai-assistant/blob/master/assistant/app/auth.py"
click node_agent "https://github.com/methos237/dealer-portal-ai-assistant/blob/master/assistant/app/agent.py"
click node_retrieval "https://github.com/methos237/dealer-portal-ai-assistant/blob/master/assistant/rag/retrieval.py"
click node_rag_store "https://github.com/methos237/dealer-portal-ai-assistant/blob/master/assistant/rag/retrieval.py"
click node_ingestion "https://github.com/methos237/dealer-portal-ai-assistant/blob/master/assistant/rag/ingest.py"
click node_scheduled_ingest "https://github.com/methos237/dealer-portal-ai-assistant/blob/master/functions/function_app.py"
click node_m365_mcp "https://github.com/methos237/dealer-portal-ai-assistant/blob/master/mcp-m365/src/server.ts"
click node_graph_connector "https://github.com/methos237/dealer-portal-ai-assistant/blob/master/mcp-m365/src/graph.ts"
click node_fabric_connector "https://github.com/methos237/dealer-portal-ai-assistant/blob/master/mcp-m365/src/powerbi.ts"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_browser,node_portal_features,node_offline_drafts,node_report_ui,node_assistant_ui,node_dealer,node_browser_client toneBlue
class node_api_routes,node_api_auth,node_portal_db,node_api_reports,node_portal_mcp toneAmber
class node_assistant_api,node_assistant_auth,node_agent,node_retrieval,node_rag_store toneMint
class node_ingestion,node_scheduled_ingest toneRose
class node_m365_mcp,node_graph_connector,node_fabric_connector,node_entra,node_claude,node_postgres,node_sharepoint,node_fabric,node_mcp_client toneIndigo
```

## Components

### Dealer portal

- [Portal web app](https://github.com/methos237/dealer-portal-ai-assistant/tree/master/web/src/app/(portal)): `web/src/app/(portal)`
- [Units, claims, orders](https://github.com/methos237/dealer-portal-ai-assistant/tree/master/web/src/app/(portal)): `web/src/app/(portal)`
- [Offline claim drafts](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/web/src/components/DraftReplayer.tsx): `web/src/components/DraftReplayer.tsx`
- [Reports UI](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/web/src/app/(portal)/reports/page.tsx): `web/src/app/(portal)/reports/page.tsx`
- [Assistant panel](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/web/src/components/AssistantPanel.tsx): `web/src/components/AssistantPanel.tsx`

### Portal API

- [Portal endpoints](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/api/src/DealerPortal.Api/Endpoints/PortalEndpoints.cs): `api/src/DealerPortal.Api/Endpoints/PortalEndpoints.cs`
- [Identity and tenancy](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/api/src/DealerPortal.Api/Auth/CurrentUser.cs): `api/src/DealerPortal.Api/Auth/CurrentUser.cs`
- [Portal database](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/api/src/DealerPortal.Api/Data/PortalDbContext.cs): `api/src/DealerPortal.Api/Data/PortalDbContext.cs`
- [Report service](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/api/src/DealerPortal.Api/Reports/PowerBiClient.cs): `api/src/DealerPortal.Api/Reports/PowerBiClient.cs`
- [Portal MCP tools](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/api/src/DealerPortal.Api/Mcp/PortalTools.cs): `api/src/DealerPortal.Api/Mcp/PortalTools.cs`

### AI assistant

- [Assistant API](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/assistant/app/chat.py): `assistant/app/chat.py`
- [Caller validation](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/assistant/app/auth.py): `assistant/app/auth.py`
- [Agent and tool loop](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/assistant/app/agent.py): `assistant/app/agent.py`
- [Hybrid retrieval](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/assistant/rag/retrieval.py): `assistant/rag/retrieval.py`
- [RAG document index](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/assistant/rag/retrieval.py): `assistant/rag/retrieval.py`

### Knowledge ingestion

- [Document ingestion](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/assistant/rag/ingest.py): `assistant/rag/ingest.py`
- [Ingestion trigger](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/functions/function_app.py): `functions/function_app.py`

### External integrations

- [M365 MCP server](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/mcp-m365/src/server.ts): `mcp-m365/src/server.ts`
- [SharePoint connector](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/mcp-m365/src/graph.ts): `mcp-m365/src/graph.ts`
- [Fabric query tools](https://github.com/methos237/dealer-portal-ai-assistant/blob/master/mcp-m365/src/powerbi.ts): `mcp-m365/src/powerbi.ts`
- **Microsoft Entra ID**
- **Claude model**
- **PostgreSQL with pgvector**
- **SharePoint libraries**
- **Fabric semantic model**

### Other components

- **Dealer user**
- **Browser client**
- **Claude Desktop / Code**

## Connections

- Dealer user → Portal web app: uses (evidence: `README.md`)
- Portal web app → Microsoft Entra ID: signs in (evidence: `README.md`)
- Portal web app → Units, claims, orders: presents (evidence: `README.md`)
- Portal web app → Portal endpoints: calls with token (evidence: `README.md`)
- Portal web app → Assistant API: streams chat (evidence: `README.md`)
- Portal web app → Offline claim drafts: stores offline (evidence: `README.md`)
- Offline claim drafts → Portal endpoints: replays writes (evidence: `README.md`)
- Portal web app → Reports UI: shows reports (evidence: `README.md`)
- Portal endpoints → Identity and tenancy: uses caller context (evidence: `api/src/DealerPortal.Api/Endpoints/PortalEndpoints.cs`)
- Portal endpoints → Portal database: reads and writes (evidence: `api/src/DealerPortal.Api/Endpoints/PortalEndpoints.cs`)
- Identity and tenancy → Portal database: scopes queries (evidence: `api/src/DealerPortal.Api/Data/PortalDbContext.cs`)
- Reports UI → Report service: requests summary (evidence: `README.md`)
- Report service → Fabric semantic model: queries DAX (evidence: `api/src/DealerPortal.Api/Reports/PowerBiClient.cs`)
- Portal endpoints → Portal MCP tools: exposes tools (evidence: `api/src/DealerPortal.Api/Mcp/PortalTools.cs`)
- Claude Desktop / Code → Portal MCP tools: calls tools (evidence: `README.md`)
- Assistant API → Caller validation: validates caller (evidence: `assistant/app/chat.py`)
- Assistant API → Agent and tool loop: runs turn (evidence: `assistant/app/chat.py`)
- Agent and tool loop → Hybrid retrieval: retrieves chunks (evidence: `assistant/app/agent.py`)
- Hybrid retrieval → RAG document index: queries hybrid index (evidence: `assistant/rag/retrieval.py`)
- Assistant API → PostgreSQL with pgvector: checks index metadata
- Agent and tool loop → Claude model: streams model calls (evidence: `README.md`)
- Agent and tool loop → Portal MCP tools: calls with user token (evidence: `assistant/app/agent.py`)
- Caller validation → Portal endpoints: resolves dealer (evidence: `assistant/app/auth.py`)
- Ingestion trigger → Document ingestion: triggers indexing (evidence: `functions/function_app.py`)
- Document ingestion → RAG document index: embeds and upserts (evidence: `assistant/rag/ingest.py`)
- Ingestion trigger → SharePoint libraries: fetches document changes (evidence: `README.md`)
- Claude Desktop / Code → M365 MCP server: connects over MCP (evidence: `README.md`)
- M365 MCP server → SharePoint connector: registers document tools (evidence: `mcp-m365/src/server.ts`)
- SharePoint connector → SharePoint libraries: browses and reads (evidence: `README.md`)
- M365 MCP server → Fabric query tools: registers query tool (evidence: `mcp-m365/src/server.ts`)
- Fabric query tools → Fabric semantic model: executes DAX (evidence: `README.md`)
