feat(01-03): implement echo chat UI with MudBlazor

Add ChatGPT-style chat interface using MudBlazor components. User messages
display on the right (purple), bot echoes "success msg!" on the left.
Includes app bar, centered 768px layout, bottom-anchored messages, and
documented inline comments on every Blazor concept introduced.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
local
2026-04-03 01:51:53 +01:00
parent 7dd4243f01
commit 711df97ce9
14 changed files with 545 additions and 143 deletions

96
ARCHITECTURE.md Normal file
View File

@@ -0,0 +1,96 @@
# Architecture Decisions
## Blazor Hosting Model: Server vs WebAssembly
### How They Differ
| Aspect | Blazor Server | Blazor WASM |
|--------|--------------|-------------|
| Code runs | On the server | In the browser |
| UI updates | Via SignalR WebSocket (server pushes diffs) | Locally in browser (no round-trip) |
| Calling backend services | Direct — code is already server-side | Needs HTTP calls if accessing server resources |
| Offline capable | No (requires persistent connection) | Yes |
| Startup speed | Fast | Slower (downloads .NET runtime to browser) |
### Decision: Blazor WASM
This project uses **Blazor WebAssembly (standalone)** with a separate ASP.NET Core Web API backend.
## When Do You Need a Separate API Project?
There are two distinct concerns that are easy to conflate:
### 1. Consuming an External API (e.g. OpenAI)
Both Blazor Server and WASM can call external APIs directly from C# — no controller needed. The difference is **where that code executes**:
- **Blazor Server**: Code runs on the server. A service class calls OpenAI directly. API keys live safely in server memory. No controller, no exposed endpoint required.
- **Blazor WASM**: Code runs in the browser. You *can* call OpenAI directly, but any **API key would be embedded in the browser download** — anyone could inspect it via browser dev tools. This is the primary reason to add a backend proxy.
### 2. Exposing an API Endpoint (e.g. ChatAgent.Api)
This is a separate concern. You expose an API endpoint when:
- Another application needs to communicate with your chat system
- You want a REST API for mobile clients, scripts, or integrations
- You need a server-side proxy to protect secrets from the browser (the WASM case above)
**Key insight:** You don't need an API endpoint to *use* an external service. You only need one in WASM to **keep secrets out of the browser**.
### 3. Component Updates Do Not Require an API
In both hosting models, Blazor components update themselves locally:
- Components hold state in fields/properties
- Calling `StateHasChanged()` triggers a re-render
- Components can call injected C# services directly
- No HTTP round-trip is needed for UI updates
For example, a chat component that echoes "success msg!" back needs no API at all — a simple injected service handles it entirely within the client project.
## API Key Management Scenarios
The need for an API project in WASM depends on how secrets are managed:
| Scenario | WASM needs API project? | Why |
|----------|------------------------|-----|
| Raw API key in config | Yes | To keep the key out of browser-downloadable code |
| Azure Key Vault | Yes | Browser sandbox cannot access Key Vault or managed identity |
| API Management gateway (Azure APIM) with token auth | No | WASM calls the gateway directly; gateway handles auth via managed identity |
| Blazor Server (any scenario) | No | Code is already server-side; secrets never leave the server |
### Enterprise Pattern: API Gateway
In enterprise environments, a common pattern avoids the need for a custom API proxy entirely:
1. An **API Management gateway** (e.g. Azure APIM) sits in front of the external service (e.g. OpenAI)
2. The gateway authenticates via managed identity and handles secret retrieval
3. The gateway exposes a public endpoint requiring only a subscription key or OAuth token
4. WASM calls the gateway directly — no secrets in the browser, no custom API project needed
The "proxy" becomes infrastructure rather than application code.
## Current Project Structure
```
ChatAgent.sln
src/
ChatAgent.Client/ -- Blazor WASM (standalone)
Pages/ -- Routable page components
Layout/ -- MainLayout, NavMenu
Services/ -- Client-side services (e.g. ChatApiClient)
Program.cs -- Client entry point, DI registration
ChatAgent.Api/ -- ASP.NET Core Web API (backend proxy)
Controllers/ -- API controllers (e.g. HealthController)
Program.cs -- Server entry point, middleware config
ChatAgent.Shared/ -- Models shared between Client and Api
Models/ -- DTOs (e.g. HealthResponse)
```
### Why Three Projects?
- **ChatAgent.Client**: The Blazor WASM app running in the browser
- **ChatAgent.Api**: Exists to proxy requests that require server-side secrets (e.g. future OpenAI calls). Not needed for basic component interactions.
- **ChatAgent.Shared**: Models referenced by both Client and Api, avoiding duplication
For the initial "echo success" phase, only ChatAgent.Client is actively used. The Api and Shared projects exist to support future integration with external services that require secret management.