diff --git a/Bezalu.ProjectReporting.API/README.md b/Bezalu.ProjectReporting.API/README.md index 434136e..0bf582f 100644 --- a/Bezalu.ProjectReporting.API/README.md +++ b/Bezalu.ProjectReporting.API/README.md @@ -95,8 +95,13 @@ Required App Settings: ## Security -- Function auth level currently `Function`; set keys or add front-end auth (e.g., Entra ID) before production. -- Do not send sensitive data inside report payload for PDF endpoint; only project analysis data. +- **Authentication**: Azure Static Web Apps (SWA) with Azure AD integration + - Function endpoints use `AuthorizationLevel.Anonymous` - authentication enforced at SWA layer + - SWA configuration requires `authenticated` role for all `/api/*` routes + - Unauthenticated requests blocked by SWA with 401 redirect to Azure AD login + - Azure Functions trust SWA authentication; no additional function keys required +- **Configuration**: Sensitive data (API keys, credentials) stored in Azure App Settings; use Azure Key Vault references in production +- **Data Handling**: Report payloads contain project analysis data only; no raw credentials transmitted ## Extensibility diff --git a/README.md b/README.md index fa1a6f5..3f05339 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,11 @@ A comprehensive project reporting solution that integrates with ConnectWise Mana ## Overview -This solution consists of two main projects: +This solution consists of three main projects: 1. **Bezalu.ProjectReporting.API** - Azure Functions backend API that generates project completion reports -2. **Bezalu.ProjectReporting.Web** - Blazor WebAssembly frontend (not yet implemented) +2. **Bezalu.ProjectReporting.Web** - Blazor WebAssembly frontend for interactive report viewing and PDF export +3. **Bezalu.ProjectReporting.Shared** - Shared DTOs for consistent contracts between API and frontend ## Features @@ -90,8 +91,11 @@ Generates a comprehensive project completion report for the specified project ID ### Frontend (Web) -- **Blazor WebAssembly** (to be implemented) -- Will consume the API to display and generate PDF reports +- **Blazor WebAssembly** with Fluent UI components +- Interactive report visualization with tabs for phases and tickets +- AI-generated summary rendered as Markdown using Markdig +- PDF export functionality (posts existing report to API to avoid regeneration) +- Integrated with Azure Static Web Apps for deployment and authentication ## Project Structure @@ -106,16 +110,34 @@ CW-ProjectReporting/ │ ├── host.json # Azure Functions host configuration │ ├── local.settings.json # Local development settings (not in git) │ └── README.md # Detailed API documentation -└── Bezalu.ProjectReporting.Web/ - └── (Blazor WebAssembly project - to be implemented) +├── Bezalu.ProjectReporting.Web/ +│ ├── Pages/ # Blazor pages (Home.razor) +│ ├── Layout/ # Layout components +│ ├── wwwroot/ # Static assets and JS helpers +│ ├── staticwebapp.config.json # Azure Static Web Apps configuration +│ └── Program.cs # Blazor WebAssembly startup +└── Bezalu.ProjectReporting.Shared/ + └── DTOs/ # Shared data transfer objects ``` ## Security -- API keys and credentials stored in configuration (use Azure Key Vault in production) -- `local.settings.json` excluded from source control -- Function-level authorization required for API endpoints -- No vulnerabilities detected by CodeQL security scanning +- **Authentication**: Azure Static Web Apps with Azure AD (Entra ID) integration + - API endpoints use `AuthorizationLevel.Anonymous` at the Function level + - Authentication enforced by Static Web Apps configuration - requires `authenticated` role for `/api/*` routes + - Unauthenticated requests receive 401 and redirect to Azure AD login +- **Configuration**: API keys and credentials stored in Azure App Settings (use Azure Key Vault in production) +- **Source Control**: `local.settings.json` excluded from source control +- **Scanning**: No vulnerabilities detected by CodeQL security scanning + +### Authentication Flow + +1. User accesses the Blazor WebAssembly app hosted on Azure Static Web Apps +2. Static Web Apps enforces authentication via Azure AD (configured in `staticwebapp.config.json`) +3. Authenticated users receive session cookies from SWA +4. API requests include SWA authentication cookies automatically +5. SWA validates authentication before forwarding requests to Azure Functions +6. Azure Functions trust the SWA authentication layer (no additional function-level auth required) ## Development Notes @@ -126,12 +148,13 @@ CW-ProjectReporting/ ## Future Enhancements -- Implement Blazor frontend for report visualization -- Add PDF generation capability -- Implement additional report types -- Add caching for improved performance +- Add visual charts for timeline and budget variance trends +- Implement additional report types (financial analysis, resource utilization) +- Add caching layer for ConnectWise API responses - Add unit and integration tests - Implement batch report generation +- Add Excel export capability +- Implement browser-side caching (localStorage) for recent reports ## Documentation diff --git a/docs/architecture.md b/docs/architecture.md index 46658d1..1403e46 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -7,14 +7,17 @@ The solution consists of three projects: - Bezalu.ProjectReporting.Shared (DTO contracts shared by both) ## Data Flow -1. User enters Project ID in Web UI. -2. Front end POSTs projectId to `/api/reports/project-completion`. -3. API fetches project, phases, tickets, notes from ConnectWise. -4. API builds `ProjectCompletionReportResponse` and invokes Azure OpenAI to produce `AiGeneratedSummary`. -5. JSON returned to client; client renders summary markdown using Markdig. -6. User initiates PDF download; front end POSTs the full report JSON to `/api/reports/project-completion/pdf`. -7. API composes PDF using QuestPDF with supplied data (skip re-fetch & AI). -8. Client receives PDF bytes and triggers browser download via JS interop. +1. User accesses Blazor WebAssembly app via Azure Static Web Apps. +2. Static Web Apps enforces authentication via Azure AD (Entra ID). +3. User enters Project ID in Web UI. +4. Front end POSTs projectId to `/api/reports/project-completion` (with SWA auth cookies). +5. SWA validates authentication and forwards request to Azure Functions. +6. API fetches project, phases, tickets, notes from ConnectWise. +7. API builds `ProjectCompletionReportResponse` and invokes Azure OpenAI to produce `AiGeneratedSummary`. +8. JSON returned to client; client renders summary markdown using Markdig. +9. User initiates PDF download; front end POSTs the full report JSON to `/api/reports/project-completion/pdf`. +10. API composes PDF using QuestPDF with supplied data (skip re-fetch & AI). +11. Client receives PDF bytes and triggers browser download via JS interop. ## Key Services - `IConnectWiseApiClient`: wraps HTTP calls to ConnectWise endpoints. @@ -26,8 +29,18 @@ The solution consists of three projects: - POST for PDF avoids second expensive aggregation call. - Markdown + Markdig chosen for flexibility in AI summary formatting. - QuestPDF chosen for deterministic server-side PDF rendering. +- **Azure Static Web Apps** provides integrated hosting, authentication, and API routing. +- **Function AuthorizationLevel.Anonymous** used because authentication is enforced upstream by SWA. + +## Authentication Architecture +- **Static Web Apps** handles authentication via Azure AD (Entra ID) +- `staticwebapp.config.json` enforces `authenticated` role for `/api/*` routes +- Unauthenticated users redirected to `/.auth/login/aad` +- SWA session cookies automatically included in API requests +- Azure Functions trust SWA authentication layer - no function keys needed ## Future Enhancements - Caching of raw ConnectWise responses. - Additional export formats (Excel, HTML full report). -- Authentication (OIDC) integration for user-level access. +- User-level access control based on ConnectWise permissions. +- Visual charts for variance trends and project analytics. diff --git a/docs/deployment.md b/docs/deployment.md index 44c3fa8..0e185d6 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -2,13 +2,24 @@ ## Azure Static Web Apps + Azure Functions - Front end (Blazor WASM) deployed to Static Web Apps. -- API (Azure Functions) either integrated (api folder) or separate Functions App. +- API (Azure Functions) integrated via SWA's managed Functions (api folder) or linked to separate Functions App. +- **Authentication** handled by Static Web Apps with Azure AD integration. + +## Steps (Integrated Deployment) +1. Create Azure Static Web App resource in Azure Portal. +2. Configure Azure AD authentication provider in SWA settings. +3. Set `api_location` to point to Azure Functions project folder during SWA build. +4. Configure Application Settings for ConnectWise + Azure OpenAI in SWA or linked Functions App. +5. Deploy via GitHub Actions (auto-configured by SWA) or manual deployment: + - Front-end: `dotnet publish -c Release Bezalu.ProjectReporting.Web` + - API: Functions automatically deployed with SWA or via `func azure functionapp publish ` ## Steps (Separate Functions App) 1. Create Azure Functions App (Isolated .NET runtime) and configure Application Settings for ConnectWise + Azure OpenAI. 2. Deploy API project via `func azure functionapp publish ` or CI. -3. Create Static Web App and set `api_location` to Functions App if integrated, else configure front end to call external API base URL. -4. Upload front-end build (`dotnet publish -c Release Bezalu.ProjectReporting.Web`). +3. Create Static Web App and link to external Functions App or configure front end to call external API base URL. +4. Configure Azure AD authentication in Static Web Apps settings. +5. Upload front-end build output to SWA. ## Configuration Keys - `ConnectWise:*` @@ -16,7 +27,13 @@ - `AzureOpenAI:DeploymentName` ## Authentication -- Add Entra ID or other auth on Static Web Apps; issue front-end access token; secure Functions with Easy Auth or custom. +- **Azure Static Web Apps** integrated with **Azure AD (Entra ID)** for authentication +- Configure authentication provider in Azure Portal under SWA > Settings > Authentication +- `staticwebapp.config.json` enforces authentication: + - `/api/*` routes require `authenticated` role + - Unauthenticated users redirected to `/.auth/login/aad` +- No function keys needed - Azure Functions use `AuthorizationLevel.Anonymous` and trust SWA authentication +- Session managed by SWA; cookies automatically included in API requests ## Environment Segregation - Use separate resource groups for dev/stage/prod. diff --git a/docs/frontend.md b/docs/frontend.md index c1855ec..44751b1 100644 --- a/docs/frontend.md +++ b/docs/frontend.md @@ -1,17 +1,32 @@ # Front-End (Blazor WebAssembly) +## Overview +The front-end is a Blazor WebAssembly application using Microsoft Fluent UI components, deployed on Azure Static Web Apps with integrated Azure AD authentication. + ## Key Behaviors +- User must authenticate via Azure AD before accessing the application. - User enters Project ID; triggers report fetch. - Displays metrics in Fluent UI components (cards, tabs, data grids, accordion). - AI summary rendered as markdown using Markdig. - PDF download posts existing report JSON to API; no recomputation. +## Authentication +- **Azure Static Web Apps** handles authentication via Azure AD (Entra ID) +- Configured in `staticwebapp.config.json`: + - `/api/*` routes require `authenticated` role + - Unauthenticated users redirected to `/.auth/login/aad` +- SWA session cookies automatically included in API requests +- No additional token management needed in Blazor code + ## State Management - Local component state only (no global store yet). - `IsLoading` for initial report, `IsPdfLoading` for PDF call. ## HTTP -- `HttpClient` base address from host environment; assumes reverse proxy or relative `/api` route. +- `HttpClient` base address from host environment. +- Assumes SWA reverse proxy routing for `/api` routes. +- SWA authentication cookies automatically included in requests. +- No manual authorization headers needed. ## File Download - `saveFile` JS helper converts Base64 to Blob and triggers ``.