CSR Volunteer Management Platform
Architecture Design Document
Client: John Keells Foundation, part of John Keells Holdings PLC
Prepared by: CloudNavision Private Limited
Author: Azmie Sally, Founder & CEO
Version: 3.0  |  Date: March 2026  |  Classification: Confidential
Document Control
Document Information
Approvals
Revision History
1. Executive Summary
This Architecture Design Document describes the technical architecture for the CSR Volunteer Management Platform deployed for John Keells Foundation, part of John Keells Holdings PLC. The platform enables enterprise-wide volunteer management, tracking, ratings, and impact reporting across all JKH business units.
The architecture is a fully managed, containerised deployment on Microsoft Azure with zero self-managed servers. Both the React web application and the n8n automation platform run as Azure Container Apps. All external traffic is routed exclusively through Cloudflare tunnels — no Azure resource has a public-facing origin endpoint. Outbound connectivity to Supabase is locked to a single fixed IP via NAT Gateway.
1.1 Key Architecture Decisions
Azure Container Apps
For both frontend (React/Express.js) and automation (n8n) — no VMs, no OS patching
Cloudflare Tunnel Model
Internal ingress only; both services use outbound tunnels, eliminating exposed origin endpoints
Express.js Server Layer
Within the React container, required to serve the built SPA from a Container App
Supabase SaaS
For managed PostgreSQL, authentication, edge functions, and Realtime
Microsoft SharePoint
For file storage via n8n and Microsoft Graph API
Cloudflare ZTNA
For n8n admin access only — web app uses WAF + Entra ID SSO (no double authentication for 15,000 users)
Microsoft Entra ID — Two Tenants
jkhmgmt.onmicrosoft.com for Azure subscription hosting only; keells.onmicrosoft.com for all users, app registrations, and employee SSO login
LinkedIn OAuth
For non-Entra ID users — secondary authentication
NAT Gateway
With static IP for fixed egress identity — required for Supabase network allowlist
SheetJS
For server-side Excel report generation within the Express.js layer
Revised Sizing
1.0 vCPU / 2.0 Gi per web app replica, min 2 / max 10 replicas, scaling on HTTP concurrent connections
2. Architecture Overview
2.1 High-Level Architecture Diagram
Figure 1: High-Level Architecture Diagram illustrating the five-layer deployment model — Users, Cloudflare Edge, Azure Container Apps, NAT Gateway, and External Services — for the CSR Volunteer Management Platform hosted on Azure (Southeast Asia / Singapore).
2.2 Architecture Layers
2.3 Subscription and Tenant Details
The two tenants serve entirely separate purposes. jkhmgmt.onmicrosoft.com is used solely for Azure subscription hosting — it contains no users and no app registrations. keells.onmicrosoft.com holds all JKH employees and is the tenant where all app registrations are created, including both the n8n automation registration and the Supabase Auth SSO registration. They do not interact.
2.4 Domain Names
All subdomains are exclusively under johnkeellsfoundation.com. DNS is managed by Cloudflare. The api subdomain is reserved — no DNS record should be created until required.
2.5 Naming Convention
All Azure resources follow the pattern: JKH-{ENV}-FND-{TYPE}-{INSTANCE}
Resource type abbreviations:

⚠️ ACR naming exception: Azure Container Registry only accepts lowercase alphanumeric characters with no hyphens, maximum 50 characters. The provisioned ACR name is acrjkhjkfprd. This is the only resource that deviates from the standard convention.
2.6 Core Principles
3. Network Design
3.1 Virtual Network
3.3 NAT Gateway

Record the JKH-PRD-FND-PIP-NAT IP immediately after provisioning. This IP is added to the Supabase network allowlist and must be known before Container Apps are deployed.
3.2 Subnet Allocation
3.4 Network Security Groups
JKH-PRD-FND-NSG-ACA — Container Apps subnet
Inbound DenyAll is the primary perimeter — both Container Apps have internal-only ingress so no legitimate inbound traffic arrives directly. All external traffic arrives via outbound Cloudflare tunnels.
JKH-PRD-FND-NSG-ACR — Container Registry subnet
3.5 Public-Facing URLs
3.6 Service Communication Map
4. Azure Resources
4.1 Azure Container Registry
4.2 Container Apps Environment
4.3 Container App — React Web App
App Configuration
Containers
Container App Secrets (never in code)
TUNNEL_TOKEN = <JKH-PRD-FND-TUNNEL-CSR token>
Build-time variables (GitHub Actions secrets — injected at docker build via --build-arg)
VITE_SUPABASE_URL = https://<ref>.supabase.co VITE_SUPABASE_ANON_KEY = <anon key> VITE_ENTRA_CLIENT_ID = <client ID — keells.onmicrosoft.com tenant> VITE_ENTRA_TENANT_ID = <tenant ID — keells.onmicrosoft.com> VITE_ENTRA_REDIRECT_URI = https://csr.johnkeellsfoundation.com/auth/callback VITE_LINKEDIN_CLIENT_ID = <LinkedIn OAuth client ID> VITE_N8N_WEBHOOK_BASE_URL = https://n8n.johnkeellsfoundation.com VITE_N8N_WEBHOOK_SECRET = <webhook auth token>

VITE_ variables are baked into the JavaScript bundle at build time by Vite. They must exist as GitHub Actions secrets and be passed as --build-arg in the Dockerfile. Setting them only in Container Apps runtime environment has no effect on the frontend.
The AI translation service (Google Translate API) is stored as a Supabase Edge Function secret, not a frontend variable. It is not a build argument and does not appear in the Docker build.
4.4 Container App — n8n
App Configuration
Containers
Container App Secrets
TUNNEL_TOKEN = <JKH-PRD-FND-TUNNEL-N8N token> N8N_ENCRYPTION_KEY = <random 32-char string> DB_POSTGRESDB_PASSWORD = <Supabase DB password> SUPABASE_SERVICE_KEY = <Supabase service role key — never in frontend>
Environment Variables
N8N_HOST = n8n.johnkeellsfoundation.com WEBHOOK_URL = https://n8n.johnkeellsfoundation.com N8N_PROTOCOL = https N8N_PORT = 5678 DB_TYPE = postgresdb DB_POSTGRESDB_HOST = db.JKHFOUNDATION.supabase.co DB_POSTGRESDB_PORT = 5432 DB_POSTGRESDB_DATABASE = postgres DB_POSTGRESDB_SCHEMA = n8n_data DB_POSTGRESDB_USER = postgres EXECUTIONS_DATA_PRUNE = true EXECUTIONS_DATA_MAX_AGE = 336
5. Cloudflare Configuration
5.1 Tunnels
5.2 WAF — Applied to Both Hostnames
5.3 CDN Caching — csr.johnkeellsfoundation.com Only
Cloudflare CDN caches all static assets at the edge. For a React SPA, this means the vast majority of bytes transferred never reach the origin container. Effective concurrent connections at origin for 600 concurrent users is estimated at 120–180 (20–30% of total).
5.4 Access Protection Decision — Per Service

This is a deliberate architectural decision — not a gap. The web app security posture is: Cloudflare WAF blocks malicious requests at the edge → Entra ID SSO prevents unauthorised access to data → Supabase RLS enforces data access at the database level. Three independent layers without double authentication for 15,000 users.
5.5 ZTNA Access Policy — n8n.johnkeellsfoundation.com Only
Identity provider: Microsoft Entra ID (keells.onmicrosoft.com)
6. Security Architecture
6.1 Security Model
6.2 Secrets Management
All credentials are managed through two secure stores. No secret is stored in source code, Docker images, or configuration files committed to GitHub.
6.3 Transport Security
6.4 Data Security
At Rest
Supabase encryption — AES-256 managed by Supabase
In Transit
TLS 1.2+ — All connections encrypted
Row-level
Supabase RLS — Per-table, per-user policies on all csr_app tables
Token
JWT — Stateless authentication via Supabase Auth tokens
7. Authentication Architecture
7.1 Overview — Two Separate Tenants
This platform involves two distinct Entra ID tenants serving entirely different purposes. They must never be confused:
Both app registrations — the n8n automation registration and the Supabase Auth SSO registration — are created in keells.onmicrosoft.com. The jkhmgmt.onmicrosoft.com tenant is used exclusively for the Azure subscription and contains no users or app registrations.
7.2 User Authentication Flow
7.3 Part A — n8n App Registration (Amendment)
A.1 Registration Details
A.2 Current Permission State (Granted)
A.3 Additional Permissions Required
Review items from original document: Contacts.Read vs Contacts.ReadWrite — recommend Contacts.Read only (least privilege). Mail.ReadWrite.Shared and Mail.Send.Shared — not required for current workflow scope; add only if workflows send from shared mailboxes.
A.4 Open Items — Status
7.4 Part B — Supabase Auth App Registration (New)
This is a new, separate app registration required to enable Microsoft Entra ID as the SSO identity provider for volunteer and employee login via Supabase Auth. It is entirely separate from the n8n registration but resides in the same keells.onmicrosoft.com tenant.
B.1 Registration Overview
This registration must be created in the keells.onmicrosoft.com tenant. JKH employees authenticate with their @keells.com Microsoft accounts, which live in the keells tenant. All app registrations for this platform reside in this tenant.
B.2 Required Permissions
B.3 SAP Employee ID — Entra ID Attribute Mapping
Feature B.19 specifies that the volunteer's SAP number is automatically populated from the Microsoft identity platform during sign-in. This requires the SAP employee ID to be stored as a custom or extension attribute on the user's Entra ID profile in keells.onmicrosoft.com.

Action required from JKH IT: Confirm which Entra ID attribute holds the SAP/HR employee identifier.
Once confirmed, the Supabase Auth hook reads this attribute at login and populates the SAP Number field on the volunteer profile. It will not overwrite manual entries per B.19 specification.
B.4 Token Configuration
The following optional claims must be added to the token configuration in the Azure Portal:
In Azure Portal → App Registration → Token configuration → Add optional claim → ID token:
For the groups claim: Token configuration → Add groups claim → Security groups → ID token.
Group IDs are returned as GUIDs in the token. A mapping table in the platform (configured by Central Admin per SC.6) maps these GUIDs to Business Units. JKH IT must provide the Entra ID group GUIDs that correspond to each Business Unit.
B.5 Client Secret
The client secret is entered directly into the Supabase Auth provider configuration. It is never stored in code, GitHub, or any config file.
B.6 Supabase Auth Provider Configuration
Once the app registration is created, configure in Supabase Dashboard → Authentication → Providers → Azure:
B.7 Redirect URI Configuration
In Entra ID app registration → Authentication → Redirect URIs:
https://JKHFOUNDATION.supabase.co/auth/v1/callback
In Supabase Dashboard → Authentication → URL Configuration:
Site URL : https://csr.johnkeellsfoundation.com Redirect URLs : https://csr.johnkeellsfoundation.com/auth/callback https://csr.johnkeellsfoundation.com/**

Remove all Lovable development URLs (*.lovable.app, localhost:*) from the redirect URLs list before go-live.
7.5 LinkedIn OAuth (Secondary Authentication)
LinkedIn OAuth is provided as a secondary sign-in path for non-Entra ID users (e.g. external partners, contractors, or alumni who do not hold a @keells.com Microsoft account).
LinkedIn OAuth users do not receive SAP employee ID auto-population (B.19) or automatic Business Unit assignment (SC.6), as these rely on Entra ID group and profile attributes. Manual data entry applies.
8. Supabase Configuration
8.1 Supabase Specification
8.2 Database Schemas
8.3 Connection Summary
8.4 Network Allowlist
All Supabase access is either browser-side (protected by RLS and anon key scope) or via the NAT Gateway (Container Apps server-side). Supabase dashboard access for CloudNavision and JKH IT is always permitted by Supabase independently of network restrictions.
8.5 Auth Redirect URLs
Site URL : https://csr.johnkeellsfoundation.com Redirect URLs : https://csr.johnkeellsfoundation.com/auth/callback https://csr.johnkeellsfoundation.com/**

Remove all Lovable development URLs before go-live.
8.6 Row Level Security
RLS must be enabled and verified on all tables in the csr_app schema before go-live. The anon key used by the frontend grants zero access beyond what RLS policies explicitly permit.
8.7 Realtime — Connection Management
The React app uses Supabase Realtime for live in-app notifications (Feature B.15). Each active user maintains a persistent WebSocket connection. At 600 concurrent users this consumes 600 of the available 600 pooled connections — leaving no headroom for REST API calls and direct n8n PostgreSQL connections.
Realtime channel pattern — user-scoped subscriptions only:
//
9. n8n Configuration
9.1 n8n Specification
9.2 n8n Version Pinning and Upgrade Policy

n8n upgrades must never be applied automatically. The pinned version tag in the Container App definition is the single source of truth for the deployed version.
9.3 n8n Workflows
Teams Notifications
Trigger: Webhook from Web App
Send event reminders, status updates, and alerts to Microsoft Teams
New Project Notification
Trigger: Webhook on project creation
Dispatch full project details to downstream systems
File Upload to SharePoint
Trigger: Webhook from Web App
Upload evaluation photos, documents, and event images to SharePoint
Teams Adaptive Card Responses
Trigger: Teams Webhook
Process user interactions with Teams Adaptive Cards
Report Generation
Trigger: Scheduled / On-demand
Generate advanced reports and save to SharePoint
10. Data Flow Diagrams
10.1 User Authentication Flow
01
Navigate
User navigates to csr.johnkeellsfoundation.com
02
Route
Cloudflare routes request to ca-jkh-csr-prd via Cloudflare tunnel
03
Sign-in Options
Web app presents sign-in options: Microsoft Entra ID (keells.onmicrosoft.com) or LinkedIn
04
Authenticate
User authenticates with selected provider (+ MFA if configured for Entra ID)
05
OAuth Tokens
Identity provider returns OAuth tokens to web app
06
Exchange
Web app exchanges tokens with Supabase Auth
07
SAP ID
On first Entra ID login: SAP employee ID auto-populated from Entra ID profile (B.19)
08
BU Mapping
On first Entra ID login: Group GUIDs mapped to Business Unit (SC.6)
09
Session
User session established with role-based access
10.2 Volunteer Registration Flow
01
Browse Projects
Volunteer browses available projects in web app
02
Fetch Data
Web app fetches project data from Supabase (REST API, anon key + RLS)
03
Submit Application
Volunteer submits application
04
Create Record
Web app creates application record in Supabase
05
Webhook
Web app sends webhook to n8n (n8n.johnkeellsfoundation.com/webhook/...)
06
Teams Notification
n8n sends Teams notification to volunteer and administrator via Microsoft Graph
07
Log Update
n8n updates notification log in Supabase (n8n_data schema)
10.3 File Upload Flow
01
Upload
User uploads photo or document via web app
02
Send to n8n
Web app sends file data to n8n webhook
03
Authenticate
n8n authenticates with Microsoft Graph API (using JKHMIT_FOUNDATION_n8nAuto_PRD credentials from keells.onmicrosoft.com)
04
Upload to SharePoint
n8n uploads file to SharePoint (John Keells Foundation library)
05
Return URL
n8n returns SharePoint URL to web app
06
Store Reference
Web app stores SharePoint URL reference in Supabase
10.4 Report Generation Flow
01
Request Report
Central Admin requests report via web app
02
Generate Excel
SheetJS generates Excel workbook within the Express.js server layer
03
Download
Report available for immediate download from the Reports module
04
Optional: SharePoint + Teams
Optionally: n8n uploads report to SharePoint and sends Teams notification with report link
11. Integration Details
11.1 Integration Summary
11.2 Microsoft Teams Integration
Teams integration is handled entirely through n8n workflows using the Microsoft Graph API:
Adaptive Cards
For project notifications and reminders
Channel Messages
For team announcements
Direct Messages
For individual notifications
Adaptive Card Actions
Action responses via webhooks
11.3 SharePoint Integration
SharePoint integration is handled through n8n workflows. The web app never connects directly to SharePoint. Flow: Web app sends file data to n8n webhook → n8n authenticates with SharePoint using JKHMIT_FOUNDATION_n8nAuto_PRD service principal (Sites.Selected permission) from keells.onmicrosoft.com → n8n uploads file to designated folder in John Keells Foundation library → n8n returns SharePoint URL to web app for storage in Supabase.
12. Monitoring and Logging
12.1 Azure Monitoring
Application Performance
Azure Application Insights (JKH-PRD-FND-APPI-001)
Request tracking, performance metrics, exceptions
Infrastructure Logs
Azure Log Analytics (JKH-PRD-FND-LOG-001)
Container logs, diagnostic data, custom queries
Alerts
Azure Monitor Alerts
Threshold-based alerting for critical metrics
12.2 Key Metrics
12.3 Log Retention
13. CI/CD Pipeline
13.1 Source Control
13.2 Pipeline Flow
git push → main │ ▼ GitHub Actions ├── npm ci ├── npm run build (Vite — VITE_ vars injected as build args) ├── docker build (two-stage — builder + serve) ├── docker push → acrjkhjkfprd.azurecr.io/jkh-csr-app:<sha> └── az containerapp update → ca-jkh-csr-prd (rolling redeploy)
n8n is not in the CI/CD pipeline — it uses the official n8nio/n8n image updated manually via a pinned version tag.
13.3 Dockerfile
# Stage 1 — Build FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . ARG VITE_SUPABASE_URL ARG VITE_SUPABASE_ANON_KEY ARG VITE_ENTRA_CLIENT_ID ARG VITE_ENTRA_TENANT_ID ARG VITE_ENTRA_REDIRECT_URI ARG VITE_LINKEDIN_CLIENT_ID ARG VITE_N8N_WEBHOOK_BASE_URL ARG VITE_N8N_WEBHOOK_SECRET RUN npm run build # Stage 2 — Serve FROM node:20-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --omit=dev COPY server.js ./ COPY --from=builder /app/dist ./dist EXPOSE 8080 CMD ["node", "server.js"]

The AI translation key is not a build argument. It is stored as a Supabase Edge Function secret and accessed server-side only. It does not appear in the Dockerfile or the built JavaScript bundle.
13.4 GitHub Actions Workflow
name: Build and Deploy on: push: branches: [main] env: ACR_NAME: acrjkhjkfprd IMAGE_NAME: jkh-csr-app CONTAINER_APP: ca-jkh-csr-prd RESOURCE_GROUP: JKH-PRD-FND-RG-001 jobs: build-and-deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Log in to Azure uses: azure/login@v2 with: creds: ${{ secrets.AZURE_CREDENTIALS }} - name: Log in to ACR run: az acr login --name $ACR_NAME - name: Build and push image run: | docker build \ --build-arg VITE_SUPABASE_URL=${{ secrets.VITE_SUPABASE_URL }} \ --build-arg VITE_SUPABASE_ANON_KEY=${{ secrets.VITE_SUPABASE_ANON_KEY }} \ --build-arg VITE_ENTRA_CLIENT_ID=${{ secrets.VITE_ENTRA_CLIENT_ID }} \ --build-arg VITE_ENTRA_TENANT_ID=${{ secrets.VITE_ENTRA_TENANT_ID }} \ --build-arg VITE_ENTRA_REDIRECT_URI=${{ secrets.VITE_ENTRA_REDIRECT_URI }} \ --build-arg VITE_LINKEDIN_CLIENT_ID=${{ secrets.VITE_LINKEDIN_CLIENT_ID }} \ --build-arg VITE_N8N_WEBHOOK_BASE_URL=${{ secrets.VITE_N8N_WEBHOOK_BASE_URL }} \ --build-arg VITE_N8N_WEBHOOK_SECRET=${{ secrets.VITE_N8N_WEBHOOK_SECRET }} \ -t $ACR_NAME.azurecr.io/$IMAGE_NAME:${{ github.sha }} \ -t $ACR_NAME.azurecr.io/$IMAGE_NAME:latest \ . docker push $ACR_NAME.azurecr.io/$IMAGE_NAME:${{ github.sha }} docker push $ACR_NAME.azurecr.io/$IMAGE_NAME:latest - name: Deploy to Container Apps run: | az containerapp update \ --name $CONTAINER_APP \ --resource-group $RESOURCE_GROUP \ --image $ACR_NAME.azurecr.io/$IMAGE_NAME:${{ github.sha }}
13.5 GitHub Actions Secrets Required
13.6 Environments
14. Scalability Plan
14.1 Load Profile
15K
Total User Base
All JKH employees — potential volunteers
600
Peak Concurrent (Baseline)
~4% of base — typical for web-based employee portal
1,500
Peak Concurrent (Headroom)
Revised sizing target
1
Realtime Connections
Per active user — Supabase Realtime for live notifications (B.15)
14.2 Cloudflare Edge Absorption
Cloudflare CDN caches all static assets at the edge. Only HTML requests and API calls reach the origin container.
Estimated effective concurrent connections at origin for 600 concurrent users: 120–180 (20–30% of total).
14.3 Container Sizing — Current (Revised)
Scaling rule (Container Apps HTTP scaling):
Scale metric : http_requests (concurrent) Target per replica: 150 Min replicas : 2 Max replicas : 10 Scale-out cooldown: 30 seconds Scale-in cooldown : 120 seconds
Minimum 2 replicas eliminates cold-start delay for the first users. Scale-in cooldown is 120s to prevent thrashing during sustained load.

Capacity at current sizing: 150 concurrent connections × 10 replicas = 1,500 concurrent capacity + Cloudflare CDN absorbs ~70% of requests = Effective headroom well above 600 concurrent users
14.4 Scale-Up Tiers
14.5 Supabase Compute — Connection Tiers

Scale trigger: Upgrade to Large when pooled connection utilisation consistently exceeds 70% (420/600). Monitor via Supabase Dashboard → Reports → Database.
14.6 Scaling Triggers
14.7 Scaling Principles
  • Container Apps scale horizontally by adding replicas — no downtime, no architectural change required
  • Supabase compute upgrades are performed via the Supabase dashboard with minimal downtime (~2–3 minutes)
  • Cloudflare CDN has no per-connection limits relevant to this scale — no changes needed at any tier
  • n8n must remain at 1 replica at all tiers — it is not in the user-facing request path and must not scale horizontally
  • All scale-up actions require no code changes, no redeployment, and no architectural rework
14.8 Scaling Responsibilities
14.9 Load Testing Recommendation
Before go-live, a load test against the staging environment should validate the revised sizing.
Recommended tool: k6 (open source, integrates with Azure and GitHub Actions)
15. Backup and Recovery
15.1 Backup Configuration
Supabase Pro Plan includes automated daily backups with point-in-time recovery (PITR).
15.2 Recovery Procedure

Recommendation: Enable the Supabase PITR add-on on production provisioning. Given the platform manages employee attendance, ratings, and HR-linked data, a 24-hour RPO from daily backups alone is not sufficient for production use.
15.3 Disaster Recovery — Platform Level
15.4 Backup Responsibilities
16. Provisioning Order
The following sequence must be followed exactly. Steps are ordered to satisfy dependencies — each step assumes all prior steps are complete.
01
Resource Group
JKH-PRD-FND-RG-001
02
Log Analytics
JKH-PRD-FND-LOG-001
03
VNet + all subnets
JKH-PRD-FND-VNET-001
04
NSGs
JKH-PRD-FND-NSG-ACA, JKH-PRD-FND-NSG-ACR
05
Associate NSGs
Attach each NSG to its subnet
06
Public IP (NAT)
JKH-PRD-FND-PIP-NAT — record static IP immediately
07
NAT Gateway
JKH-PRD-FND-NAT-001 → associate to JKH-PRD-FND-SNET-ACA
08
Container Registry
acrjkhjkfprd → private endpoint in JKH-PRD-FND-SNET-ACR
01
Supabase Network Restrict
Add JKH-PRD-FND-PIP-NAT + JKH office IPs to allowlist
02
Supabase Auth URLs
Update redirect URLs to johnkeellsfoundation.com; remove Lovable dev URLs
03
Container Apps Environment
cae-jkh-jkf-prd → JKH-PRD-FND-SNET-ACA
04
Cloudflare Tunnels
Create JKH-PRD-FND-TUNNEL-CSR + JKH-PRD-FND-TUNNEL-N8N → save both tokens
05
Cloudflare Access Policy
ZTNA for n8n.johnkeellsfoundation.com + webhook bypass rule
06
Cloudflare WAF Rules
Apply OWASP + bot rules to both hostnames
07
Container App (n8n)
ca-jkh-n8n-prd — n8n + cloudflared sidecar + secrets
08
Verify n8n Tunnel
Cloudflare dashboard → JKH-PRD-FND-TUNNEL-N8N → Healthy
09
Container App (web app)
ca-jkh-csr-prd — React + cloudflared sidecar + secrets
01
Verify Web App Tunnel
Cloudflare dashboard → JKH-PRD-FND-TUNNEL-CSR → Healthy
02
GitHub Actions Secrets
AZURE_CREDENTIALS + all VITE_ vars
03
First Deployment
Push to main → verify full pipeline runs
04
App Insights
JKH-PRD-FND-APPI-001 → linked to JKH-PRD-FND-LOG-001
05
Update Redirect URIs
Entra ID (keells tenant) → csr.johnkeellsfoundation.com
06
n8n M365 App Registration
Complete open items A.3–A.4 (JKH IT)
07
RLS Audit
Verify all csr_app tables have RLS enabled
08
Enable PITR
Supabase dashboard → enable PITR add-on before go-live
09
End-to-End Smoke Test
Full user journey across all integrations
17. Open Items Before Provisioning
18. Browser and Device Support
18.1 Supported Browsers
The platform is a Progressive Web App (PWA) built on React 19.
Internet Explorer is not supported. Chromium-based browsers are recommended for the best experience.
18.2 Supported Devices
18.3 PWA Installation
Add to Home Screen (iOS)
Safari — Share → Add to Home Screen
Add to Home Screen (Android)
Chrome — Install prompt or browser menu
Install on Desktop (Chrome/Edge)
Address bar install prompt
Offline Support
⚠️ Limited — read-only cached views only; active features require connectivity
Push Notifications
Supported on Android and desktop; limited on iOS (iOS 16.4+ required)
Camera Access (QR Scanning)
Required for attendance check-in via QR code
18.4 Network Requirements
19. Appendices
Appendix A: Technology Stack Summary
Appendix B: Key Dependencies
Core Framework
Backend and Server
Forms and Validation
UI Components and Styling
Data Visualization, Date/Time, QR Code and Media
Radix UI Primitives
Appendix C: Revised Monthly Cost Estimate
Microsoft Entra ID and SharePoint are included in existing JKH Microsoft 365 subscriptions. AI translation (Google Translate API) is usage-based and billed separately via Google Cloud. Cost increase versus v2.0 estimate is driven by web app container scaling headroom (max 10 replicas vs 3) required to support up to 1,500 concurrent users.
Appendix D: Entra ID App Registration Action Items
Appendix E: Contact Information
Document Supersession Notice
This document supersedes Architecture Design Document v2.0 (March 2026). All changes are recorded in the Revision History above. The architecture described herein reflects the final agreed deployment model incorporating the pre-deployment architecture review, capacity sizing analysis, and Entra ID app registration amendments (March 2026).
Document Version
3.0 — March 2026
Supersedes
Architecture Design Document v2.0 (March 2026)
Classification
Confidential
Prepared By
CloudNavision Private Limited