AI Assistance: See .github/skills/writing-typescript-code/SKILL.md for coding patterns.
React 19 single-page application with:
- TypeScript for type safety
- Vite for fast development (HMR) and optimized builds
- MSAL.js for Microsoft Entra ID authentication (PKCE flow)
- Server-Sent Events (SSE) for real-time chat streaming
- CSS Modules for scoped styling
- SSE Streaming — Real-time token-by-token response streaming with cancellation support
- Stream Retry — Automatic retry (3×) with exponential backoff; failed messages restore to input
- Message Queue — Type-ahead during streaming; queued messages shown as dismissible chips, auto-sent when stream completes
- Smart Auto-Scroll — Auto-scrolls only when near bottom; "↓ New messages" pill when scrolled up
- Tool-Use Indicators — Inline "Searching files...", "Running code..." during agent tool execution
- Copy — Copy full assistant response to clipboard
- Regenerate — Resend last message for a new response (↻ button)
- Edit — Edit last user message (removes messages, restores text to input with undo)
- Feedback — 👍👎 per-message rating tracked to Application Insights
- File Attachments — Images and documents via paste (Ctrl+V), drag-and-drop, or file picker
- Voice Input — Web Speech API microphone with feature detection and error feedback
- Keyboard Shortcuts — ⌨️ button shows shortcuts; Ctrl+N new chat, Escape cancel
- Toolbar — Primary actions always visible (attach, cancel, voice, new chat); secondary actions (history, export, shortcuts, settings) in ⋯ overflow menu
- History Sidebar — Browse and resume past conversations; accessed via ⋯ menu
- Search — Filter conversations by title in sidebar
- Export — Download conversation as Markdown; accessed via ⋯ menu
- Delete — Remove conversations from history
- Authentication — MSAL.js with silent token refresh + popup fallback
- Accessibility — ARIA live regions, keyboard navigation, focus management, screen reader announcements
- Performance — React 19
useDeferredValuefor responsive input during streaming - Theming — Light/dark/system theme with Fluent UI design tokens
- Citations — Inline citation markers with footnote navigation and source links
frontend/src/
├── App.tsx # Root with MsalProvider
├── main.tsx # Entry point
├── components/
│ ├── AgentChat.tsx # Container (state → ChatInterface)
│ ├── ChatInterface.tsx # Controlled chat UI
│ └── chat/ # Chat subcomponents
│ ├── AssistantMessage.tsx # Streaming message + citations
│ ├── UserMessage.tsx # User message + image previews
│ ├── ChatInput.tsx # Input + file upload + cancel
│ └── CitationMarker.tsx # Inline citation badge
├── services/
│ └── chatService.ts # SSE streaming + API calls
├── contexts/
│ └── AppContext.tsx # Centralized state (useReducer)
├── hooks/
│ ├── useAuth.ts # MSAL token acquisition
│ └── useAppState.ts # State access hook
├── reducers/
│ └── appReducer.ts # State transitions
├── config/
│ └── authConfig.ts # MSAL configuration
├── types/ # TypeScript interfaces
└── utils/ # Helpers (citations, files, etc.)
- Node.js 18+
.env.localfile generated (runazd upfirst)
Option 1: VS Code task (recommended)
- Run task
Frontend: React Vite- dependencies are installed automatically
Option 2: Manual
cd frontend
npm install # .npmrc sets legacy-peer-deps automatically
npm run devFrontend runs at http://localhost:5173 with Hot Module Replacement (HMR).
.env.local file (auto-generated by azd up):
VITE_ENTRA_SPA_CLIENT_ID=...
VITE_ENTRA_TENANT_ID=...
CRITICAL: Environment variables are replaced at build time. Access them at module level only:
// ✅ Correct - module level
const clientId = import.meta.env.VITE_ENTRA_SPA_CLIENT_ID;
// ❌ Wrong - inside function (won't work after build)
function getClientId() {
return import.meta.env.VITE_ENTRA_SPA_CLIENT_ID;
}- Hot reload: Vite HMR updates browser instantly on save
- React 19:
.npmrchandles peer-dep conflicts automatically — just runnpm installfromfrontend/ - State debugging: Console shows
🔄 ACTION_TYPEfor each state change (dev only) - CORS: Backend allows
http://localhost:5173in dev mode
npm run build # Production build → dist/
npm run preview # Preview production build locallyProduction builds are created in Docker multi-stage builds and served from ASP.NET Core's wwwroot.
| Package | Purpose |
|---|---|
| react | UI framework |
| @azure/msal-react | Entra ID authentication |
| @azure/msal-browser | MSAL.js browser library |
| @fluentui/react-components | Fluent UI components |
| vite | Build tool + dev server |
See package.json for current versions.
| Component | Role | Pattern |
|---|---|---|
AgentChat |
Container | Wires state to controlled component |
ChatInterface |
Presentation | Stateless, receives props + callbacks |
ChatInput |
Controlled input | Manages local input state, calls parent handlers |
AssistantMessage |
Memoized | Renders streaming text + citations |
User Action
→ dispatch(action)
→ appReducer (pure function)
→ new state
→ React re-render
→ UI update
Action types: CHAT_SEND_MESSAGE → CHAT_START_STREAM → CHAT_STREAM_CHUNK (×N) → CHAT_STREAM_COMPLETE
| Issue | Solution |
|---|---|
| Module not found | Run npm install from frontend/ (.npmrc handles peer deps) |
| Auth popup blocked | Allow popups for localhost in browser |
| Stale cache | Delete node_modules/.vite and restart |
| HMR not working | Check Vite terminal for errors |
| 401 on API calls | Verify .env.local has correct client ID |
For AI-assisted development, see .github/skills/writing-typescript-code/SKILL.md and .github/skills/implementing-chat-streaming/SKILL.md.