diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 00000000..f6bf661f --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,29 @@ +{ + "env": { + "node": true, + "es2020": true + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2020, + "sourceType": "module" + }, + "plugins": [ + "@typescript-eslint" + ], + "rules": { + "@typescript-eslint/no-explicit-any": "warn", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }], + "no-console": "off" + }, + "ignorePatterns": [ + "node_modules/", + "dist/", + "*.js" + ] +} diff --git a/.github/.copilot-instructions b/.github/.copilot-instructions new file mode 100644 index 00000000..cdc41fa7 --- /dev/null +++ b/.github/.copilot-instructions @@ -0,0 +1,1058 @@ +# HIPAA Attachments - Copilot Instructions + +## Repository Context + +This repository implements a HIPAA-compliant Azure Logic Apps solution for processing healthcare EDI attachments between clearinghouse and claims system. The system processes X12 275 (attachment requests), 277 (status notifications), and 278 (services review) transactions with complete audit trails and encryption. + +**Trading Partners:** +- Clearinghouse (Sender ID: {config.clearinghouseId}) - EDI clearinghouse +- Health Plan Backend (Receiver ID: {config.payerId}) - Sample Health Plan + +**Key Infrastructure:** +- Azure Logic Apps Standard (WS1 SKU) - Stateful workflow orchestration +- Azure Data Lake Storage Gen2 - HIPAA-compliant file storage with hierarchical namespace +- Azure Service Bus (Standard) - Message queuing with topics: `attachments-in`, `rfai-requests`, `edi-278`, `appeals-auth`, `auth-statuses`, `dead-letter` +- Integration Account - X12 EDI encoding/decoding +- Application Insights - Monitoring and telemetry + +**Current Workflows:** +1. **ingest275** - SFTP polling → Data Lake archive → X12 decode → claims backend API → Service Bus +2. **ingest278** - 278 transaction processing → Data Lake → Service Bus topic `edi-278` +3. **replay278** - HTTP endpoint for deterministic transaction replay +4. **rfai277** - Service Bus consumer → X12 encode → SFTP outbound +5. **process_appeals** - Appeals detection and registration from attachments +6. **process_authorizations** - Authorization request/response with 277 generation + +## Naming Conventions + +### File and Script Naming + +**PowerShell Scripts:** +- Use kebab-case: `deploy-workflows.ps1`, `fix-repo-structure.ps1`, `test-workflows.ps1` +- Approved verbs: Get, Set, New, Remove, Invoke, Test, Deploy, Configure +- Parameters in PascalCase: `-ResourceGroup`, `-LogicAppName`, `-RepoRoot` + +**Bicep Templates:** +- Use `main.bicep` for primary templates +- Module files: `-module.bicep` (e.g., `storage-module.bicep`) + +**Workflow Files:** +- Always `workflow.json` within workflow directory +- Directory names: lowercase with underscores (e.g., `ingest275`, `process_appeals`) + +**GitHub Actions:** +- Use kebab-case: `deploy-dev.yml`, `pr-lint.yml` +- Descriptive names: `deploy_logicapps_workflows_matrix_with_lint.yml` + +### Branch Naming + +``` +main # Production-ready code +├── release/* # UAT auto-deploy (e.g., release/v1.0.0) +├── feature/* # New features (e.g., feature/add-278-replay) +└── bugfix/* # Bug fixes (e.g., bugfix/fix-x12-decode) +``` + +### Azure Resource Naming + +Pattern: `{baseName}-{resource-type}` + +Examples: +- Logic App: `hipaa-attachments-la` +- Storage: `hipaaattachmentsstorage` (no hyphens for storage accounts) +- Service Bus: `hipaa-attachments-svc` +- Integration Account: `hipaa-attachments-ia` +- Application Insights: `hipaa-attachments-ai` + +### Data Lake Paths + +Date-partitioned structure: +``` +hipaa-attachments/ +├── raw/{type}/yyyy/MM/dd/ # Inbound files (275, 278, authorizations) +├── sent/{type}/yyyy/MM/dd/ # Outbound files (277) +└── processed/{type}/yyyy/MM/dd/ # Processing artifacts +``` + +## Code Standards + +### PowerShell + +**Structure:** +```powershell +<# +.SYNOPSIS + Brief description +.DESCRIPTION + Detailed description +.PARAMETER ParamName + Parameter description +.EXAMPLE + Usage example +#> +[CmdletBinding()] +param( + [Parameter(Mandatory=$true, HelpMessage="Description")] + [ValidateNotNullOrEmpty()] + [string]$ResourceGroup, + + [Parameter(Mandatory=$false)] + [switch]$WhatIf +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +try { + # Main logic +} catch { + Write-Error "Operation failed: $_" + exit 1 +} finally { + # Cleanup +} +``` + +**Conventions:** +- Use `[CmdletBinding()]` for advanced functions +- Implement try/catch/finally error handling +- Use `Set-StrictMode -Version Latest` +- Clear sensitive variables: `Clear-Variable apiKey` +- Cross-platform paths: `Join-Path` or `[System.IO.Path]::Combine()` + +### Bicep + +**Structure:** +```bicep +@description('Base name for all resources') +@minLength(3) +@maxLength(20) +param baseName string + +@description('Azure region for deployment') +@allowed(['eastus', 'westus', 'centralus']) +param location string = 'eastus' + +resource logicApp 'Microsoft.Web/sites@2023-01-01' = { + name: '${baseName}-la' + location: location + kind: 'functionapp,workflowapp' + identity: { + type: 'SystemAssigned' + } + properties: { + httpsOnly: true + siteConfig: { + minTlsVersion: '1.2' + } + } +} + +output logicAppName string = logicApp.name +output principalId string = logicApp.identity.principalId +``` + +**Conventions:** +- Use `@description` for all parameters +- Use `@allowed` for constrained values +- Enable managed identity: `type: 'SystemAssigned'` +- HTTPS only: `httpsOnly: true` +- Minimum TLS 1.2: `minTlsVersion: '1.2'` +- **Expected warnings:** "use-parent-property" for Service Bus topics (safe to ignore) + +### JSON (Logic Apps Workflows) + +**Required Structure:** +```json +{ + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "actions": {}, + "triggers": {}, + "parameters": {} + }, + "kind": "Stateful", + "parameters": {} +} +``` + +**Required Keys:** +- `definition` - Complete workflow definition +- `kind` - MUST be "Stateful" (all workflows require Logic Apps Standard) +- `parameters` - Workflow parameter definitions + +**Action Naming:** +- Use descriptive names: `Store_Raw_in_Blob`, `Decode_X12_275`, `Call_Claims_Backend_API` +- PascalCase with underscores +- Verb-Object pattern + +**Error Handling:** +```json +{ + "type": "Scope", + "actions": { + "Try_Process_275": { + "actions": { + // Main processing actions + }, + "runAfter": {} + }, + "Catch_Processing_Error": { + "actions": { + // Error handling + }, + "runAfter": { + "Try_Process_275": ["Failed", "Skipped", "TimedOut"] + } + } + } +} +``` + +### YAML (GitHub Actions) + +**Conventions:** +```yaml +name: Deploy UAT Environment + +on: + push: + branches: + - 'release/*' + +jobs: + deploy: + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Azure login via OIDC + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID_UAT }} + tenant-id: ${{ secrets.AZURE_TENANT_ID_UAT }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID_UAT }} +``` + +**Important Rules:** +- Boolean values: Use only `true` or `false` (NOT `on`, `off`, `yes`, `no`) +- Note: `on` is reserved for workflow trigger events +- Descriptive step names with action description +- Set appropriate timeouts: 30+ minutes for deployments +- Use OIDC authentication (never store credentials) +- Line length restrictions disabled for long parameter lines + +## HIPAA Compliance Requirements + +### No PII/PHI in Logs + +**Prohibited:** +```javascript +// ❌ WRONG +console.log(`Processing claim: ${claimNumber} for member: ${memberId}`); +logger.info(`Patient SSN: ${ssn}`); +``` + +**Required:** +```javascript +// ✅ CORRECT +console.log(`Processing claim: ${claimNumber.substring(0, 3)}*** for member: ***${memberId.slice(-4)}`); +logger.info(`Processing record`, { correlationId, recordType: 'claim' }); +``` + +**PHI Elements (Must Mask):** +- Member/Patient IDs +- Social Security Numbers +- Claim numbers (mask when logging) +- Provider NPIs (when linked to patients) +- Medical record numbers +- Attachment file contents + +### Secret Management + +**Never commit secrets:** +```powershell +# ❌ WRONG +$apiKey = "abc123-secret-key-456def" + +# ✅ CORRECT - Use Key Vault +$apiKey = az keyvault secret show --vault-name "hipaa-keyvault" --name "api-key" --query "value" -o tsv +``` + +**Use Managed Identity:** +```bash +# ✅ Assign roles to managed identity +az role assignment create \ + --assignee $PRINCIPAL_ID \ + --role "Storage Blob Data Contributor" \ + --scope $STORAGE_ID +``` + +**GitHub Secrets:** +- Store in GitHub Settings → Secrets → Actions +- Environment-specific: `AZURE_CLIENT_ID_DEV`, `AZURE_CLIENT_ID_UAT`, `AZURE_CLIENT_ID_PROD` +- Never print in logs: secrets are automatically masked by GitHub + +### Encryption Requirements + +**Data in Transit:** +- SFTP: SSH-2 with AES-256, minimum 2048-bit RSA keys +- HTTPS: TLS 1.2+ only, strong cipher suites +- Service Bus: AMQP over TLS + +**Data at Rest:** +- Data Lake: Azure SSE with Microsoft-managed keys (automatic) +- Service Bus: Encrypted at rest (automatic) +- Application Insights: Encrypted logs + +**Enforcement:** +```bash +# Enable HTTPS only +az webapp update --resource-group $RG --name $LA --https-only true + +# Set minimum TLS +az webapp config set --resource-group $RG --name $LA --min-tls-version "1.2" +``` + +### Audit Logging + +**Required Logging:** +- All PHI access (who, what, when, why) +- Authentication attempts +- Role assignments +- Resource changes +- Workflow runs + +**Retention:** +- Application Insights: 90 days minimum (365 recommended) +- Activity Log: 90 days default (extend for compliance) +- Storage audit logs: 365 days +- HIPAA requirement: 6 years + +### Access Control + +**Principle of Least Privilege:** +```bash +# ❌ Too permissive +az role assignment create --assignee $ID --role "Contributor" --scope "/subscriptions/$SUB" + +# ✅ Specific role on specific resource +az role assignment create --assignee $ID --role "Storage Blob Data Contributor" --scope "$STORAGE_SCOPE" +``` + +**Required Roles:** +- Storage Blob Data Contributor (Data Lake) +- Azure Service Bus Data Sender (Service Bus) +- Integration Account Contributor (X12 processing) + +## Gated Deployments + +### Environment Flow + +``` +DEV → UAT → PROD + ↓ ↓ ↓ +auto auto manual + approval +``` + +### DEV Environment + +- **Trigger:** Manual or push to `main` +- **Workflow:** `deploy-dev.yml` +- **Resource Group:** `payer-attachments-dev-rg` +- **Auto-approval:** Yes +- **Purpose:** Development and testing + +### UAT Environment + +- **Trigger:** Push to `release/*` branches (automatic) +- **Workflow:** `deploy-uat.yml` +- **Resource Group:** `payer-attachments-uat-rg` +- **Auto-approval:** Yes +- **Purpose:** User acceptance testing, pre-production validation + +### PROD Environment + +- **Trigger:** Manual workflow dispatch only +- **Workflow:** `deploy.yml` +- **Resource Group:** `payer-attachments-prod-rg` +- **Approval Required:** Yes (designated approvers) +- **Purpose:** Production system + +**Pre-PROD Checklist:** +- [ ] UAT deployment successful and tested +- [ ] All validation checks pass +- [ ] Security review completed +- [ ] Change management ticket approved +- [ ] Backup verified +- [ ] Rollback plan documented +- [ ] Stakeholders notified + +## Deployment Processes + +### Pre-Deployment Validation + +**Always run before deploying:** +```bash +# 1. Validate JSON workflows +find logicapps/workflows -name "workflow.json" -exec jq -e 'has("definition") and has("kind") and has("parameters")' {} \; + +# 2. Validate Bicep +az bicep build --file infra/main.bicep --outfile /tmp/arm.json + +# 3. Validate PowerShell +pwsh -Command "Get-Content './test-workflows.ps1' | Out-Null" + +# 4. Fix repo structure +pwsh -c "./fix_repo_structure.ps1 -RepoRoot ." + +# 5. Create workflow package +cd logicapps && zip -r ../workflows.zip workflows/ && cd .. +``` + +### Deployment Sequence + +**Infrastructure First:** +```bash +# 1. Create resource group +az group create -n $RG_NAME -l $LOCATION + +# 2. Deploy infrastructure +az deployment group create \ + -g $RG_NAME \ + -f infra/main.bicep \ + -p baseName=$BASE_NAME + +# 3. Verify resources +az resource list -g $RG_NAME --output table +``` + +**Then Workflows:** +```bash +# 4. Deploy Logic App workflows +az webapp deploy \ + --resource-group $RG_NAME \ + --name $LOGIC_APP_NAME \ + --src-path workflows.zip \ + --type zip + +# 5. Restart Logic App +az webapp restart -g $RG_NAME -n $LOGIC_APP_NAME + +# 6. Verify deployment +az webapp show -g $RG_NAME -n $LOGIC_APP_NAME --query "state" +``` + +**Post-Deployment Configuration:** +1. Configure API connections (sftp-ssh, azureblob, servicebus, integrationaccount) +2. Upload X12 schemas to Integration Account +3. Configure trading partners and agreements +4. Assign managed identity permissions +5. Set Logic App parameters +6. Test workflows with sample data + +### GitHub Actions Deployment + +**Workflow Dispatch:** +1. Navigate to GitHub → Actions +2. Select appropriate workflow (deploy-dev, deploy-uat, or deploy) +3. Click "Run workflow" +4. Provide parameters (or use defaults) +5. Monitor deployment (5-15 minutes per environment) + +**Automatic Triggers:** +- UAT: Push to `release/*` branches +- DEV: Can be configured for `main` branch + +**OIDC Authentication:** +- Uses federated credentials (no secrets stored) +- Environment-specific service principals +- Secrets: `AZURE_CLIENT_ID_*`, `AZURE_TENANT_ID_*`, `AZURE_SUBSCRIPTION_ID_*` + +## Key Files and Purposes + +### Documentation Files + +| File | Purpose | When to Consult | +|------|---------|-----------------| +| `README.md` | Architecture overview, deployment guide | Getting started, understanding system | +| `ARCHITECTURE.md` | Detailed system design, data flows, components | Understanding how system works | +| `CONTRIBUTING.md` | Development workflow, validation, code review | Contributing to repository | +| `DEPLOYMENT.md` | Step-by-step deployment procedures | Deploying to environments | +| `SECURITY.md` | HIPAA compliance, encryption, access control | Security questions | +| `TROUBLESHOOTING.md` | Common issues and solutions | Debugging problems | + +### Infrastructure Files + +| File | Purpose | Contains | +|------|---------|----------| +| `infra/main.bicep` | Primary infrastructure template | All Azure resources (Storage, Service Bus, Logic App, App Insights) | +| `attachments_logicapps_package/main.bicep` | Alternative package-based template | Similar to infra/main.bicep | + +### Workflow Files + +| File | Purpose | Trigger | Flow | +|------|---------|---------|------| +| `logicapps/workflows/ingest275/workflow.json` | 275 attachment ingestion | SFTP poll | SFTP → Data Lake → X12 → claims backend → Service Bus | +| `logicapps/workflows/ingest278/workflow.json` | 278 services review | SFTP poll | SFTP → Data Lake → X12 → Service Bus | +| `logicapps/workflows/replay278/workflow.json` | 278 replay endpoint | HTTP POST | Validate → Queue to Service Bus | +| `logicapps/workflows/rfai277/workflow.json` | 277 RFAI outbound | Service Bus | Consume → X12 encode → SFTP send | +| `logicapps/workflows/process_appeals/workflow.json` | Appeals processing | Service Bus | Detect appeals → claims backend API → RFAI publish | +| `logicapps/workflows/process_authorizations/workflow.json` | Authorization processing | Service Bus | 278 decode → claims backend → 277 encode | + +### Script Files + +| File | Purpose | Usage | +|------|---------|-------| +| `fix_repo_structure.ps1` | Normalize repository layout | `pwsh -c "./fix_repo_structure.ps1 -RepoRoot ."` | +| `test-workflows.ps1` | Comprehensive workflow testing | `pwsh -c "./test-workflows.ps1 -TestInbound275"` | +| `deploy-workflows.ps1` | Deploy Logic App workflows | `pwsh -c "./deploy-workflows.ps1 -ResourceGroup $RG"` | +| `configure-hipaa-trading-partners.ps1` | Configure X12 trading partners | Manual setup post-deployment | +| `configure-x12-agreements.ps1` | Configure X12 agreements | Manual setup post-deployment | + +### GitHub Actions Workflows + +| File | Purpose | Trigger | +|------|---------|---------| +| `.github/workflows/deploy-dev.yml` | DEV deployment | Manual/push to main | +| `.github/workflows/deploy-uat.yml` | UAT deployment | Push to release/* | +| `.github/workflows/deploy.yml` | PROD deployment | Manual with approval | +| `.github/workflows/pr-lint.yml` | PR validation | Pull request | +| `.github/workflows/sanity.yml` | Health checks | Manual | + +## API Development Standards + +### HTTP Endpoints + +**Current API Endpoints:** +- **Replay278:** `POST /api/replay278/triggers/HTTP_Replay_278_Request/invoke` + +**Request Format:** +```json +{ + "blobUrl": "hipaa-attachments/raw/278/2024/01/15/file.edi", + "fileName": "optional-custom-name" +} +``` + +**Response Format:** +```json +{ + "status": "success|error", + "message": "Description of result", + "data": { + "blobUrl": "...", + "fileName": "...", + "queueTimestamp": "2024-01-15T10:30:00Z", + "topicName": "edi-278" + } +} +``` + +**Input Validation:** +```javascript +// Always validate inputs +if (!blobUrl || !blobUrl.includes('hipaa-attachments')) { + return { + status: 'error', + message: 'Invalid blobUrl provided', + data: { providedBlobUrl: blobUrl, timestamp: new Date().toISOString() } + }; +} +``` + +**Error Handling:** +- 200: Success +- 400: Bad request (validation failure) +- 401: Unauthorized (authentication required) +- 500: Internal server error (log details, return generic message) + +### claims backend API Integration + +**Base URL:** Environment-specific (DEV/UAT/PROD) + +**Authentication:** Bearer token (OAuth 2.0) + +**Endpoints:** +- `POST /api/claims/attachments/link` - Link attachment to claim +- `POST /claims/correlate-appeal` - Correlate appeal with claim +- `POST /appeals/register` - Register appeal in claims backend + +**Retry Policy:** +```json +{ + "type": "Http", + "inputs": { + "method": "POST", + "uri": "@{parameters('backend_base_url')}/api/claims/attachments/link", + "headers": { + "Authorization": "Bearer @{parameters('backend_api_token')}", + "Content-Type": "application/json" + }, + "body": "@body('Extract_Metadata')", + "retryPolicy": { + "type": "exponential", + "count": 4, + "interval": "PT15S", + "maximumInterval": "PT1M", + "minimumInterval": "PT10S" + } + } +} +``` + +**Timeout:** 30 seconds per request + +## Container Readiness + +### Current State +- Deployed as Logic Apps Standard (App Service-based) +- Infrastructure as Code (Bicep) +- Stateful workflows with state persistence + +### Azure Container Apps Migration Path + +**Prerequisites:** +- All workflows must be containerizable +- State management strategy (Azure Storage for state) +- Environment configuration externalized +- Secrets in Key Vault + +**Container Image Requirements:** +```dockerfile +FROM mcr.microsoft.com/azure-functions/dotnet:4-dotnet6 + +# Copy workflow definitions +COPY logicapps /home/site/wwwroot + +# Set environment +ENV AzureWebJobsStorage=UseDevelopmentStorage=true +ENV FUNCTIONS_WORKER_RUNTIME=dotnet-isolated +ENV WEBSITE_HOSTNAME=0.0.0.0 + +EXPOSE 80 +``` + +**Migration Checklist:** +- [ ] Containerize Logic Apps workflows +- [ ] Test locally with Docker +- [ ] Configure Container Apps environment +- [ ] Migrate state storage +- [ ] Update VNET integration +- [ ] Test Service Bus connectivity +- [ ] Update monitoring (Application Insights) +- [ ] Performance testing +- [ ] Cutover plan + +**Benefits of Container Apps:** +- Better scaling (scale to zero) +- Consistent deployment across environments +- CI/CD integration with container registries +- Support for Dapr (future service mesh) + +## Common Tasks and Patterns + +### Validating Changes + +**Before Committing:** +```bash +# Complete validation +./validate-all.sh # If available + +# Or manually: +find logicapps/workflows -name "workflow.json" -exec jq . {} \; +az bicep build --file infra/main.bicep --outfile /tmp/arm.json +pwsh -Command "Get-Content './test-workflows.ps1' | Out-Null" +``` + +### Creating a New Workflow + +```bash +# 1. Create directory +mkdir -p logicapps/workflows/new_workflow + +# 2. Create workflow.json +cat > logicapps/workflows/new_workflow/workflow.json <<'EOF' +{ + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "actions": {}, + "triggers": {}, + "parameters": {} + }, + "kind": "Stateful", + "parameters": {} +} +EOF + +# 3. Validate +jq . logicapps/workflows/new_workflow/workflow.json + +# 4. Test and deploy +``` + +### Debugging Workflow Failures + +```bash +# 1. Check workflow runs in Azure Portal +# Navigate to Logic App → Workflows → workflow_name → Runs + +# 2. Query Application Insights +# Portal → App Insights → Logs +traces +| where timestamp > ago(1h) +| where severityLevel >= 3 +| where message contains "workflow_name" +| project timestamp, message, severityLevel + +# 3. Check dead-letter queue +az servicebus topic subscription dead-letter list \ + --resource-group $RG \ + --namespace-name $NS \ + --topic-name attachments-in \ + --subscription-name default +``` + +### Testing Workflows + +```powershell +# Test 275 ingestion +pwsh -c "./test-workflows.ps1 -TestInbound275 -ResourceGroup 'payer-attachments-uat-rg' -LogicAppName 'hipaa-attachments-uat-la'" + +# Test 278 replay +curl -X POST "https://hipaa-attachments-uat-la.azurewebsites.net/api/replay278/..." \ + -H "Content-Type: application/json" \ + -d '{"blobUrl": "hipaa-attachments/raw/278/2024/01/15/test.edi"}' +``` + +### Adding a Service Bus Topic + +```bicep +// In infra/main.bicep +resource newTopic 'Microsoft.ServiceBus/namespaces/topics@2022-10-01-preview' = { + parent: serviceBusNamespace + name: 'new-topic-name' + properties: { + maxSizeInMegabytes: 1024 + defaultMessageTimeToLive: 'P14D' + enableBatchedOperations: true + requiresDuplicateDetection: true + duplicateDetectionHistoryTimeWindow: 'PT10M' + } +} +``` + +### Querying Application Insights + +```kusto +// Failed workflows +traces +| where timestamp > ago(24h) +| where severityLevel >= 3 +| where message contains "workflow" +| project timestamp, message, severityLevel + +// claims backend API performance +dependencies +| where name contains "backend" +| summarize avg(duration), percentile(duration, 95) by bin(timestamp, 1h) + +// PHI access audit +customEvents +| where name in ("file_accessed", "claim_linked", "attachment_processed") +| extend userId = tostring(customDimensions["userId"]) +| project timestamp, userId, name +| order by timestamp desc +``` + +## Frequently Used Commands + +### Azure CLI + +```bash +# Login +az login + +# Set subscription +az account set --subscription $SUBSCRIPTION_ID + +# List resources +az resource list --resource-group $RG --output table + +# Deploy infrastructure +az deployment group create -g $RG -f infra/main.bicep -p baseName=$BASE_NAME + +# Deploy workflows +az webapp deploy --resource-group $RG --name $LA --src-path workflows.zip --type zip + +# Restart Logic App +az webapp restart -g $RG -n $LA + +# Get Logic App status +az webapp show -g $RG -n $LA --query "{name:name, state:state}" -o table + +# Assign managed identity role +az role assignment create --assignee $PRINCIPAL_ID --role "Storage Blob Data Contributor" --scope $SCOPE + +# Query Activity Log +az monitor activity-log list --resource-group $RG --start-time "2024-01-01" --query "[?level=='Error']" +``` + +### PowerShell + +```powershell +# Test workflows +pwsh -c "./test-workflows.ps1 -TestInbound275" + +# Fix repository structure +pwsh -c "./fix_repo_structure.ps1 -RepoRoot ." + +# Deploy workflows +pwsh -c "./deploy-workflows.ps1 -ResourceGroup 'rg-name' -LogicAppName 'la-name'" + +# Configure trading partners +pwsh -c "./configure-hipaa-trading-partners.ps1 -ResourceGroup 'rg-name' -IntegrationAccountName 'ia-name'" +``` + +### Validation Commands + +```bash +# JSON validation +find logicapps/workflows -name "workflow.json" -exec jq -e 'has("definition") and has("kind") and has("parameters")' {} \; + +# Bicep validation +az bicep build --file infra/main.bicep --outfile /tmp/arm.json + +# PowerShell syntax +pwsh -Command "Get-Content './test-workflows.ps1' | Out-Null" + +# Create workflow package +cd logicapps && zip -r ../workflows.zip workflows/ && cd .. + +# Verify package +unzip -l workflows.zip | grep workflow.json +``` + +### Git Commands + +```bash +# Create feature branch +git checkout -b feature/new-feature + +# Commit changes +git add . +git commit -m "feat: Add new feature" + +# Push branch +git push origin feature/new-feature + +# Create release branch for UAT +git checkout -b release/v1.0.0 +git push origin release/v1.0.0 # Triggers UAT deployment +``` + +## Security Considerations for Copilot + +### What Copilot Should Know + +1. **This is HIPAA-regulated code** - Extra care required for PHI handling +2. **All workflows must be Stateful** - Logic Apps Standard requirement +3. **Never hardcode secrets** - Use Key Vault or managed identity +4. **Mask PHI in logs** - Never log full member IDs, SSNs, or claim details +5. **Validate all inputs** - Especially for HTTP endpoints +6. **Use retry policies** - claims backend API and SFTP can have transient failures +7. **Encryption everywhere** - TLS 1.2+ for transit, SSE for rest +8. **Audit everything** - Log PHI access with correlation IDs + +### What Copilot Should Not Do + +1. **❌ Don't suggest storing credentials in code** +2. **❌ Don't log PHI without masking** +3. **❌ Don't create Stateless workflows** (all must be Stateful) +4. **❌ Don't suggest anonymous HTTP endpoints** +5. **❌ Don't bypass input validation** +6. **❌ Don't suggest direct connection strings** (use managed identity) +7. **❌ Don't suggest plain HTTP** (HTTPS only) +8. **❌ Don't recommend disabling encryption** + +### Secure Code Review Checklist + +When reviewing code, Copilot should verify: +- [ ] No hardcoded secrets or credentials +- [ ] No PHI logged in plain text +- [ ] Input validation present for all user inputs +- [ ] Error messages don't expose sensitive information +- [ ] Managed identity used (not connection strings) +- [ ] Encryption enabled (TLS 1.2+, HTTPS only) +- [ ] Retry policies implemented for external calls +- [ ] Audit logging for PHI access +- [ ] Workflow kind is "Stateful" +- [ ] Required workflow keys present (definition, kind, parameters) + +### Example: Secure vs Insecure + +**Insecure:** +```powershell +# ❌ WRONG +$apiKey = "your-api-key-here" +$connectionString = "DefaultEndpointsProtocol=https;AccountName=storage;AccountKey=your-account-key" +Write-Host "Processing claim $claimNumber for member $memberId" +Invoke-RestMethod -Uri $url -Headers @{ "X-API-Key" = $apiKey } +``` + +**Secure:** +```powershell +# ✅ CORRECT +$apiKey = az keyvault secret show --vault-name "hipaa-kv" --name "api-key" --query "value" -o tsv +# Use managed identity for storage (no connection string needed) +Write-Host "Processing claim $(($claimNumber).Substring(0,3))*** for member ***$(($memberId).Substring($memberId.Length-4))" +Invoke-RestMethod -Uri $url -Authentication Bearer -Token $(ConvertTo-SecureString $apiKey -AsPlainText) +``` + +## Working with Copilot Chat + +### Effective Prompts + +**Good:** +- "How do I add a new Service Bus topic to the infrastructure?" +- "Create a Stateful Logic Apps workflow for processing 999 transactions" +- "Show me how to mask PHI in Application Insights logs" +- "What's the retry policy configuration for claims backend API calls?" + +**Better:** +- "Add a new Service Bus topic called 'auth-responses' to infra/main.bicep with 14-day TTL and duplicate detection" +- "Create a Stateful workflow in logicapps/workflows/ingest999/ that polls SFTP, archives to Data Lake, and publishes to Service Bus" +- "Update the logging in ingest275 workflow to mask claim numbers (show first 3 chars) and member IDs (show last 4 chars)" +- "Show the retry policy we use for claims backend API in ingest275 workflow and explain why we use 4 retries with 15-second intervals" + +### Context to Provide + +When asking Copilot for help, include: +1. **Environment:** DEV, UAT, or PROD +2. **Component:** Workflow name, Bicep file, script name +3. **Error message:** Full error text if available +4. **What you've tried:** Validation steps, troubleshooting done +5. **Expected behavior:** What should happen +6. **Actual behavior:** What actually happens + +### Example Interaction + +**User:** "The ingest275 workflow is failing with an X12 decode error in UAT. I've verified the trading partners are configured correctly (Clearinghouse: {config.clearinghouseId}, Health Plan: {config.payerId}). The error says 'Schema not found for transaction set 275'." + +**Copilot should respond with:** +1. Check if X12_005010X210_275 schema is uploaded to Integration Account +2. Verify agreement Clearinghouse-to-HealthPlan-275-Receive is active +3. Check ISA/GS identifiers in the actual EDI file +4. Review Application Insights for detailed error +5. Provide commands to verify schema and agreement configuration + +## Timing and Performance Expectations + +### Validation Commands + +- **JSON validation:** <1 second (set timeout: 10+ seconds) +- **Bicep validation:** ~4 seconds (set timeout: 30+ seconds) +- **PowerShell validation:** <1 second (set timeout: 10+ seconds) +- **Repo structure fix:** ~1 second (set timeout: 30+ seconds) +- **ZIP creation:** <1 second (set timeout: 10+ seconds) + +### Deployment Operations + +- **Bicep deployment:** 5-10 minutes (set timeout: 30+ minutes) +- **Workflow ZIP deployment:** 2-5 minutes (set timeout: 15+ minutes) +- **Complete CI pipeline:** 10-20 minutes per environment (set timeout: 60+ minutes) +- **Logic App restart:** 1-2 minutes + +### Workflow Execution + +- **ingest275:** 5-15 seconds per file +- **ingest278:** 5-15 seconds per file +- **rfai277:** 3-8 seconds per message +- **replay278:** 1-2 seconds (just queueing) +- **process_appeals:** 10-20 seconds (includes claims backend API calls) +- **process_authorizations:** 15-30 seconds (includes claims backend API and 277 generation) + +### NEVER CANCEL + +- Azure deployments (may leave resources in inconsistent state) +- Logic App restarts (may corrupt state) +- Long-running validation commands (they're just slow, not hung) +- CI/CD pipelines (will break deployment) + +## Additional Context + +### Integration Account Setup + +**Required Schemas:** +- X12_005010X210_275 (Attachment Request) +- X12_005010X212_277 (Status Notification) +- X12_005010X217_278 (Services Review) + +**Trading Partners:** +- Clearinghouse: Qualifier=ZZ, Value={config.clearinghouseId} +- Health Plan: Qualifier=ZZ, Value={config.payerId} + +**Agreements:** +1. Clearinghouse-to-HealthPlan-275-Receive (Inbound 275) +2. HealthPlan-to-Clearinghouse-277-Send (Outbound 277) +3. payer-278-Processing (Internal 278) + +### Data Lake Structure + +``` +hipaa-attachments/ +├── raw/ +│ ├── 275/yyyy/MM/dd/ # Inbound attachment requests +│ ├── 278/yyyy/MM/dd/ # Inbound services review +│ └── authorizations/yyyy/MM/dd/ # Authorization transactions +├── sent/ +│ └── 277/yyyy/MM/dd/ # Outbound status notifications +└── processed/ + └── {type}/yyyy/MM/dd/ # Processing artifacts +``` + +### Service Bus Topics + +| Topic | Purpose | Publishers | Subscribers | +|-------|---------|------------|-------------| +| `attachments-in` | Processed 275 events | ingest275 | process_appeals, analytics | +| `rfai-requests` | RFAI generation requests | claims backend, process_appeals | rfai277 | +| `edi-278` | 278 transaction queue | ingest278, replay278 | process_authorizations | +| `appeals-auth` | Appeals and auth events | process_appeals | Downstream systems | +| `auth-statuses` | Authorization status events | process_authorizations | Tracking systems | +| `dead-letter` | Failed messages | All topics | Monitoring, replay | + +### Error Codes + +**claims backend API:** +- 400: Invalid request (check payload) +- 401: Authentication failure (check token) +- 404: Claim not found (verify claim number) +- 409: Duplicate attachment (already linked) +- 500: Internal error (retry with backoff) +- 503: Service unavailable (retry with backoff) + +**X12 Decode:** +- Schema not found: Upload schema to Integration Account +- Trading partner not found: Configure partner in Integration Account +- Invalid ISA/GS: Check sender/receiver identifiers +- Segment error: Validate EDI file format + +## References + +For more detailed information, consult: +- **[README.md](../README.md)** - Architecture overview and quick start +- **[ARCHITECTURE.md](../ARCHITECTURE.md)** - Detailed system design and data flows +- **[CONTRIBUTING.md](../CONTRIBUTING.md)** - Development workflow and standards +- **[DEPLOYMENT.md](../DEPLOYMENT.md)** - Step-by-step deployment procedures +- **[SECURITY.md](../SECURITY.md)** - HIPAA compliance and security practices +- **[TROUBLESHOOTING.md](../TROUBLESHOOTING.md)** - Common issues and solutions + +--- + +**Last Updated:** 2024-11-16 +**Maintained By:** Development Team +**Version:** 1.0 diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..3d396358 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,15 @@ +# These are supported funding model platforms + +github: [AURELIANWARE] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry +polar: # Replace with a single Polar username +buy_me_a_coffee: # Replace with a single Buy Me a Coffee username +thanks_dev: # Replace with a single thanks.dev username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 00000000..4a5922f1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,145 @@ +name: Bug Report +description: Report a bug or issue with Cloud Health Office +title: "[Bug]: " +labels: ["bug", "triage"] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to report a bug! Please fill out the form below to help us investigate and fix the issue. + + **Important**: Never include Protected Health Information (PHI), real patient data, or production credentials in bug reports. + + - type: checkboxes + id: checklist + attributes: + label: Pre-submission Checklist + options: + - label: I have searched existing issues to ensure this bug has not already been reported + required: true + - label: I have reviewed the [TROUBLESHOOTING.md](../TROUBLESHOOTING.md) guide + required: true + - label: This report does not contain any PHI, real patient data, or production credentials + required: true + + - type: dropdown + id: component + attributes: + label: Affected Component + description: Which component of Cloud Health Office is affected? + options: + - Logic Apps Workflows (ingest275, ingest278, rfai277, replay278) + - Infrastructure (Bicep/ARM) + - Service Bus Messaging + - Data Lake Storage + - Integration Account (X12/EDI) + - GitHub Actions / CI/CD + - Documentation + - API Connections + - Other + validations: + required: true + + - type: dropdown + id: environment + attributes: + label: Environment + description: In which environment did you encounter this bug? + options: + - Development (local) + - DEV (Azure) + - UAT (Azure) + - Production (Azure) + - Not applicable + validations: + required: true + + - type: textarea + id: description + attributes: + label: Bug Description + description: A clear and concise description of what the bug is. + placeholder: Describe the bug... + validations: + required: true + + - type: textarea + id: steps + attributes: + label: Steps to Reproduce + description: Steps to reproduce the behavior + placeholder: | + 1. Go to '...' + 2. Click on '...' + 3. Scroll down to '...' + 4. See error + validations: + required: true + + - type: textarea + id: expected + attributes: + label: Expected Behavior + description: A clear and concise description of what you expected to happen. + placeholder: What should have happened? + validations: + required: true + + - type: textarea + id: actual + attributes: + label: Actual Behavior + description: A clear and concise description of what actually happened. + placeholder: What actually happened? + validations: + required: true + + - type: textarea + id: logs + attributes: + label: Relevant Logs/Error Messages + description: | + Please copy and paste any relevant log output or error messages. + **Important**: Redact any sensitive information before pasting. + render: shell + placeholder: | + Paste error logs here (redact any sensitive information)... + + - type: dropdown + id: edi-type + attributes: + label: EDI Transaction Type (if applicable) + description: If this bug involves EDI processing, which transaction type? + options: + - Not applicable + - X12 275 (Attachment) + - X12 277 (RFAI) + - X12 278 (Prior Authorization) + - Other X12 transaction + + - type: textarea + id: additional + attributes: + label: Additional Context + description: Add any other context about the problem here (screenshots, configuration details, etc.) + placeholder: Any additional information that might help us investigate... + + - type: dropdown + id: severity + attributes: + label: Severity + description: How severe is this bug? + options: + - Critical (system down, data loss, security issue) + - High (major feature broken, significant impact) + - Medium (feature partially broken, workaround exists) + - Low (minor issue, cosmetic) + validations: + required: true + + - type: textarea + id: workaround + attributes: + label: Workaround + description: If you've found a workaround, please share it to help others. + placeholder: Describe any workaround you've found... diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..a6786767 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,11 @@ +blank_issues_enabled: false +contact_links: + - name: Security Vulnerability + url: https://github.com/aurelianware/cloudhealthoffice/security/policy + about: Report security vulnerabilities through our security policy + - name: Questions & Discussions + url: https://github.com/aurelianware/cloudhealthoffice/discussions + about: Ask questions and discuss ideas with the community + - name: Documentation + url: https://github.com/aurelianware/cloudhealthoffice/blob/main/README.md + about: Read the documentation before opening an issue diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 00000000..cb7adf50 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,161 @@ +name: Feature Request +description: Suggest a new feature or enhancement for Cloud Health Office +title: "[Feature]: " +labels: ["enhancement", "triage"] +body: + - type: markdown + attributes: + value: | + Thanks for suggesting a feature for Cloud Health Office! Please fill out the form below to help us understand your request. + + Before submitting, please: + - Search existing issues to see if this feature has already been requested + - Review the [ROADMAP.md](../ROADMAP.md) to see if this is already planned + + - type: checkboxes + id: checklist + attributes: + label: Pre-submission Checklist + options: + - label: I have searched existing issues and discussions to ensure this feature has not already been requested + required: true + - label: I have reviewed the project roadmap + required: true + + - type: dropdown + id: category + attributes: + label: Feature Category + description: Which area of Cloud Health Office would this feature affect? + options: + - EDI Processing (275, 277, 278 transactions) + - Integration Account / Trading Partners + - Workflow Automation + - API / Integrations + - Infrastructure / Deployment + - Monitoring / Observability + - Security / Compliance + - Developer Experience + - Documentation + - Other + validations: + required: true + + - type: textarea + id: problem + attributes: + label: Problem Statement + description: | + Describe the problem or pain point this feature would solve. + A clear problem statement helps us understand the "why" behind your request. + placeholder: | + As a [type of user], I want [goal] so that [benefit]. + + Currently, I have to... + validations: + required: true + + - type: textarea + id: solution + attributes: + label: Proposed Solution + description: Describe the solution you'd like to see implemented. + placeholder: Describe your proposed solution in detail... + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternatives Considered + description: Have you considered any alternative solutions or workarounds? + placeholder: Describe any alternatives you've considered... + + - type: dropdown + id: edi-standard + attributes: + label: EDI Standard Impact (if applicable) + description: If this feature involves EDI processing, which standards are affected? + options: + - Not applicable + - X12 275 (Additional Information to Support a Health Care Claim) + - X12 277 (Health Care Claim Status Request for Additional Information) + - X12 278 (Health Care Services Review) + - Multiple X12 transaction types + - New EDI standard support + + - type: dropdown + id: compliance + attributes: + label: Compliance Considerations + description: Does this feature have HIPAA or other compliance implications? + options: + - No compliance impact + - May affect PHI handling + - May affect audit logging + - May affect access controls + - May affect encryption + - Multiple compliance areas + - Unsure - needs review + validations: + required: true + + - type: textarea + id: use-cases + attributes: + label: Use Cases + description: | + Describe specific use cases or scenarios where this feature would be valuable. + Include any real-world examples (without PHI or sensitive data). + placeholder: | + Use Case 1: ... + Use Case 2: ... + + - type: dropdown + id: priority + attributes: + label: Suggested Priority + description: How important is this feature to you? + options: + - Critical (blocking production use) + - High (significantly improves workflow) + - Medium (nice to have, improves efficiency) + - Low (minor enhancement) + validations: + required: true + + - type: textarea + id: implementation + attributes: + label: Implementation Ideas + description: | + If you have ideas about how this could be implemented, share them here. + This could include technical approaches, Azure services to use, workflow designs, etc. + placeholder: Technical implementation suggestions... + + - type: checkboxes + id: contribution + attributes: + label: Contribution Interest + description: Would you be interested in contributing to this feature? + options: + - label: I would be willing to submit a PR implementing this feature + - label: I would be willing to help test this feature + - label: I would be willing to help document this feature + + - type: textarea + id: additional + attributes: + label: Additional Context + description: Add any other context, screenshots, or mockups about the feature request here. + placeholder: Any additional information... + + - type: textarea + id: references + attributes: + label: References + description: | + Links to relevant documentation, similar features in other projects, or supporting materials. + placeholder: | + - Link 1 + - Link 2 diff --git a/.github/ISSUE_TEMPLATE/v4-analytics-reporting.md b/.github/ISSUE_TEMPLATE/v4-analytics-reporting.md new file mode 100644 index 00000000..0a435187 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/v4-analytics-reporting.md @@ -0,0 +1,582 @@ +--- +name: "[v4.0] Advanced Analytics and Reporting" +about: Implement analytics dashboards for claims trends, fraud detection, and payer performance +title: "[v4.0] Implement Advanced Analytics and Reporting Dashboards" +labels: enhancement, analytics, v4.0, priority-medium +assignees: aurelianware +--- + +## Overview +Add advanced analytics for claims trends, fraud risk detection, and payer performance metrics. Integrate with existing Prometheus/Grafana monitoring stack and tie to Stripe for metered premium reports. Use tenant management to ensure data isolation per payer. + +## Objectives +- ✅ Real-time claims analytics dashboards (adjudication time, denial rates, cost trends) +- ✅ Fraud detection with basic ML (anomaly detection for suspicious claims) +- ✅ Payer performance scorecards (network efficiency, provider satisfaction) +- ✅ Exportable reports (PDF/CSV) gated behind Stripe subscriptions +- ✅ Anonymized PHI in aggregates (HIPAA compliance) +- ✅ Prepare foundation for Q3 2026 advanced AI features + +## Architecture + +``` +┌─────────────────────────────────────────────────┐ +│ Analytics & Reporting Stack │ +├─────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────┐ ┌─────────────┐ ┌────────┐│ +│ │ Grafana │ │ PowerBI/ │ │ Jupyter││ +│ │ Dashboards │ │ Embedded │ │ Notebooks││ +│ └──────┬──────┘ └──────┬──────┘ └───┬────┘│ +│ │ │ │ │ +│ └──────────────────┴───────────────┘ │ +│ │ │ +│ ┌──────▼──────┐ │ +│ │ Analytics │ │ +│ │ Service │ │ +│ └──────┬───────┘ │ +│ │ │ +│ ┌────────────────┴────────────────┐ │ +│ │ │ │ +│ ┌────▼────┐ ┌──────────┐ ┌──────────▼───┐ │ +│ │ Cosmos │ │ Kafka │ │ PostgreSQL │ │ +│ │ DB │ │ Stream │ │ Analytics │ │ +│ └─────────┘ └──────────┘ └──────────────┘ │ +│ │ +│ ML Pipeline (Python/PyTorch) │ +│ Stripe Metering (Premium Reports) │ +└──────────────────────────────────────────────────┘ +``` + +## Implementation Steps + +### Phase 1: Analytics Service (Weeks 1-2) + +#### 1.1 Create Analytics Microservice +```bash +mkdir -p services/analytics-service +cd services/analytics-service +dotnet new webapi -n AnalyticsService +``` + +**Project Structure:** +``` +services/analytics-service/ +├── Controllers/ +│ ├── AnalyticsController.cs +│ ├── ReportsController.cs +│ └── MetricsController.cs +├── Services/ +│ ├── IAnalyticsService.cs +│ ├── AnalyticsService.cs +│ ├── IReportGenerator.cs +│ └── ReportGenerator.cs (PDF/CSV export) +├── Models/ +│ ├── ClaimAnalytics.cs +│ ├── TrendData.cs +│ └── PerformanceMetrics.cs +├── Data/ +│ ├── AnalyticsRepository.cs (PostgreSQL for aggregates) +│ └── EventConsumer.cs (Kafka consumer) +└── ML/ + ├── FraudDetectionModel.cs + └── AnomalyDetector.cs +``` + +#### 1.2 API Endpoints + +```csharp +// Controllers/AnalyticsController.cs +[ApiController] +[Route("api/v1/analytics")] +public class AnalyticsController : ControllerBase +{ + [HttpGet("claims/trends")] + public async Task GetClaimTrends( + [FromQuery] string tenantId, + [FromQuery] DateTime startDate, + [FromQuery] DateTime endDate) + { + return new ClaimTrends + { + TotalClaims = 15234, + AdjudicatedClaims = 14891, + DeniedClaims = 343, + AvgAdjudicationTime = TimeSpan.FromMinutes(2.3), + DailyVolume = new[] { /* time series data */ } + }; + } + + [HttpGet("claims/denial-reasons")] + public async Task GetDenialReasons( + [FromQuery] string tenantId, + [FromQuery] DateTime startDate) + { + // Top denial reasons by count + return new DenialReasonBreakdown + { + Reasons = new[] + { + new DenialReason { Code = "CO-50", Description = "Non-covered service", Count = 128 }, + new DenialReason { Code = "PR-1", Description = "Deductible", Count = 89 }, + new DenialReason { Code = "CO-97", Description = "Payment adjusted", Count = 56 } + } + }; + } + + [HttpGet("performance/payer-scorecard")] + public async Task GetPayerScorecard([FromQuery] string tenantId) + { + return new PayerScorecard + { + PayerName = "Blue Shield California", + Metrics = new + { + ClaimsVolume90d = 12450, + AvgTimeToPayment = TimeSpan.FromDays(14.2), + AutoApprovalRate = 0.92, + DenialRate = 0.023, + ProviderSatisfactionScore = 4.3, // out of 5 + NetworkSize = 18234, + MemberCount = 245000 + }, + Trends = new + { + ClaimsVolumeChange = 0.15, // +15% vs prior 90d + PaymentSpeedChange = -0.08 // -8% (improvement) + } + }; + } +} +``` + +#### 1.3 Real-Time Data Pipeline + +**Kafka Consumer for Aggregation:** +```csharp +// Data/EventConsumer.cs +public class ClaimEventConsumer : BackgroundService +{ + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + var consumer = new ConsumerBuilder(_config).Build(); + consumer.Subscribe("claims-adjudication"); + + while (!stoppingToken.IsCancellationRequested) + { + var result = consumer.Consume(stoppingToken); + var claimEvent = result.Message.Value; + + // Aggregate in PostgreSQL + await _analyticsRepo.UpdateAggregatesAsync(new + { + TenantId = claimEvent.TenantId, + Date = claimEvent.AdjudicatedAt.Date, + TotalClaims = 1, + TotalAmount = claimEvent.BilledAmount, + AvgAdjudicationTime = claimEvent.ProcessingTime + }); + } + } +} +``` + +**PostgreSQL Schema for Aggregates:** +```sql +CREATE TABLE claim_daily_aggregates ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + tenant_id VARCHAR(255) NOT NULL, + date DATE NOT NULL, + total_claims INT DEFAULT 0, + adjudicated_claims INT DEFAULT 0, + denied_claims INT DEFAULT 0, + total_billed_amount DECIMAL(12,2) DEFAULT 0, + total_paid_amount DECIMAL(12,2) DEFAULT 0, + avg_adjudication_time_ms INT DEFAULT 0, + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW(), + UNIQUE(tenant_id, date) +); + +CREATE INDEX idx_tenant_date ON claim_daily_aggregates(tenant_id, date DESC); +``` + +### Phase 2: Grafana Dashboards (Week 2-3) + +#### 2.1 Deploy Grafana +```yaml +# k8s/monitoring/grafana-deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana + namespace: cho-svcs +spec: + replicas: 1 + template: + spec: + containers: + - name: grafana + image: grafana/grafana:10.2.0 + env: + - name: GF_SECURITY_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: grafana-secret + key: admin-password + - name: GF_DATABASE_TYPE + value: postgres + - name: GF_DATABASE_HOST + value: postgres.cho-svcs:5432 + volumeMounts: + - name: grafana-storage + mountPath: /var/lib/grafana +``` + +#### 2.2 Create Dashboards + +**Claims Overview Dashboard:** +- **Panel 1:** Total claims processed (gauge) +- **Panel 2:** Adjudication time trend (time series) +- **Panel 3:** Denial rate by reason (pie chart) +- **Panel 4:** Claims volume heatmap (by hour/day) +- **Panel 5:** Top providers by volume (bar chart) + +**Payer Performance Dashboard:** +- **Panel 1:** Payer scorecard (stat panels) +- **Panel 2:** Network growth (time series) +- **Panel 3:** Provider satisfaction trend (line chart) +- **Panel 4:** Cost per claim (area chart) + +**Fraud Detection Dashboard:** +- **Panel 1:** Anomaly score distribution (histogram) +- **Panel 2:** Flagged claims (table with drill-down) +- **Panel 3:** Fraud patterns (network graph - future) + +#### 2.3 Embed in Portals +```razor + +@page "/analytics" +@attribute [Authorize(Policy = "PremiumFeatures")] + + + +Export Dashboard +``` + +### Phase 3: Machine Learning (Weeks 3-4) + +#### 3.1 Fraud Detection Model + +**Python Service for ML:** +```python +# functions/ClaimRiskScorer/main.py +import torch +import numpy as np +from sklearn.ensemble import IsolationForest + +class FraudDetector: + def __init__(self): + self.model = IsolationForest(contamination=0.01) # 1% fraud rate + + def train(self, claims_data): + """Train on historical claims with known fraud labels""" + features = self.extract_features(claims_data) + self.model.fit(features) + + def extract_features(self, claims): + """Extract features for anomaly detection""" + return np.array([ + claims['billed_amount'], + claims['service_count'], + claims['diagnosis_complexity'], + claims['provider_risk_score'], + claims['time_since_last_claim_hours'], + claims['distance_from_member_miles'] + ]) + + def predict_risk_score(self, claim): + """Return risk score 0-1 (1 = high fraud risk)""" + features = self.extract_features([claim]) + anomaly_score = self.model.decision_function(features)[0] + # Normalize to 0-1 range + return 1 / (1 + np.exp(anomaly_score)) + +# Flask API endpoint +from flask import Flask, request, jsonify +app = Flask(__name__) +detector = FraudDetector() + +@app.route('/score', methods=['POST']) +def score_claim(): + claim = request.json + risk_score = detector.predict_risk_score(claim) + + return jsonify({ + 'claim_id': claim['id'], + 'risk_score': float(risk_score), + 'flagged': risk_score > 0.75, + 'reasons': get_risk_factors(claim) if risk_score > 0.75 else [] + }) +``` + +#### 3.2 Integrate with Claims Service + +```csharp +// services/claims-service/Services/FraudCheckService.cs +public class FraudCheckService +{ + private readonly HttpClient _mlClient; + + public async Task CheckClaimAsync(Claim claim) + { + var response = await _mlClient.PostAsJsonAsync( + "http://claim-risk-scorer.cho-svcs/score", + new + { + id = claim.ClaimId, + billed_amount = claim.BilledAmount, + service_count = claim.ServiceLines.Count, + diagnosis_complexity = CalculateComplexity(claim.DiagnosisCodes), + provider_risk_score = await GetProviderRiskScore(claim.ProviderId), + time_since_last_claim_hours = await GetTimeSinceLastClaim(claim.MemberId), + distance_from_member_miles = await CalculateDistance(claim) + }); + + return await response.Content.ReadFromJsonAsync(); + } +} +``` + +#### 3.3 Anomaly Alerting + +```csharp +// Trigger alert if fraud risk > 75% +if (fraudScore.RiskScore > 0.75) +{ + await _alertService.SendAlertAsync(new Alert + { + Type = "FraudSuspicion", + Severity = "High", + TenantId = claim.TenantId, + ClaimId = claim.ClaimId, + Message = $"Claim flagged for fraud review. Risk score: {fraudScore.RiskScore:P0}", + Reasons = fraudScore.Reasons + }); + + // Hold claim for manual review + claim.Status = "PendingFraudReview"; + await _claimsRepo.UpdateAsync(claim); +} +``` + +### Phase 4: Report Generation (Week 4-5) + +#### 4.1 PDF Export with QuestPDF + +```csharp +// Services/ReportGenerator.cs +using QuestPDF.Fluent; +using QuestPDF.Helpers; + +public class ReportGenerator : IReportGenerator +{ + public byte[] GenerateClaimsSummaryPdf(ClaimAnalytics analytics, string tenantName) + { + return Document.Create(container => + { + container.Page(page => + { + page.Header().Text($"{tenantName} - Claims Summary Report") + .FontSize(20).Bold(); + + page.Content().Column(column => + { + column.Item().Text($"Report Period: {analytics.StartDate:d} - {analytics.EndDate:d}"); + + column.Item().PaddingTop(10).Table(table => + { + table.ColumnsDefinition(columns => + { + columns.RelativeColumn(); + columns.RelativeColumn(); + }); + + table.Cell().Text("Total Claims").Bold(); + table.Cell().Text(analytics.TotalClaims.ToString("N0")); + + table.Cell().Text("Adjudicated Claims").Bold(); + table.Cell().Text(analytics.AdjudicatedClaims.ToString("N0")); + + table.Cell().Text("Denial Rate").Bold(); + table.Cell().Text($"{analytics.DenialRate:P2}"); + + table.Cell().Text("Avg Adjudication Time").Bold(); + table.Cell().Text($"{analytics.AvgAdjudicationTime.TotalMinutes:N1} min"); + }); + + column.Item().PaddingTop(20).Image( + GenerateTrendChart(analytics.DailyVolume) + ); + }); + + page.Footer().AlignCenter().Text(text => + { + text.Span("Generated by Cloud Health Office - "); + text.Hyperlink("cloudhealthoffice.com", "https://cloudhealthoffice.com"); + }); + }); + }).GeneratePdf(); + } +} +``` + +#### 4.2 CSV Export + +```csharp +public string GenerateClaimsCsv(List claims) +{ + var csv = new StringBuilder(); + csv.AppendLine("Claim ID,Member ID,Provider NPI,Service Date,Billed Amount,Paid Amount,Status"); + + foreach (var claim in claims) + { + csv.AppendLine($"{claim.ClaimId},{claim.MemberId},{claim.ProviderNpi}," + + $"{claim.ServiceDate:yyyy-MM-dd},{claim.BilledAmount:C}," + + $"{claim.PaidAmount:C},{claim.Status}"); + } + + return csv.ToString(); +} +``` + +#### 4.3 Stripe Metering for Reports + +```csharp +// Controllers/ReportsController.cs +[HttpPost("export/pdf")] +[Authorize(Policy = "PremiumFeatures")] +public async Task ExportPdf([FromQuery] string tenantId) +{ + // Generate report + var analytics = await _analyticsService.GetClaimTrendsAsync(tenantId, startDate, endDate); + var pdf = _reportGenerator.GenerateClaimsSummaryPdf(analytics, tenantId); + + // Meter in Stripe (if usage-based tier) + await _stripeService.ReportUsageAsync(tenantId, "report.generated", 1); + + return File(pdf, "application/pdf", $"claims-summary-{DateTime.UtcNow:yyyyMMdd}.pdf"); +} +``` + +### Phase 5: Compliance & Anonymization (Week 5) + +#### 5.1 PHI Masking + +```csharp +public class PhiMasker +{ + public ClaimAnalytics AnonymizeForReporting(List claims) + { + return new ClaimAnalytics + { + TotalClaims = claims.Count, + AverageBilledAmount = claims.Average(c => c.BilledAmount), + // DO NOT include: MemberId, SSN, Name, DOB, Address + // DO include: Aggregates, trends, anonymized demographics + AgeBrackets = claims + .GroupBy(c => GetAgeBracket(c.MemberAge)) + .ToDictionary(g => g.Key, g => g.Count()), + GenderDistribution = claims + .GroupBy(c => c.MemberGender) + .ToDictionary(g => g.Key, g => g.Count()) + }; + } + + private string GetAgeBracket(int age) + { + return age switch + { + < 18 => "0-17", + < 35 => "18-34", + < 50 => "35-49", + < 65 => "50-64", + _ => "65+" + }; + } +} +``` + +#### 5.2 Audit Logging + +```csharp +logger.LogInformation("User {UserId} generated analytics report for tenant {TenantId}. " + + "Date range: {StartDate} - {EndDate}. Row count: {RowCount}", + userId, tenantId, startDate, endDate, claims.Count); +// Never log actual claim data or PHI +``` + +## Tech Stack +- **Backend:** .NET 8 Analytics Service +- **Data Store:** PostgreSQL (aggregates), Cosmos DB (raw data) +- **Streaming:** Kafka (real-time events) +- **Visualization:** Grafana 10.2, ApexCharts.NET (embedded) +- **ML:** Python 3.11, PyTorch, scikit-learn, Isolation Forest +- **Reporting:** QuestPDF (PDF), CsvHelper (CSV) +- **Billing:** Stripe metering for premium reports + +## Testing + +### Load Tests +```bash +# Simulate 1000 concurrent analytics queries +k6 run --vus 1000 --duration 30s analytics-load-test.js +``` + +### Accuracy Tests +```python +# Validate ML model with labeled fraud dataset +from sklearn.metrics import precision_recall_fscore_support + +y_true = [0, 0, 1, 1, 0, 1] # Actual fraud labels +y_pred = model.predict(test_claims) + +precision, recall, f1, _ = precision_recall_fscore_support(y_true, y_pred) +assert precision > 0.8 # 80% precision +assert recall > 0.7 # 70% recall +``` + +## Dependencies +- ✅ Tenant Management (data isolation) +- ✅ Stripe Billing (metering) +- ⏳ PostgreSQL deployment +- ⏳ Grafana setup +- ⏳ Python ML service + +## Documentation +- [ ] Create [docs/ANALYTICS.md](../../docs/ANALYTICS.md) +- [ ] Update [ARCHITECTURE.md](../../ARCHITECTURE.md) with analytics flow +- [ ] Add Swagger docs for Analytics Service APIs + +## Success Criteria +- ✅ Dashboards load <3s with 1-year data +- ✅ Fraud detection: >80% precision, >70% recall +- ✅ Reports generate in <10s +- ✅ Zero PHI leaks in aggregated reports +- ✅ Stripe metering tracks 100% of premium exports + +## Timeline +- **Weeks 1-2:** Analytics Service + APIs +- **Weeks 2-3:** Grafana dashboards +- **Weeks 3-4:** ML fraud detection +- **Weeks 4-5:** Report generation + Stripe metering +- **Week 5:** Compliance audit + testing + +**Total:** 5 weeks (2 FTE) + +## References +- [Grafana Dashboards](https://grafana.com/docs/grafana/latest/dashboards/) +- [scikit-learn Anomaly Detection](https://scikit-learn.org/stable/modules/outlier_detection.html) +- [QuestPDF Documentation](https://www.questpdf.com/) diff --git a/.github/ISSUE_TEMPLATE/v4-availity-integration.md b/.github/ISSUE_TEMPLATE/v4-availity-integration.md new file mode 100644 index 00000000..16d3a5cb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/v4-availity-integration.md @@ -0,0 +1,670 @@ +--- +name: 'Availity Clearinghouse Integration' +about: Integrate with Availity for real-time eligibility and claims processing +title: '[v4.0] Availity Clearinghouse Integration - Beta MVP' +labels: 'integration, clearinghouse, priority:critical' +assignees: '' +--- + +## 🎯 Objective + +Integrate Cloud Health Office with Availity clearinghouse for production-ready eligibility verification (270/271) and claims submission (837). This is the **minimum viable integration** for Beta launch with paying customers. + +**Priority:** 🔴 **CRITICAL** (Beta blocker - can't process real transactions without this) +**Effort:** 3-4 weeks (2 developers) +**Depends On:** Azure Key Vault integration (#TBD) +**Blocks:** Beta launch, revenue generation + +--- + +## 📋 Success Criteria + +- [ ] Availity sandbox account created and credentials stored in Key Vault +- [ ] SFTP connection to Availity established with retry logic +- [ ] 270 Eligibility requests sent to Availity, 271 responses parsed +- [ ] 837 Professional claims submitted to Availity +- [ ] Transaction metering enabled for Stripe billing +- [ ] <500ms p95 latency for eligibility checks (including clearinghouse round-trip) +- [ ] 100 test transactions processed successfully (50 eligibility, 50 claims) +- [ ] Error handling for all Availity error codes (AAA rejection codes) +- [ ] Monitoring and alerting for failed transactions + +--- + +## 🏗️ Architecture Overview + +``` +┌─────────────────┐ +│ Portal/API │ +│ (Member/ │ +│ Provider) │ +└────────┬────────┘ + │ HTTP POST /api/v1/eligibility + ▼ +┌─────────────────────────┐ +│ eligibility-service │ ← New microservice or extend existing +│ (validates request) │ +└────────┬────────────────┘ + │ Publish to Kafka + ▼ +┌─────────────────────────┐ +│ Argo Workflow │ +│ (270-eligibility.yaml) │ +└────────┬────────────────┘ + │ Step 1: Build X12 270 + │ Step 2: SFTP upload to Availity + │ Step 3: Poll for 271 response + │ Step 4: Parse and store in Cosmos DB + ▼ +┌─────────────────────────┐ +│ Availity SFTP │ +│ sftp.availity.com:22 │ +│ /inbound/270/ │ +│ /outbound/271/ │ +└─────────────────────────┘ +``` + +**Key Design Decisions:** +- Use existing Argo Workflow pattern (proven for 275/278) +- SFTP for eligibility (Availity doesn't offer real-time REST API for 270/271 in all regions) +- Async processing with Kafka for audit trail +- Cosmos DB for response caching (avoid duplicate clearinghouse calls) + +--- + +## 🔧 Implementation Steps + +### Phase 1: Availity Account Setup (Days 1-3) + +**1.1 Create Availity Sandbox Account** + +**Action Items:** +- [ ] Register at https://www.availity.com/essentials-providers +- [ ] Select "Payer Solutions" (not "Provider Solutions") +- [ ] Request sandbox access via https://availity.com/support +- [ ] Obtain credentials: + - Submitter ID (e.g., `TEST123456`) + - SFTP username (e.g., `cho_sandbox`) + - SFTP password + - Submitter NPI (for testing) + +**Expected Timeline:** 3-5 business days for approval + +**1.2 Store Credentials in Azure Key Vault** + +```bash +# Availity sandbox credentials +az keyvault secret set \ + --vault-name "kv-cho-prod-eastus" \ + --name "Availity--Sandbox--SubmitterId" \ + --value "TEST123456" + +az keyvault secret set \ + --vault-name "kv-cho-prod-eastus" \ + --name "Availity--Sandbox--SftpUsername" \ + --value "cho_sandbox" + +az keyvault secret set \ + --vault-name "kv-cho-prod-eastus" \ + --name "Availity--Sandbox--SftpPassword" \ + --value "${AVAILITY_SFTP_PASSWORD}" + +az keyvault secret set \ + --vault-name "kv-cho-prod-eastus" \ + --name "Availity--Sandbox--SftpHost" \ + --value "sftp-sandbox.availity.com" + +# Submitter NPI for X12 headers +az keyvault secret set \ + --vault-name "kv-cho-prod-eastus" \ + --name "Availity--Sandbox--SubmitterNpi" \ + --value "1234567890" +``` + +**1.3 Test SFTP Connection** + +```bash +# Test connectivity +sftp cho_sandbox@sftp-sandbox.availity.com + +# Expected directory structure: +# /inbound/270/ <- Upload eligibility requests here +# /outbound/271/ <- Download responses here +# /inbound/837/ <- Upload claims here +# /outbound/999/ <- Download acknowledgements here +``` + +--- + +### Phase 2: X12 270 Eligibility Request Builder (Days 4-7) + +**2.1 Create X12 270 Generator** + +**New File:** `containers/x12-270-generator/generate-270.py` + +```python +#!/usr/bin/env python3 +""" +Generate X12 270 Eligibility Inquiry from JSON API request. +Follows 5010 X12 270 implementation guide. +""" +import json +import sys +from datetime import datetime + +def generate_270(request_data): + """Build X12 270 from API request.""" + + # ISA - Interchange Control Header + isa = f"ISA*00* *00* *30*{request_data['submitter_id']:<15}*30*{request_data['receiver_id']:<15}*{datetime.now():%y%m%d}*{datetime.now():%H%M}*^*00501*{request_data['control_number']:09d}*0*P*:~" + + # GS - Functional Group Header + gs = f"GS*HS*{request_data['submitter_id']}*{request_data['receiver_id']}*{datetime.now():%Y%m%d}*{datetime.now():%H%M}*{request_data['group_control_number']}*X*005010X279A1~" + + # ST - Transaction Set Header + st = f"ST*270*{request_data['transaction_control_number']:04d}*005010X279A1~" + + # BHT - Beginning of Hierarchical Transaction + bht = f"BHT*0022*13*{request_data['reference_id']}*{datetime.now():%Y%m%d}*{datetime.now():%H%M%S}~" + + # HL - Information Source (Payer) + hl_payer = "HL*1**20*1~" + nm1_payer = f"NM1*PR*2*{request_data['payer_name']}*****PI*{request_data['payer_id']}~" + + # HL - Information Receiver (Provider) + hl_provider = "HL*2*1*21*1~" + nm1_provider = f"NM1*1P*2*{request_data['provider_name']}*****XX*{request_data['provider_npi']}~" + + # HL - Subscriber + hl_subscriber = "HL*3*2*22*0~" + trn = f"TRN*1*{request_data['trace_number']}*{request_data['submitter_id']}~" + nm1_subscriber = f"NM1*IL*1*{request_data['subscriber_last_name']}*{request_data['subscriber_first_name']}****MI*{request_data['member_id']}~" + dmg = f"DMG*D8*{request_data['date_of_birth']}*{request_data.get('gender', 'U')}~" + dtp = f"DTP*291*D8*{datetime.now():%Y%m%d}~" + + # EQ - Eligibility/Benefit Inquiry (30 = All available) + eq = "EQ*30~" + + # SE - Transaction Set Trailer + segment_count = 13 # Count all segments between ST and SE + se = f"SE*{segment_count}*{request_data['transaction_control_number']:04d}~" + + # GE - Functional Group Trailer + ge = f"GE*1*{request_data['group_control_number']}~" + + # IEA - Interchange Control Trailer + iea = f"IEA*1*{request_data['control_number']:09d}~" + + # Combine all segments + x12_270 = "\n".join([ + isa, gs, st, bht, + hl_payer, nm1_payer, + hl_provider, nm1_provider, + hl_subscriber, trn, nm1_subscriber, dmg, dtp, eq, + se, ge, iea + ]) + + return x12_270 + +if __name__ == "__main__": + # Read JSON from stdin + request_data = json.load(sys.stdin) + + # Generate X12 270 + x12_output = generate_270(request_data) + + # Write to stdout + print(x12_output) +``` + +**2.2 Containerize X12 270 Generator** + +**New File:** `containers/x12-270-generator/Dockerfile` + +```dockerfile +FROM python:3.11-slim + +WORKDIR /app + +COPY generate-270.py /app/ +RUN chmod +x /app/generate-270.py + +# No dependencies needed for basic X12 generation +ENTRYPOINT ["python3", "/app/generate-270.py"] +``` + +**Build and Push:** +```bash +docker build -t ghcr.io/aurelianware/cloudhealthoffice-x12-270-generator:latest containers/x12-270-generator/ +docker push ghcr.io/aurelianware/cloudhealthoffice-x12-270-generator:latest +``` + +--- + +### Phase 3: Argo Workflow for Availity (Days 8-12) + +**3.1 Create Argo Workflow for 270 Submission** + +**New File:** `argo-workflows/270-eligibility-availity.yaml` + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: WorkflowTemplate +metadata: + name: x12-270-eligibility-availity + namespace: cho-svcs +spec: + entrypoint: process-270-eligibility + + templates: + - name: process-270-eligibility + inputs: + parameters: + - name: tenant-id + - name: request-json # JSON payload from API + + dag: + tasks: + # Step 1: Generate X12 270 from JSON request + - name: generate-x12-270 + template: x12-270-generator + arguments: + parameters: + - name: request-json + value: "{{inputs.parameters.request-json}}" + + # Step 2: Upload to Availity SFTP + - name: upload-to-availity + template: sftp-upload + dependencies: [generate-x12-270] + arguments: + parameters: + - name: x12-content + value: "{{tasks.generate-x12-270.outputs.result}}" + - name: remote-path + value: "/inbound/270/{{inputs.parameters.tenant-id}}_270_{{workflow.creationTimestamp}}.x12" + + # Step 3: Poll for 271 response (with retry) + - name: poll-for-response + template: sftp-poll + dependencies: [upload-to-availity] + arguments: + parameters: + - name: remote-path + value: "/outbound/271/" + - name: filename-pattern + value: "{{inputs.parameters.tenant-id}}_271_*.x12" + + # Step 4: Parse 271 response + - name: parse-271-response + template: x12-271-parser + dependencies: [poll-for-response] + arguments: + parameters: + - name: x12-content + value: "{{tasks.poll-for-response.outputs.result}}" + + # Step 5: Store in Cosmos DB + - name: store-response + template: cosmos-db-upsert + dependencies: [parse-271-response] + arguments: + parameters: + - name: tenant-id + value: "{{inputs.parameters.tenant-id}}" + - name: response-json + value: "{{tasks.parse-271-response.outputs.result}}" + + # Template: X12 270 Generator + - name: x12-270-generator + inputs: + parameters: + - name: request-json + container: + image: ghcr.io/aurelianware/cloudhealthoffice-x12-270-generator:latest + command: ["python3", "/app/generate-270.py"] + stdin: "{{inputs.parameters.request-json}}" + + # Template: SFTP Upload + - name: sftp-upload + inputs: + parameters: + - name: x12-content + - name: remote-path + script: + image: alpine:latest + command: [sh] + source: | + apk add --no-cache openssh-client + + # Get credentials from Key Vault (via env vars injected by pod identity) + SFTP_HOST="${AVAILITY_SFTP_HOST}" + SFTP_USER="${AVAILITY_SFTP_USERNAME}" + SFTP_PASS="${AVAILITY_SFTP_PASSWORD}" + + # Upload file + echo "{{inputs.parameters.x12-content}}" > /tmp/270.x12 + sshpass -p "$SFTP_PASS" sftp -o StrictHostKeyChecking=no "$SFTP_USER@$SFTP_HOST" < /tmp/file_list.txt + ls {{inputs.parameters.remote-path}}{{inputs.parameters.filename-pattern}} + bye + EOF + + # Check if file exists + if grep -q "271" /tmp/file_list.txt; then + # Download first matching file + FILENAME=$(grep "271" /tmp/file_list.txt | head -1) + sshpass -p "$SFTP_PASS" sftp -o StrictHostKeyChecking=no "$SFTP_USER@$SFTP_HOST" < /tmp/response.json + + az cosmosdb sql container item create \ + --account-name "cosmos-cho-prod" \ + --database-name "CloudHealthOffice" \ + --container-name "EligibilityResponses" \ + --partition-key-value "{{inputs.parameters.tenant-id}}" \ + --body @/tmp/response.json +``` + +--- + +### Phase 4: API Endpoint & Testing (Days 13-18) + +**4.1 Create Eligibility API Endpoint** + +**Update:** `services/eligibility-service/Controllers/EligibilityController.cs` + +```csharp +[ApiController] +[Route("api/v1/eligibility")] +public class EligibilityController : ControllerBase +{ + private readonly IArgoWorkflowService _argoWorkflowService; + private readonly ITenantContextService _tenantContextService; + + [HttpPost("check")] + [ProducesResponseType(typeof(EligibilityResponse), 200)] + [ProducesResponseType(typeof(ErrorResponse), 400)] + public async Task CheckEligibility([FromBody] EligibilityRequest request) + { + var tenantId = await _tenantContextService.GetTenantIdAsync(); + if (string.IsNullOrEmpty(tenantId)) + { + return BadRequest(new ErrorResponse { Message = "Missing tenant context" }); + } + + // Build JSON payload for Argo Workflow + var workflowInput = new + { + tenant_id = tenantId, + request_json = JsonSerializer.Serialize(new + { + submitter_id = "TEST123456", // From Key Vault + receiver_id = "AVAILITY", + payer_id = request.PayerId, + payer_name = request.PayerName, + provider_npi = request.ProviderNpi, + provider_name = request.ProviderName, + subscriber_last_name = request.SubscriberLastName, + subscriber_first_name = request.SubscriberFirstName, + member_id = request.MemberId, + date_of_birth = request.DateOfBirth.ToString("yyyyMMdd"), + gender = request.Gender, + control_number = GenerateControlNumber(), + group_control_number = GenerateGroupControlNumber(), + transaction_control_number = GenerateTransactionControlNumber(), + reference_id = Guid.NewGuid().ToString(), + trace_number = $"CHO{DateTime.UtcNow:yyyyMMddHHmmss}" + }) + }; + + // Submit Argo Workflow + var workflowName = await _argoWorkflowService.SubmitWorkflowAsync( + "x12-270-eligibility-availity", + workflowInput + ); + + // Return immediate response (async processing) + return Accepted(new + { + workflowName = workflowName, + status = "processing", + statusUrl = $"/api/v1/eligibility/status/{workflowName}" + }); + } + + [HttpGet("status/{workflowName}")] + public async Task GetStatus(string workflowName) + { + var status = await _argoWorkflowService.GetWorkflowStatusAsync(workflowName); + + if (status.Phase == "Succeeded") + { + // Fetch parsed 271 response from Cosmos DB + var response = await _cosmosDbService.GetEligibilityResponseAsync(workflowName); + return Ok(response); + } + else if (status.Phase == "Failed") + { + return StatusCode(500, new ErrorResponse { Message = "Eligibility check failed", Details = status.Message }); + } + else + { + return Ok(new { status = status.Phase, message = "Processing..." }); + } + } +} +``` + +**4.2 Integration Testing** + +```bash +# Test 270 generation +curl -X POST https://api-staging.cloudhealthoffice.com/api/v1/eligibility/check \ + -H "X-Tenant-ID: tenant-123" \ + -H "Content-Type: application/json" \ + -d '{ + "payerId": "BCBSFL", + "payerName": "Blue Cross Blue Shield of Florida", + "providerNpi": "1234567890", + "providerName": "Test Medical Group", + "subscriberLastName": "Doe", + "subscriberFirstName": "John", + "memberId": "ABC123456789", + "dateOfBirth": "1980-05-15", + "gender": "M" + }' + +# Expected response: +# { +# "workflowName": "x12-270-eligibility-availity-abc123", +# "status": "processing", +# "statusUrl": "/api/v1/eligibility/status/x12-270-eligibility-availity-abc123" +# } + +# Poll for completion (after ~30 seconds) +curl https://api-staging.cloudhealthoffice.com/api/v1/eligibility/status/x12-270-eligibility-availity-abc123 +``` + +**4.3 Load Testing (100 Transactions)** + +```bash +# Use k6 for load testing +k6 run scripts/load-test-270-eligibility.js + +# Expected: +# - 100 requests submitted +# - <500ms p95 latency for API response (not including clearinghouse round-trip) +# - 0 errors +# - All workflows complete within 2 minutes +``` + +--- + +### Phase 5: Production Deployment & Monitoring (Days 19-21) + +**5.1 Configure Stripe Metering** + +```csharp +// In Argo Workflow completion handler +public async Task OnWorkflowCompleted(string workflowName, string tenantId) +{ + // Record transaction usage for Stripe billing + await _stripeService.RecordUsageAsync( + tenantId, + "transaction-meter", + quantity: 1, // 1 eligibility check + timestamp: DateTime.UtcNow + ); +} +``` + +**5.2 Monitoring & Alerting** + +**Application Insights Queries:** +```kusto +// Failed Availity transactions (last 24 hours) +traces +| where timestamp > ago(24h) +| where message contains "Availity" and severityLevel >= 3 +| summarize count() by bin(timestamp, 1h), message + +// Eligibility check latency (p95) +dependencies +| where timestamp > ago(1h) +| where name contains "270" +| summarize percentile(duration, 95) by bin(timestamp, 5m) +``` + +**Alerts:** +- Availity SFTP connection failure (> 5 failures in 10 minutes) +- 271 polling timeout (> 10% of workflows timeout) +- Eligibility check p95 latency > 2 seconds (including clearinghouse) + +**5.3 Production Deployment** + +```bash +# Deploy to production namespace +kubectl apply -f argo-workflows/270-eligibility-availity.yaml -n cho-svcs + +# Verify workflow template exists +argo template list -n cho-svcs | grep 270-eligibility + +# Submit test workflow manually +argo submit -n cho-svcs \ + --from workflowtemplate/x12-270-eligibility-availity \ + -p tenant-id=tenant-123 \ + -p request-json='{"subscriber_last_name":"Test","subscriber_first_name":"Patient",...}' +``` + +--- + +## 📚 Availity API Documentation + +- **Developer Portal:** https://developer.availity.com/ +- **270/271 Implementation Guide:** https://www.availity.com/documents/270-271-companion-guide.pdf +- **SFTP Connection Guide:** https://availity.com/support/sftp-setup +- **Error Codes:** https://availity.com/resources/error-codes + +--- + +## 🚨 Error Handling + +**Availity-Specific Error Codes (AAA segment in 271):** +- `AAA*N*42` - Subscriber not found +- `AAA*N*56` - Coverage not in effect on service date +- `AAA*N*58` - Invalid member ID format +- `AAA*N*71` - Patient birth date mismatch +- `AAA*N*T4` - Payer ID not recognized + +**Retry Strategy:** +- SFTP connection errors: Exponential backoff (5s, 10s, 20s, 40s) +- 271 polling timeout: Fail after 5 minutes (Availity SLA is 30 seconds) +- Invalid request (4xx): Don't retry, return error to caller +- Clearinghouse outage (5xx): Retry up to 3 times with 1-minute intervals + +--- + +## ✅ Definition of Done + +- [ ] Availity sandbox account provisioned +- [ ] SFTP connection tested and credentials in Key Vault +- [ ] X12 270 generator containerized and tested +- [ ] Argo Workflow for 270 → 271 deployed +- [ ] API endpoint `/api/v1/eligibility/check` functional +- [ ] 100 test transactions processed successfully (95%+ success rate) +- [ ] Transaction metering sending data to Stripe +- [ ] Monitoring dashboards created in Application Insights +- [ ] Alerts configured for failures +- [ ] Documentation updated (API docs, runbooks) + +--- + +## 📅 Timeline + +| Days | Task | Owner | Status | +|------|------|-------|--------| +| 1-3 | Availity account setup | DevOps | ⬜ Not Started | +| 4-7 | Build X12 270 generator | Backend Dev | ⬜ Not Started | +| 8-12 | Create Argo Workflow | Backend Dev | ⬜ Not Started | +| 13-18 | API endpoint + testing | Backend Dev | ⬜ Not Started | +| 19-21 | Production deployment + monitoring | DevOps | ⬜ Not Started | + +**Target Completion:** 3 weeks from start +**Beta Launch:** Week 4 (with Availity integration live) diff --git a/.github/ISSUE_TEMPLATE/v4-azure-key-vault.md b/.github/ISSUE_TEMPLATE/v4-azure-key-vault.md new file mode 100644 index 00000000..e38386db --- /dev/null +++ b/.github/ISSUE_TEMPLATE/v4-azure-key-vault.md @@ -0,0 +1,369 @@ +--- +name: 'Azure Key Vault Integration' +about: Migrate all secrets to Azure Key Vault for production-grade security +title: '[v4.0] Azure Key Vault Integration - Production Security Hardening' +labels: 'security, infrastructure, priority:critical' +assignees: '' +--- + +## 🎯 Objective + +Migrate all application secrets from environment variables and configuration files to Azure Key Vault with managed identity authentication. This is a **BLOCKER** for Beta launch and clearinghouse integration. + +**Priority:** 🔴 **CRITICAL** +**Effort:** 1-2 weeks (1 developer) +**Depends On:** Azure subscription with Key Vault quota +**Blocks:** Clearinghouse integration, customer onboarding + +--- + +## 📋 Success Criteria + +- [ ] All production secrets stored in Azure Key Vault (Premium SKU with HSM) +- [ ] All 17 microservices read secrets from Key Vault via managed identity +- [ ] Portal reads Stripe API keys from Key Vault +- [ ] SFTP credentials migrated from local config to Key Vault +- [ ] Cosmos DB connection strings use Key Vault references +- [ ] Zero secrets in code, config files, or environment variables +- [ ] Secret rotation automated (90-day policy) +- [ ] Audit logging enabled for all secret access +- [ ] Smoke tests pass in staging environment + +--- + +## 🔧 Implementation Steps + +### Phase 1: Azure Key Vault Setup (Day 1) + +**1.1 Create Key Vault Resource** +```bash +# Create Key Vault (Premium SKU for HSM-backed keys) +az keyvault create \ + --name "kv-cho-prod-${LOCATION}" \ + --resource-group "rg-cloudhealthoffice-prod" \ + --location "eastus" \ + --sku "Premium" \ + --enable-rbac-authorization true \ + --enable-purge-protection true \ + --retention-days 90 + +# Configure network access (allow Azure services + deny public) +az keyvault network-rule add \ + --name "kv-cho-prod-eastus" \ + --resource-group "rg-cloudhealthoffice-prod" \ + --vnet-name "vnet-cho-prod" \ + --subnet "snet-aks" + +az keyvault update \ + --name "kv-cho-prod-eastus" \ + --resource-group "rg-cloudhealthoffice-prod" \ + --default-action Deny +``` + +**1.2 Enable Audit Logging** +```bash +# Send Key Vault logs to Log Analytics +az monitor diagnostic-settings create \ + --name "KeyVaultAudit" \ + --resource $(az keyvault show --name "kv-cho-prod-eastus" -g "rg-cloudhealthoffice-prod" --query id -o tsv) \ + --workspace $(az monitor log-analytics workspace show --name "law-cho-prod" -g "rg-cloudhealthoffice-prod" --query id -o tsv) \ + --logs '[{"category": "AuditEvent", "enabled": true, "retentionPolicy": {"enabled": true, "days": 365}}]' \ + --metrics '[{"category": "AllMetrics", "enabled": true}]' +``` + +**1.3 Configure Managed Identity for AKS** +```bash +# Enable managed identity on AKS cluster +az aks update \ + --resource-group "rg-cloudhealthoffice-prod" \ + --name "cho-aks-prod" \ + --enable-managed-identity + +# Get AKS managed identity +AKS_IDENTITY=$(az aks show -g "rg-cloudhealthoffice-prod" -n "cho-aks-prod" --query identityProfile.kubeletidentity.clientId -o tsv) + +# Grant Key Vault Secrets User role +az role assignment create \ + --role "Key Vault Secrets User" \ + --assignee $AKS_IDENTITY \ + --scope $(az keyvault show --name "kv-cho-prod-eastus" -g "rg-cloudhealthoffice-prod" --query id -o tsv) +``` + +--- + +### Phase 2: Migrate Secrets (Days 2-3) + +**2.1 Audit Current Secrets** +Create inventory of all secrets currently in: +- GitHub Secrets (production) +- appsettings.json files +- Kubernetes ConfigMaps/Secrets +- Environment variables + +**2.2 Upload Secrets to Key Vault** +```bash +# Cosmos DB secrets +az keyvault secret set --vault-name "kv-cho-prod-eastus" --name "CosmosDb--ConnectionString" --value "${COSMOS_CONNECTION_STRING}" + +# Stripe secrets +az keyvault secret set --vault-name "kv-cho-prod-eastus" --name "Stripe--SecretKey" --value "${STRIPE_SECRET_KEY}" +az keyvault secret set --vault-name "kv-cho-prod-eastus" --name "Stripe--PublishableKey" --value "${STRIPE_PUBLISHABLE_KEY}" +az keyvault secret set --vault-name "kv-cho-prod-eastus" --name "Stripe--WebhookSecret" --value "${STRIPE_WEBHOOK_SECRET}" + +# Azure AD secrets (portal) +az keyvault secret set --vault-name "kv-cho-prod-eastus" --name "AzureAd--ClientSecret" --value "${AZURE_AD_CLIENT_SECRET}" + +# SFTP credentials (per tenant) +az keyvault secret set --vault-name "kv-cho-prod-eastus" --name "SFTP--clouddentaloffice--Password" --value "${SFTP_PASSWORD}" + +# Application Insights +az keyvault secret set --vault-name "kv-cho-prod-eastus" --name "ApplicationInsights--ConnectionString" --value "${APPINSIGHTS_CONNECTION_STRING}" + +# Service Bus (if still using) +az keyvault secret set --vault-name "kv-cho-prod-eastus" --name "ServiceBus--ConnectionString" --value "${SERVICEBUS_CONNECTION_STRING}" +``` + +**2.3 Clearinghouse Credentials (for future integration)** +```bash +# Availity (sandbox then production) +az keyvault secret set --vault-name "kv-cho-prod-eastus" --name "Availity--Username" --value "${AVAILITY_USERNAME}" +az keyvault secret set --vault-name "kv-cho-prod-eastus" --name "Availity--Password" --value "${AVAILITY_PASSWORD}" +az keyvault secret set --vault-name "kv-cho-prod-eastus" --name "Availity--SftpHost" --value "sftp.availity.com" + +# Change Healthcare +az keyvault secret set --vault-name "kv-cho-prod-eastus" --name "ChangeHealthcare--ApiKey" --value "${CHANGE_API_KEY}" +az keyvault secret set --vault-name "kv-cho-prod-eastus" --name "ChangeHealthcare--ClientId" --value "${CHANGE_CLIENT_ID}" +az keyvault secret set --vault-name "kv-cho-prod-eastus" --name "ChangeHealthcare--ClientSecret" --value "${CHANGE_CLIENT_SECRET}" +``` + +--- + +### Phase 3: Update Applications (Days 4-7) + +**3.1 Install Azure.Extensions.AspNetCore.Configuration.Secrets** + +Add to all service `.csproj` files: +```xml + + +``` + +**3.2 Update Program.cs (Microservices)** + +Add to `Program.cs` in all 17 microservices: +```csharp +using Azure.Identity; + +var builder = WebApplication.CreateBuilder(args); + +// Add Key Vault configuration +if (builder.Environment.IsProduction()) +{ + var keyVaultEndpoint = new Uri($"https://kv-cho-prod-eastus.vault.azure.net/"); + builder.Configuration.AddAzureKeyVault( + keyVaultEndpoint, + new DefaultAzureCredential()); // Uses managed identity in AKS +} + +// Rest of configuration... +``` + +**3.3 Update Portal Program.cs** + +```csharp +// In portal/CloudHealthOffice.Portal/Program.cs +if (builder.Environment.IsProduction()) +{ + var keyVaultEndpoint = new Uri(builder.Configuration["KeyVault:VaultUri"] + ?? "https://kv-cho-prod-eastus.vault.azure.net/"); + + builder.Configuration.AddAzureKeyVault( + keyVaultEndpoint, + new DefaultAzureCredential()); +} +``` + +**3.4 Remove Hardcoded Secrets** + +Update all appsettings.json files to use Key Vault references: +```json +{ + "CosmosDb": { + "ConnectionString": "" // Now loaded from Key Vault + }, + "Stripe": { + "SecretKey": "", + "PublishableKey": "", + "WebhookSecret": "" + }, + "AzureAd": { + "ClientSecret": "" // Now loaded from Key Vault + } +} +``` + +--- + +### Phase 4: Update Kubernetes Deployments (Days 8-10) + +**4.1 Remove Kubernetes Secrets** + +Delete or comment out existing secret manifests: +```bash +# Backup existing secrets +kubectl get secrets -n cho-svcs -o yaml > secrets-backup-$(date +%Y%m%d).yaml + +# Verify apps will use Key Vault instead +# (Don't delete secrets until apps are updated and tested) +``` + +**4.2 Update Deployment Manifests** + +Add Key Vault URI as environment variable (not secret): +```yaml +# k8s/base/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: member-service +spec: + template: + spec: + containers: + - name: member-service + image: ghcr.io/aurelianware/cloudhealthoffice-member-service:latest + env: + - name: KeyVault__VaultUri + value: "https://kv-cho-prod-eastus.vault.azure.net/" + - name: ASPNETCORE_ENVIRONMENT + value: "Production" + # Secrets now loaded from Key Vault via managed identity +``` + +**4.3 Enable Workload Identity (Optional - More Secure)** + +For pod-level identity instead of node-level: +```bash +# Enable workload identity on AKS +az aks update \ + --resource-group "rg-cloudhealthoffice-prod" \ + --name "cho-aks-prod" \ + --enable-workload-identity + +# Create service account with federated identity +# (Advanced - can defer to post-Beta) +``` + +--- + +### Phase 5: Testing & Validation (Days 11-14) + +**5.1 Staging Environment Testing** +```bash +# Deploy to staging namespace +kubectl apply -k k8s/overlays/staging + +# Verify secret access +kubectl logs -n cho-svcs-staging deployment/member-service | grep "KeyVault" + +# Test API endpoints +curl https://staging-api.cloudhealthoffice.com/api/v1/members/health +``` + +**5.2 Smoke Tests** +- [ ] Portal login works (Azure AD client secret from Key Vault) +- [ ] Stripe checkout works (API keys from Key Vault) +- [ ] Cosmos DB queries work (connection string from Key Vault) +- [ ] Application Insights telemetry appears (instrumentation key from Key Vault) +- [ ] SFTP connection succeeds (credentials from Key Vault) + +**5.3 Security Validation** +- [ ] No secrets in application logs +- [ ] Key Vault audit logs show access attempts +- [ ] Managed identity authentication working (no access key in config) +- [ ] Secret rotation policy configured (90-day expiry) + +**5.4 Production Deployment** +```bash +# Blue/Green deployment to minimize downtime +kubectl apply -k k8s/overlays/production + +# Monitor for errors +kubectl rollout status deployment/member-service -n cho-svcs +kubectl logs -f deployment/member-service -n cho-svcs --tail=100 +``` + +--- + +## 🚨 Rollback Plan + +If Key Vault integration breaks production: + +**Step 1: Immediate Rollback** +```bash +# Restore previous deployment +kubectl rollout undo deployment/member-service -n cho-svcs + +# Verify rollback +kubectl rollout status deployment/member-service -n cho-svcs +``` + +**Step 2: Restore Secrets** +```bash +# Re-apply backed-up Kubernetes secrets +kubectl apply -f secrets-backup-YYYYMMDD.yaml +``` + +**Step 3: Root Cause Analysis** +- Check managed identity permissions +- Verify Key Vault network rules allow AKS subnet +- Review audit logs for access denials + +--- + +## 📚 Reference Documentation + +- [Azure Key Vault Best Practices](https://learn.microsoft.com/en-us/azure/key-vault/general/best-practices) +- [ASP.NET Core Key Vault Configuration](https://learn.microsoft.com/en-us/aspnet/core/security/key-vault-configuration) +- [AKS Managed Identity](https://learn.microsoft.com/en-us/azure/aks/use-managed-identity) +- [Key Vault RBAC Permissions](https://learn.microsoft.com/en-us/azure/key-vault/general/rbac-guide) + +--- + +## 🔐 Security Considerations + +- **Principle of Least Privilege:** Each service should only access secrets it needs (future: split Key Vaults per service) +- **Secret Rotation:** Automate with Azure Automation or Logic Apps (90-day rotation policy) +- **Audit All Access:** Monitor for unusual access patterns (spike in reads, access from unexpected IPs) +- **Break Glass Procedure:** Document manual Key Vault access for emergencies +- **Backup Secrets:** Export secrets to secure offline storage (encrypted USB drive in safe) + +--- + +## ✅ Definition of Done + +- [ ] All production secrets migrated to Azure Key Vault +- [ ] All 17 microservices updated to use Key Vault +- [ ] Portal updated to use Key Vault +- [ ] Staging environment tested successfully +- [ ] Production deployment completed with zero downtime +- [ ] Rollback procedure documented and tested +- [ ] Old secrets rotated/invalidated +- [ ] GitHub Secrets cleaned up (only deployment credentials remain) +- [ ] Documentation updated in SECURITY.md +- [ ] Team trained on Key Vault access procedures + +--- + +## 📅 Timeline + +| Day | Task | Owner | Status | +|-----|------|-------|--------| +| 1 | Key Vault setup + managed identity | DevOps | ⬜ Not Started | +| 2-3 | Migrate secrets to Key Vault | DevOps | ⬜ Not Started | +| 4-7 | Update all applications | Backend Dev | ⬜ Not Started | +| 8-10 | Update Kubernetes manifests | DevOps | ⬜ Not Started | +| 11-12 | Staging testing | QA | ⬜ Not Started | +| 13-14 | Production deployment | DevOps | ⬜ Not Started | + +**Target Completion:** 2 weeks from start diff --git a/.github/ISSUE_TEMPLATE/v4-clearinghouse-integration.md b/.github/ISSUE_TEMPLATE/v4-clearinghouse-integration.md new file mode 100644 index 00000000..79819aa5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/v4-clearinghouse-integration.md @@ -0,0 +1,387 @@ +--- +name: "[v4.0] Real Clearinghouse Integration" +about: Integrate Availity, Change Healthcare, and Optum for production EDI exchanges +title: "[v4.0] Integrate Real Clearinghouses (Availity, Change Healthcare, Optum)" +labels: enhancement, integration, v4.0, priority-high +assignees: aurelianware +--- + +## Overview +Enable production EDI exchanges with major clearinghouses to process real X12 transactions (837 claims, 270 eligibility, 278 prior auth). Build on existing SFTP automation and X12 parsing, integrating tenant management for payer-specific configs and Stripe for transaction-based billing. + +## Objectives +- ✅ Integrate with 3 major clearinghouses (Availity, Change Healthcare, Optum) +- ✅ Process real X12 transactions (837/270/278/835/837) +- ✅ Achieve <500ms adjudication SLA +- ✅ Enable usage-based billing (per-transaction metering) +- ✅ Maintain HIPAA compliance (PHI encryption, audit trails) + +## Clearinghouse Partners + +### 1. Availity +- **Market Share:** 35% (largest US clearinghouse) +- **API:** SOAP + REST (eligibility), SFTP (claims) +- **Supported Transactions:** 270/271, 276/277, 278/279, 837, 835 +- **Test Environment:** https://apps.availity.com/availity/web/public.elegant.login +- **Integration:** Real-time API for eligibility, batch SFTP for claims + +### 2. Change Healthcare (Optum) +- **Market Share:** 30% +- **API:** REST API (Intelligent Healthcare Network) +- **Supported Transactions:** All standard X12 (270-835) +- **Test Environment:** https://developers.changehealthcare.com +- **Integration:** RESTful JSON (auto-convert to/from X12) + +### 3. Optum (UnitedHealth Group) +- **Market Share:** 25% +- **API:** Optum One Platform (REST) +- **Supported Transactions:** All X12 + proprietary formats +- **Test Environment:** Contact for sandbox access +- **Integration:** SFTP + REST hybrid + +## Implementation Steps + +### Phase 1: Clearinghouse Adapter Service (Week 1-2) + +**Goal:** Create unified adapter layer for all clearinghouses + +**Tasks:** +- [ ] Create new microservice: `services/clearinghouse-adapter-service/` + ``` + services/clearinghouse-adapter-service/ + ├── Adapters/ + │ ├── IAvailityAdapter.cs + │ ├── AvailityAdapter.cs (SOAP client) + │ ├── IChangeHealthcareAdapter.cs + │ ├── ChangeHealthcareAdapter.cs (REST client) + │ ├── IOptumAdapter.cs + │ └── OptumAdapter.cs (hybrid) + ├── Models/ + │ ├── ClearinghouseRequest.cs + │ ├── ClearinghouseResponse.cs + │ └── TransactionLog.cs + ├── Controllers/ + │ └── ClearinghouseController.cs + └── Services/ + ├── IRoutingService.cs (route to correct clearinghouse) + └── RoutingService.cs + ``` + +- [ ] Implement adapter pattern for abstraction: + ```csharp + public interface IClearinghouseAdapter + { + Task CheckEligibilityAsync(string x12_270, string tenantId); + Task SubmitClaimAsync(string x12_837, string tenantId); + Task CheckClaimStatusAsync(string claimId); + Task GetRemittanceAsync(string remittanceId); + } + ``` + +- [ ] Add tenant-to-clearinghouse routing in Tenant model: + ```csharp + // In Tenant.cs + public ClearinghouseConfig Clearinghouse { get; set; } + + public class ClearinghouseConfig + { + public string Provider { get; set; } // "availity" | "changehealthcare" | "optum" + public string SenderId { get; set; } + public string ReceiverId { get; set; } + public string SubmitterName { get; set; } + public Dictionary Credentials { get; set; } // From Key Vault + } + ``` + +### Phase 2: Availity Integration (Week 2-3) + +**Tasks:** +- [ ] Register for Availity Developer Portal +- [ ] Obtain test credentials (Sender ID, Password) +- [ ] Implement SOAP client for Eligibility API: + ```csharp + public class AvailityAdapter : IClearinghouseAdapter + { + private readonly SoapClient _client; + + public async Task CheckEligibilityAsync(string x12_270, string tenantId) + { + var request = new AvailityEligibilityRequest + { + SenderId = _config.SenderId, + ReceiverId = "AVAILITY", + Transaction = x12_270 + }; + var response = await _client.SubmitAsync(request); + return ParseX12_271(response.Transaction); + } + } + ``` + +- [ ] Configure SFTP for batch claims (837): + - Hostname: `sftp.availity.com` + - Inbound: `/claims/inbound/{senderId}/` + - Outbound: `/claims/outbound/{senderId}/` + - Auth: Key pair (store in Key Vault) + +- [ ] Update Argo Workflow `x12-837-ingest.yaml`: + ```yaml + - name: submit-to-availity + container: + image: ghcr.io/aurelianware/cloudhealthoffice-sftp-publisher:latest + env: + - name: SFTP_HOST + value: "sftp.availity.com" + - name: SFTP_USERNAME + valueFrom: + secretKeyRef: + name: availity-creds + key: username + ``` + +### Phase 3: Change Healthcare Integration (Week 3-4) + +**Tasks:** +- [ ] Register at https://developers.changehealthcare.com +- [ ] Obtain OAuth2 client credentials +- [ ] Implement REST client: + ```csharp + public class ChangeHealthcareAdapter : IClearinghouseAdapter + { + private readonly HttpClient _http; + + public async Task CheckEligibilityAsync(string x12_270, string tenantId) + { + // Convert X12 to JSON + var json = X12ToJsonConverter.Convert(x12_270); + + var response = await _http.PostAsync( + "https://api.changehealthcare.com/eligibility/v1/check", + new StringContent(json, Encoding.UTF8, "application/json") + ); + + var result = await response.Content.ReadAsStringAsync(); + return JsonToX12Converter.ConvertEligibilityResponse(result); + } + } + ``` + +- [ ] Add X12 ↔ JSON converters using `X12.NET` library +- [ ] Configure OAuth2 token refresh (store in Key Vault) + +### Phase 4: Optum Integration (Week 4-5) + +**Tasks:** +- [ ] Contact Optum for sandbox credentials +- [ ] Implement hybrid adapter (REST for eligibility, SFTP for claims) +- [ ] Add Optum-specific validation (stricter NPI requirements) + +### Phase 5: Event-Driven Processing (Week 5-6) + +**Goal:** Enhance Argo Workflows for clearinghouse automation + +**Tasks:** +- [ ] Update Kafka topics for clearinghouse events: + ```yaml + # kafka/topics.yaml + - name: clearinghouse-outbound + partitions: 6 + replication: 3 + config: + retention.ms: 604800000 # 7 days + + - name: clearinghouse-inbound + partitions: 6 + replication: 3 + config: + retention.ms: 2592000000 # 30 days + ``` + +- [ ] Create Argo EventSource for SFTP polling: + ```yaml + # argo-events/clearinghouse-eventsource.yaml + apiVersion: argoproj.io/v1alpha1 + kind: EventSource + metadata: + name: clearinghouse-sftp-poller + spec: + generic: + sftp-availity: + url: sftp://sftp.availity.com/claims/outbound/BSCA123/ + interval: 60s # Poll every minute + ``` + +- [ ] Create Argo Sensor for processing inbound files: + ```yaml + # argo-events/clearinghouse-sensor.yaml + apiVersion: argoproj.io/v1alpha1 + kind: Sensor + metadata: + name: clearinghouse-response-processor + spec: + triggers: + - template: + name: process-835-remittance + argoWorkflow: + source: + resource: + apiVersion: argoproj.io/v1alpha1 + kind: Workflow + metadata: + generateName: process-835- + spec: + entrypoint: parse-and-update + templates: + - name: parse-and-update + steps: + - - name: parse-835 + template: x12-parser + - - name: update-claims + template: claims-updater + ``` + +- [ ] Add retry logic with exponential backoff: + ```csharp + var policy = Policy + .Handle() + .WaitAndRetryAsync(3, retryAttempt => + TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); + + await policy.ExecuteAsync(async () => + await _clearinghouseAdapter.SubmitClaimAsync(x12, tenantId)); + ``` + +### Phase 6: Stripe Billing Integration (Week 6) + +**Goal:** Charge per transaction with Stripe metering + +**Tasks:** +- [ ] Create Stripe meter for transaction volume: + ```bash + stripe meters create \ + --display-name "EDI Transactions" \ + --event-name "transaction.processed" + ``` + +- [ ] Update `TenantService.UpdateUsageAsync()`: + ```csharp + public async Task UpdateUsageAsync(string tenantId, string metricType, int count) + { + // Update Cosmos DB usage + await _repository.UpdateUsageAsync(tenantId, metricType, count); + + // Report to Stripe for billing + if (metricType == "ClaimsThisMonth") + { + await _stripeService.ReportUsageAsync(tenantId, "transaction.processed", count); + } + } + ``` + +- [ ] Add usage-based pricing tier in Stripe: + - **Starter:** $500/mo base + $0.50/transaction + - **Professional:** $2,500/mo base + $0.25/transaction + - **Enterprise:** Custom pricing + +- [ ] Emit Kafka event on transaction complete: + ```csharp + await _kafka.ProduceAsync("usage-events", new UsageEvent + { + TenantId = tenantId, + EventType = "claim_submitted", + Timestamp = DateTime.UtcNow, + Metadata = new { ClaimId = claimId, Clearinghouse = "availity" } + }); + ``` + +### Phase 7: Compliance & Monitoring (Week 7) + +**Tasks:** +- [ ] Add PHI masking in logs: + ```csharp + logger.LogInformation("Submitted claim {ClaimId} to {Clearinghouse} for tenant {TenantId}", + claimId, clearinghouse, tenantId); + // Never log full X12 content or SSNs + ``` + +- [ ] Configure Prometheus metrics: + ```csharp + private static readonly Counter TransactionsProcessed = Metrics + .CreateCounter("clearinghouse_transactions_total", "Total transactions", + new CounterConfiguration { LabelNames = new[] { "clearinghouse", "type", "status" } }); + + TransactionsProcessed.WithLabels("availity", "837", "success").Inc(); + ``` + +- [ ] Build Grafana dashboard: + - Transaction volume by clearinghouse + - Avg response time (<500ms SLA) + - Error rate by type (timeout, validation, rejection) + - Cost per transaction (Stripe billing) + +- [ ] Set up alerts: + - Clearinghouse API down (>5 consecutive failures) + - Response time >1s (SLA breach) + - Error rate >5% + +## Testing + +### Unit Tests +```csharp +[Fact] +public async Task AvailityAdapter_CheckEligibility_ReturnsValid271() +{ + var x12_270 = LoadTestFile("eligibility_request.edi"); + var response = await _availityAdapter.CheckEligibilityAsync(x12_270, "test-tenant"); + Assert.Equal("ACTIVE", response.BenefitStatus); +} +``` + +### Integration Tests +- [ ] Test with clearinghouse sandbox accounts +- [ ] Validate X12 compliance with sample files from partners +- [ ] E2E: Submit 837 → receive 277 (claim acknowledged) → receive 835 (remittance) +- [ ] Load test: 10,000 claims/hour (simulate large payer) + +### Performance Tests +- [ ] Measure adjudication time: parse X12 → route to clearinghouse → receive response + - **Target:** <500ms for eligibility, <5s for claims +- [ ] Kafka throughput: sustain 1,000 messages/sec + +## Dependencies +- ✅ Tenant Management Service (routing configs) +- ✅ Stripe Billing (metering) +- ⏳ Security Hardening (Key Vault for credentials) +- ⏳ Clearinghouse test accounts (Availity, Change, Optum) + +## Documentation +- [ ] Create [docs/CLEARINGHOUSE-INTEGRATION.md](../../docs/CLEARINGHOUSE-INTEGRATION.md) +- [ ] Update [DEPLOYMENT.md](../../DEPLOYMENT.md) with onboarding guide: + 1. Register with clearinghouse + 2. Add credentials to Key Vault + 3. Update tenant config with Sender ID + 4. Test with sample X12 files +- [ ] Add API examples to Swagger docs + +## Success Criteria +- ✅ All 3 clearinghouses connected and tested +- ✅ 99.9% uptime for clearinghouse API calls +- ✅ <500ms median response time for eligibility +- ✅ Zero PHI leaks in logs (automated scans pass) +- ✅ Stripe metering tracks 100% of transactions +- ✅ E2E workflow: 837 submission → 835 remittance in <30 seconds + +## Timeline +- **Weeks 1-2:** Adapter service + Availity integration +- **Weeks 3-4:** Change Healthcare integration +- **Weeks 4-5:** Optum integration +- **Weeks 5-6:** Event-driven processing + Stripe metering +- **Week 7:** Compliance, monitoring, testing + +**Total:** 7 weeks (2 FTE) + +## References +- [Availity Developer Portal](https://www.availity.com/essentials) +- [Change Healthcare API Docs](https://developers.changehealthcare.com) +- [X12 Standards](https://x12.org/products/standards) +- [HIPAA 5010 Implementation Guides](https://www.cms.gov/regulations-and-guidance/administrative-simplification/hipaa-aca) diff --git a/.github/ISSUE_TEMPLATE/v4-legal-finalization.md b/.github/ISSUE_TEMPLATE/v4-legal-finalization.md new file mode 100644 index 00000000..a159638a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/v4-legal-finalization.md @@ -0,0 +1,436 @@ +--- +name: 'Legal Documentation Finalization' +about: Finalize BAA, ToS, and customer contracts for Beta launch +title: '[v4.0] Legal Documentation & Customer Agreements - Beta Launch Readiness' +labels: 'legal, business, priority:high' +assignees: '' +--- + +## 🎯 Objective + +Finalize all legal documentation required to onboard paying customers for Beta launch. This includes Business Associate Agreements (BAA), Terms of Service, Privacy Policy review, and customer contract templates. + +**Priority:** 🔴 **HIGH** (Beta blocker for revenue) +**Effort:** 2-4 weeks (legal counsel + sales/marketing) +**Depends On:** None (can run in parallel with Key Vault) +**Blocks:** Customer onboarding, revenue generation + +--- + +## 📋 Success Criteria + +- [ ] BAA reviewed and approved by HIPAA legal counsel +- [ ] Terms of Service finalized for SaaS offering +- [ ] Privacy Policy updated for production launch (GDPR/CCPA compliance) +- [ ] Master Services Agreement (MSA) template ready +- [ ] Pricing tiers documented and approved +- [ ] 3 Letters of Intent (LOIs) signed from prospective customers +- [ ] Sales enablement materials created (pitch deck, ROI calculator) +- [ ] Customer onboarding checklist finalized + +--- + +## 🔧 Implementation Steps + +### Phase 1: Legal Review & Finalization (Weeks 1-2) + +**1.1 Engage HIPAA Legal Counsel** + +**Action Items:** +- [ ] Identify and engage healthcare-specialized law firm + - **Recommended:** Foley & Lardner, McDermott Will & Emery, or Nixon Peabody (healthcare practice) + - **Budget:** $5K-$10K for initial review + +- [ ] Schedule kickoff call with attorney (1 hour) + - Explain Cloud Health Office business model + - Review current BAA template (in `sales-materials/contracts/`) + - Discuss HIPAA compliance posture + - Identify legal risks and mitigation strategies + +**1.2 Business Associate Agreement (BAA) Review** + +**Current Document:** `sales-materials/contracts/master-services-agreement-template.md` (Exhibit A) + +**Legal Review Checklist:** +- [ ] Verify HIPAA §164.504(e) compliance (all required provisions) +- [ ] Confirm subcontractor language covers Azure, Stripe, clearinghouses +- [ ] Review breach notification timeline (60 days per §164.410) +- [ ] Validate termination clauses and data return procedures +- [ ] Ensure indemnification provisions are balanced +- [ ] Add state-specific requirements (HITECH Act, state breach laws) + +**Deliverable:** Finalized BAA template signed by legal counsel + +**1.3 Terms of Service (ToS) Update** + +**Current Document:** `marketplace/legal/privacy-policy.md` (needs ToS counterpart) + +**Create New Document:** `marketplace/legal/terms-of-service.md` + +**Required Sections:** +```markdown +# Cloud Health Office - Terms of Service + +## 1. Definitions +- "Service" means Cloud Health Office SaaS platform +- "Customer" means healthcare organization subscriber +- "PHI" has the meaning in HIPAA §160.103 + +## 2. Scope of Service +- EDI transaction processing (837, 270/271, 276/277, 275, 278) +- Multi-tenant SaaS hosting on Azure +- 99.9% uptime SLA (see SLA document) +- Support response times per tier + +## 3. Customer Obligations +- Maintain active Azure subscription (if self-hosted) +- Provide accurate configuration data +- Comply with HIPAA Security Rule +- Pay invoices within 30 days + +## 4. Fees and Payment +- Subscription fees as per pricing page +- Transaction-based metering (overages) +- Annual contract with monthly billing +- Auto-renewal unless 30-day notice + +## 5. Data Ownership and Security +- Customer owns all PHI processed +- Cloud Health Office is Business Associate +- Data encrypted in transit (TLS 1.3) and at rest (AES-256) +- 7-year retention per HIPAA + +## 6. Termination +- Either party may terminate with 30-day notice +- Immediate termination for material breach +- Data export provided within 14 days +- No refunds for early termination + +## 7. Limitation of Liability +- Cap at 12 months of fees paid +- No liability for indirect/consequential damages +- Standard disclaimers and warranties + +## 8. Dispute Resolution +- Arbitration in Delaware +- JAMS rules +- English language, Delaware law governs + +## 9. Miscellaneous +- Force majeure +- Assignment restrictions +- Entire agreement +- Amendment process +``` + +**Action Items:** +- [ ] Draft ToS based on template above +- [ ] Legal counsel review and redline +- [ ] Incorporate counsel edits +- [ ] Get executive sign-off + +**1.4 Privacy Policy Update** + +**Current Document:** `marketplace/legal/privacy-policy.md` (v1.0, Dec 1, 2024) + +**Review Checklist:** +- [ ] Update effective date to March 1, 2026 (Beta launch) +- [ ] Add GDPR provisions if EU customers targeted +- [ ] Add CCPA provisions (California customers likely) +- [ ] Clarify data retention (7 years for claims, 90 days for logs) +- [ ] Add cookie policy if portal uses analytics +- [ ] Review subprocessor list (Azure, Stripe, Application Insights) + +**Deliverable:** Privacy Policy v2.0 + +--- + +### Phase 2: Pricing & Packaging (Week 2) + +**2.1 Finalize Pricing Tiers** + +Based on V4-LAUNCH-ROADMAP.md recommendations: + +| Tier | Monthly Price | Payers | Transactions | Target Customer | +|------|---------------|--------|--------------|-----------------| +| **Starter** | $499 | 1-3 | 10,000 | Small payers, pilots | +| **Professional** | $1,999 | 4-10 | 100,000 | Regional payers | +| **Enterprise** | $4,999 | Unlimited | Unlimited | National payers | +| **Custom** | Quote | Unlimited | Unlimited | White-label, SLA | + +**Overage Pricing:** +- Transactions: $0.05 per transaction over limit +- Storage: $50/TB/month over 1TB included +- Support: $200/hour for ad-hoc requests (non-Enterprise) + +**Action Items:** +- [ ] Validate pricing with comparable SaaS platforms (Waystar, Change Healthcare) +- [ ] Calculate unit economics (cost to serve vs. revenue) +- [ ] Get exec approval on pricing +- [ ] Configure in Stripe (products + price IDs) +- [ ] Update website pricing page + +**2.2 Configure Stripe Billing** + +**Already Done (v4.0.0):** +- ✅ Stripe integration in portal +- ✅ Subscription management +- ✅ Webhook handling + +**Remaining Work:** +- [ ] Create Stripe products for each tier + ```bash + # Starter tier + stripe products create --name="Cloud Health Office - Starter" --description="1-3 payers, 10K transactions/month" + stripe prices create --product=prod_XXX --unit-amount=49900 --currency=usd --recurring[interval]=month + + # Professional tier + stripe products create --name="Cloud Health Office - Professional" --description="4-10 payers, 100K transactions/month" + stripe prices create --product=prod_YYY --unit-amount=199900 --currency=usd --recurring[interval]=month + + # Enterprise tier + stripe products create --name="Cloud Health Office - Enterprise" --description="Unlimited payers and transactions" + stripe prices create --product=prod_ZZZ --unit-amount=499900 --currency=usd --recurring[interval]=month + ``` + +- [ ] Set up usage-based metering + ```bash + # Transaction overage meter + stripe products create --name="Transaction Overage" --type=metered + stripe prices create --product=prod_AAA --unit-amount=5 --currency=usd --recurring[interval]=month --billing_scheme=tiered + ``` + +- [ ] Test subscription lifecycle (create, upgrade, cancel) +- [ ] Configure Stripe Tax for sales tax calculation +- [ ] Set up Stripe Billing Portal (customer self-service) + +--- + +### Phase 3: Customer Acquisition (Weeks 2-4) + +**3.1 Create Sales Pitch Deck** + +**New Document:** `sales-materials/pitch-deck-v4.md` + +**Slide Outline:** +1. **Title Slide:** Cloud Health Office - Healthcare EDI Integration in <1 Hour +2. **Problem:** Legacy EDI systems cost $500K+, take 6-12 months to implement +3. **Solution:** Modern SaaS platform, self-service onboarding, pay-as-you-go +4. **Product Demo:** Live walkthrough of 837 claim submission +5. **Technology:** Kubernetes, Azure-native, HIPAA-compliant architecture +6. **Security:** Zero vulnerabilities, multi-tenant isolation, BAA included +7. **Pricing:** Transparent tiers starting at $499/month +8. **Case Study:** Mock "ACME Health Plan reduced EDI costs by 80%" +9. **Roadmap:** v4.0 features (clearinghouses, portals, analytics) +10. **Call to Action:** "Start 30-day free trial today" + +**Action Items:** +- [ ] Design slides (use Canva or PowerPoint with Cloud Health Office branding) +- [ ] Create demo environment (staging with sample data) +- [ ] Record product demo video (10 minutes, YouTube unlisted) +- [ ] Prepare FAQ document (objection handling) + +**3.2 Build ROI Calculator** + +**Tool:** Interactive spreadsheet or web calculator + +**Inputs:** +- Number of payers +- Monthly transaction volume (by type: 837, 270/271, etc.) +- Current EDI vendor cost (or internal labor cost) +- IT staff hours spent on EDI maintenance + +**Outputs:** +- Estimated Cloud Health Office cost per tier +- Monthly savings vs. status quo +- Payback period (months) +- 3-year TCO comparison + +**Action Items:** +- [ ] Build Excel/Google Sheets calculator +- [ ] Embed in website as interactive tool +- [ ] Include in sales pitch deck + +**3.3 Prospect Outreach (Get 3 LOIs)** + +**Target Profile:** +- Health plans with 10K-100K members +- Currently using manual EDI processes or expensive legacy vendor +- Located in states with Medicaid managed care (Ohio, Florida, Texas) +- Decision-maker: CTO, VP of Operations, or Health IT Director + +**Outreach Strategy:** +1. **LinkedIn Search:** "Health Plan CTO" + "Medicaid" + "EDI" +2. **Cold Email:** Personalized message highlighting pain points +3. **Demo Call:** 30-minute live demo + Q&A +4. **LOI Request:** "Commit to 90-day Beta at 50% discount ($249/month for Starter)" + +**Email Template:** +``` +Subject: Cut EDI Integration Costs by 80% - 30-Day Free Trial + +Hi [First Name], + +I noticed [Company] manages Medicaid plans in [State]. Are you still using [Legacy Vendor] for EDI processing? + +We built Cloud Health Office to eliminate the $500K+ price tag of traditional EDI systems. Our customers go live in under 1 hour with: + +✅ 837 Claims, 270/271 Eligibility, 276/277 Status, 278 Prior Auth +✅ HIPAA-compliant SaaS (BAA included) +✅ $499/month starting price (vs. $50K+ setup fees) + +Would you be open to a 15-minute demo to see if we can save [Company] time and money? + +[Your Name] +Founder, Cloud Health Office +[Email] | [Phone] +``` + +**Action Items:** +- [ ] Identify 20 prospects via LinkedIn Sales Navigator +- [ ] Send personalized emails (10/week) +- [ ] Schedule 5 demo calls +- [ ] Get 3 LOIs signed (target: 50% discount for Beta) + +--- + +### Phase 4: Customer Onboarding Process (Week 4) + +**4.1 Onboarding Checklist** + +**Already Exists:** `sales-materials/deployment-guides/customer-onboarding-checklist.md` + +**Review and Update:** +- [ ] Simplify for SaaS model (remove self-hosted Azure deployment steps) +- [ ] Add Stripe subscription creation step +- [ ] Include BAA signature workflow (DocuSign or Adobe Sign) +- [ ] Add SFTP credential provisioning (per tenant) +- [ ] Create welcome email template + +**4.2 BAA Signature Workflow** + +**Tools:** +- DocuSign (recommended, HIPAA-compliant e-signature) +- Adobe Sign (alternative) +- Manual signature + scan (last resort) + +**Process:** +1. Customer signs MSA + BAA via DocuSign +2. Sales rep countersigns within 24 hours +3. Fully executed PDFs emailed to customer + stored in SharePoint +4. BAA expiration tracked in CRM (annual renewal) + +**Action Items:** +- [ ] Set up DocuSign account ($25/month Business Pro plan) +- [ ] Upload BAA template to DocuSign +- [ ] Configure signing workflow (Customer → Sales Rep → Archive) +- [ ] Test end-to-end signature process + +**4.3 Welcome Email & Onboarding** + +**Email Template:** +``` +Subject: Welcome to Cloud Health Office - Let's Get You Live in 1 Hour + +Hi [Customer Contact], + +Congrats on joining Cloud Health Office! We're excited to help you modernize EDI integration. + +Here's how to get started: + +1. SFTP Credentials (attached PDF) + - Host: sftp.cloudhealthoffice.com + - Username: [tenant-shortname] + - Password: [secure-password] + +2. Portal Access + - URL: https://portal.cloudhealthoffice.com + - Login: Use your Azure AD credentials + +3. First Transaction Test + - Upload sample 837 claim to /inbound/837/ + - Check portal for 277 status response (within 5 minutes) + +4. Support + - Email: support@cloudhealthoffice.com + - Response SLA: 4 hours for Starter, 1 hour for Professional, 30 min for Enterprise + +Need help? Schedule a 30-minute onboarding call: [Calendly link] + +Welcome aboard! +[Your Name], Cloud Health Office Team +``` + +**Action Items:** +- [ ] Draft welcome email template +- [ ] Create SFTP credential handoff process (secure password generation) +- [ ] Set up Calendly for onboarding calls +- [ ] Build customer success checklist (30-day, 60-day, 90-day touchpoints) + +--- + +## 📚 Legal Templates to Finalize + +| Document | Status | Location | Owner | +|----------|--------|----------|-------| +| Business Associate Agreement | ✅ Draft exists, needs legal review | `sales-materials/contracts/master-services-agreement-template.md` (Exhibit A) | Legal counsel | +| Terms of Service | ❌ Needs creation | `marketplace/legal/terms-of-service.md` (new) | Legal counsel | +| Privacy Policy | ✅ Exists, needs update | `marketplace/legal/privacy-policy.md` | Legal counsel | +| SLA Document | ✅ Exists | `marketplace/legal/sla.md` | Product team | +| Master Services Agreement | ✅ Draft exists | `sales-materials/contracts/master-services-agreement-template.md` | Legal counsel | +| Order Form Template | ❌ Needs creation | `sales-materials/contracts/order-form-template.md` (new) | Sales team | + +--- + +## 💰 Budget Breakdown + +| Item | Cost | Timeline | +|------|------|----------| +| HIPAA legal counsel review | $5,000-$10,000 | 2 weeks | +| DocuSign Business Pro | $25/month | Ongoing | +| Sales enablement design (pitch deck) | $500 (Fiverr/Upwork) | 1 week | +| Stripe setup & testing | $0 (free tier) | 1 week | +| **Total** | **~$10,000** | **4 weeks** | + +--- + +## 🚨 Risk Mitigation + +| Risk | Impact | Mitigation | +|------|--------|------------| +| Legal review takes >2 weeks | Delays Beta launch | Engage counsel NOW, set hard deadline | +| BAA redlines are extensive | Delays customer signing | Use proven BAA template from healthcare SaaS competitor | +| Prospects don't convert to LOIs | No Beta customers | Offer aggressive discount (50% off for 90 days) | +| Stripe integration breaks | Can't bill customers | Extensive testing in staging, keep manual invoicing as backup | + +--- + +## ✅ Definition of Done + +- [ ] BAA approved by HIPAA legal counsel +- [ ] ToS finalized and published on website +- [ ] Privacy Policy v2.0 published +- [ ] Stripe pricing configured and tested +- [ ] 3 LOIs signed from prospective Beta customers +- [ ] Sales pitch deck finalized (PDF) +- [ ] ROI calculator built and embedded on website +- [ ] Welcome email + onboarding process documented +- [ ] DocuSign workflow tested end-to-end +- [ ] Team trained on customer onboarding process + +--- + +## 📅 Timeline + +| Week | Milestone | Owner | Status | +|------|-----------|-------|--------| +| 1 | Engage legal counsel, start BAA review | Legal | ⬜ Not Started | +| 2 | Finalize ToS, update Privacy Policy | Legal | ⬜ Not Started | +| 2 | Configure Stripe pricing | Product | ⬜ Not Started | +| 2-4 | Prospect outreach (20 emails, 5 demos) | Sales | ⬜ Not Started | +| 3 | Create pitch deck + ROI calculator | Marketing | ⬜ Not Started | +| 4 | Get 3 LOIs signed | Sales | ⬜ Not Started | +| 4 | Set up DocuSign + welcome email | Ops | ⬜ Not Started | + +**Target Completion:** 4 weeks from start +**Beta Launch:** Week 5 (first paying customer onboarded) diff --git a/.github/ISSUE_TEMPLATE/v4-member-provider-portals.md b/.github/ISSUE_TEMPLATE/v4-member-provider-portals.md new file mode 100644 index 00000000..8a7476b1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/v4-member-provider-portals.md @@ -0,0 +1,426 @@ +--- +name: "[v4.0] Member and Provider Portals" +about: Develop self-service portals for members and providers +title: "[v4.0] Develop Member and Provider Portals with Self-Service Features" +labels: enhancement, ui, v4.0, priority-medium +assignees: aurelianware +--- + +## Overview +Create dedicated portals for members (eligibility checks, benefits viewing) and providers (claims submission, performance metrics). Extend the existing Blazor admin portal, integrating tenant management for authentication and Stripe for subscription-gated features. + +## Objectives +- ✅ Member portal with eligibility, benefits, prior auth requests +- ✅ Provider portal with claims submission, directory search, performance dashboard +- ✅ Azure AD B2C authentication with tenant isolation +- ✅ Stripe-gated premium features (advanced reporting) +- ✅ Mobile-responsive UI (prepare for future native apps) +- ✅ Real-time updates via SignalR (claim status notifications) + +## Architecture + +``` +┌─────────────────────────────────────────────────┐ +│ Cloud Health Office Portals │ +├─────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────┐ ┌─────────────┐ ┌──────────┐│ +│ │ Admin │ │ Member │ │ Provider ││ +│ │ Portal │ │ Portal │ │ Portal ││ +│ │ (Existing) │ │ (New) │ │ (New) ││ +│ └──────┬──────┘ └──────┬──────┘ └────┬─────┘│ +│ │ │ │ │ +│ └────────────────┴────────────────┘ │ +│ │ │ +│ Azure AD B2C │ +│ Tenant Context │ +│ │ │ +│ ┌────────────────┴────────────────┐ │ +│ │ │ │ +│ ┌────▼────┐ ┌──────────┐ ┌──────────▼───┐ │ +│ │ Member │ │ Coverage │ │ Claims │ │ +│ │ Service │ │ Service │ │ Service │ │ +│ └─────────┘ └──────────┘ └──────────────┘ │ +│ │ +│ SignalR Hub (Real-time Updates) │ +│ Stripe (Premium Features) │ +└──────────────────────────────────────────────────┘ +``` + +## Implementation Steps + +### Phase 1: Member Portal (Weeks 1-3) + +#### 1.1 Project Setup +- [ ] Clone portal structure: + ```bash + cp -r portal/CloudHealthOffice.Portal portal/CloudHealthOffice.MemberPortal + cd portal/CloudHealthOffice.MemberPortal + dotnet new sln -n MemberPortal + ``` + +- [ ] Update project references: + ```xml + + + + + + + + + ``` + +#### 1.2 Azure AD B2C Configuration +- [ ] Create Azure AD B2C tenant: `cloudhealthofficemembers.onmicrosoft.com` +- [ ] Configure user flows: + - Sign-up/Sign-in (SUSI): Collect email, first/last name, member ID + - Password reset + - Profile editing +- [ ] Register MemberPortal app in Azure AD B2C +- [ ] Add custom attributes: + - `extension_MemberId` (link to Member Service) + - `extension_TenantId` (for multi-tenant isolation) + - `extension_SubscriptionTier` (free/premium) + +- [ ] Update `appsettings.json`: + ```json + { + "AzureAdB2C": { + "Instance": "https://cloudhealthofficemembers.b2clogin.com/", + "ClientId": "", + "Domain": "cloudhealthofficemembers.onmicrosoft.com", + "SignUpSignInPolicyId": "B2C_1_susi", + "CallbackPath": "/signin-oidc", + "Scopes": "openid profile email" + } + } + ``` + +#### 1.3 Member Portal Pages + +##### Home/Dashboard +```razor +@page "/" +@attribute [Authorize] + +Welcome, @context.User.Identity.Name + + + + + + + Coverage Summary + + + + Plan: @coverage.PlanName + Status: Active + Deductible: $@coverage.DeductibleMet / $@coverage.DeductibleTotal + + + + + + + + + Recent Claims + + + + @foreach (var claim in recentClaims) + { + @claim.ServiceDate.ToShortDateString(): @claim.Status + } + + + + +``` + +##### Eligibility Check (`Pages/Eligibility.razor`) +- [ ] Real-time 270/271 transaction via Eligibility Service +- [ ] Form: Service type, provider NPI, service date +- [ ] Display: Coverage status, copay, deductible, out-of-pocket max +- [ ] Export to PDF + +##### Benefits View (`Pages/Benefits.razor`) +- [ ] Display plan benefits from Coverage Service +- [ ] Categories: Medical, dental, vision, pharmacy, mental health +- [ ] Show copays, coinsurance, network details +- [ ] Link to provider directory + +##### Prior Authorization (`Pages/PriorAuth.razor`) +- [ ] Submit 278 (authorization request) +- [ ] Track authorization status (pending/approved/denied) +- [ ] Upload supporting documents (e.g., medical records) +- [ ] Real-time status updates via SignalR + +##### Claims History (`Pages/Claims.razor`) +- [ ] List all claims from Claims Service (filtered by member) +- [ ] Filters: Date range, status, provider +- [ ] Details: Service date, provider, billed amount, paid amount, patient responsibility +- [ ] Explanation of Benefits (EOB) download + +#### 1.4 SignalR Real-Time Updates +- [ ] Create SignalR hub in Claims Service: + ```csharp + // services/claims-service/Hubs/ClaimStatusHub.cs + public class ClaimStatusHub : Hub + { + public async Task SubscribeToClaimUpdates(string memberId) + { + await Groups.AddToGroupAsync(Context.ConnectionId, $"member-{memberId}"); + } + + public async Task NotifyClaimUpdate(string memberId, ClaimStatusUpdate update) + { + await Clients.Group($"member-{memberId}").SendAsync("ClaimUpdated", update); + } + } + ``` + +- [ ] Connect in Member Portal: + ```csharp + // Services/ClaimNotificationService.cs + private HubConnection _hubConnection; + + public async Task StartAsync() + { + _hubConnection = new HubConnectionBuilder() + .WithUrl("https://api.cloudhealthoffice.com/hubs/claimstatus") + .Build(); + + _hubConnection.On("ClaimUpdated", update => + { + NotificationService.Notify($"Claim {update.ClaimId} status: {update.NewStatus}"); + }); + + await _hubConnection.StartAsync(); + await _hubConnection.InvokeAsync("SubscribeToClaimUpdates", _memberId); + } + ``` + +### Phase 2: Provider Portal (Weeks 3-5) + +#### 2.1 Project Setup +- [ ] Clone and configure similar to Member Portal +- [ ] Azure AD B2C tenant: `cloudhealthofficeproviders.onmicrosoft.com` +- [ ] Custom attributes: `extension_NPI`, `extension_TaxonomyCode`, `extension_PracticeGroupId` + +#### 2.2 Provider Portal Pages + +##### Claims Submission (`Pages/SubmitClaim.razor`) +- [ ] Multi-step wizard: + 1. Patient info (member ID, name, DOB) + 2. Service details (CPT codes, diagnosis codes, dates) + 3. Provider info (NPI, taxonomy, place of service) + 4. Review and submit +- [ ] Generate 837 Professional or Institutional +- [ ] Upload via Clearinghouse Adapter Service +- [ ] Real-time validation (e.g., invalid CPT code) + +##### Provider Directory (`Pages/Directory.razor`) +- [ ] Search providers by name, NPI, specialty, location +- [ ] Display: Contact info, accepted plans, performance rating +- [ ] Invite to network (for admin users) + +##### Performance Dashboard (`Pages/Performance.razor`) +- [ ] Metrics from Provider Service: + - Claims volume (90-day trend) + - Authorization approval rate + - Avg time to payment + - Denial rate by reason code + - Quality score (star rating) +- [ ] Interactive charts (ApexCharts.NET) +- [ ] Export to PDF/Excel + +##### Remittance Viewer (`Pages/Remittances.razor`) +- [ ] Display 835 remittance advice +- [ ] Group by payment batch +- [ ] Show adjustments (contractual, deductible, copay) +- [ ] Download ERA (Electronic Remittance Advice) + +### Phase 3: Stripe Premium Features (Week 5) + +#### 3.1 Feature Gating +- [ ] Add `SubscriptionTier` to user claims (from Azure AD B2C) +- [ ] Create authorization policy: + ```csharp + builder.Services.AddAuthorization(options => + { + options.AddPolicy("PremiumFeatures", policy => + policy.RequireClaim("extension_SubscriptionTier", "professional", "enterprise")); + }); + ``` + +- [ ] Gate advanced reports: + ```razor + @attribute [Authorize(Policy = "PremiumFeatures")] + + @code { + // Premium analytics page + } + ``` + +#### 3.2 Stripe Checkout Integration +- [ ] Add upgrade prompt for free users: + ```razor + @if (!IsPremium) + { + + Unlock advanced analytics with a Premium subscription. + Upgrade Now + + } + ``` + +- [ ] Create checkout session: + ```csharp + // Pages/Subscribe.razor.cs + public async Task CreateCheckoutSession() + { + var session = await _stripeService.CreateCheckoutSessionAsync(new CreateCheckoutSessionRequest + { + SuccessUrl = "https://portal.cloudhealthoffice.com/payment-success", + CancelUrl = "https://portal.cloudhealthoffice.com/pricing", + CustomerId = User.FindFirst("extension_StripeCustomerId")?.Value, + PriceId = "price_professional_monthly" + }); + + return Redirect(session.Url); + } + ``` + +- [ ] Handle webhook to update Azure AD B2C custom attribute: + ```csharp + // In Stripe webhook handler + case "checkout.session.completed": + var customerId = session.CustomerId; + var memberId = session.Metadata["member_id"]; + await _graphClient.UpdateUserAsync(memberId, new + { + extension_SubscriptionTier = "professional", + extension_StripeCustomerId = customerId + }); + break; + ``` + +### Phase 4: Mobile Responsiveness (Week 6) + +- [ ] Test on mobile devices (iOS Safari, Android Chrome) +- [ ] Optimize MudBlazor components for touch: + ```razor + + + + ``` +- [ ] Add PWA manifest for "Add to Home Screen": + ```json + { + "name": "Cloud Health Office Member Portal", + "short_name": "CHO Member", + "start_url": "/", + "display": "standalone", + "icons": [ + { + "src": "images/logo-192x192.png", + "sizes": "192x192", + "type": "image/png" + } + ] + } + ``` + +### Phase 5: FHIR R4 Integration (Week 7) + +- [ ] Add FHIR resource endpoints to Member/Provider services: + ```csharp + // GET /fhir/Patient/{id} + public async Task GetPatientAsync(string id) + { + var member = await _memberService.GetMemberAsync(id); + return new Patient + { + Id = member.MemberId, + Name = new List { new HumanName { Family = member.LastName, Given = new[] { member.FirstName } } }, + BirthDate = member.DateOfBirth.ToString("yyyy-MM-dd"), + Gender = member.Gender == "M" ? AdministrativeGender.Male : AdministrativeGender.Female + }; + } + ``` + +- [ ] Expose FHIR-compliant endpoints: + - `Patient` (from Member Service) + - `Coverage` (from Coverage Service) + - `Claim` (from Claims Service) + - `ExplanationOfBenefit` (from Claims Service) + +## Tech Stack +- **Frontend:** Blazor Server (.NET 8), MudBlazor 6.11, ApexCharts.NET +- **Authentication:** Azure AD B2C, Microsoft.Identity.Web +- **Real-time:** SignalR (ASP.NET Core) +- **Payments:** Stripe.js, Stripe Checkout +- **API:** RESTful microservices (Member, Coverage, Claims, Provider) +- **Standards:** FHIR R4 (HL7) + +## Testing + +### UI Tests (Playwright) +```csharp +[Test] +public async Task MemberPortal_EligibilityCheck_ShowsCoverageStatus() +{ + await Page.GotoAsync("https://members.cloudhealthoffice.com/eligibility"); + await Page.FillAsync("#member-id", "M123456789"); + await Page.ClickAsync("button:has-text('Check Eligibility')"); + await Expect(Page.Locator(".coverage-status")).ToHaveTextAsync("Active"); +} +``` + +### E2E Tests +- [ ] Member login → view benefits → check eligibility → submit prior auth +- [ ] Provider login → submit claim → view remittance → download ERA +- [ ] Free user tries premium feature → redirected to upgrade page → completes Stripe checkout → gains access + +### Accessibility (a11y) +- [ ] WCAG 2.1 AA compliance (contrast ratios, keyboard navigation) +- [ ] Screen reader testing (NVDA, VoiceOver) +- [ ] Automated scans with axe-core + +## Dependencies +- ✅ Tenant Management Service (user-to-tenant mapping) +- ✅ Stripe Billing (premium subscriptions) +- ⏳ Azure AD B2C setup +- ⏳ Member/Provider services API readiness + +## Documentation +- [ ] Create [docs/MEMBER-PORTAL.md](../../docs/MEMBER-PORTAL.md) user guide +- [ ] Create [docs/PROVIDER-PORTAL.md](../../docs/PROVIDER-PORTAL.md) user guide +- [ ] Update [ARCHITECTURE.md](../../ARCHITECTURE.md) with portal diagram +- [ ] Add Swagger docs for FHIR endpoints + +## Success Criteria +- ✅ Member portal: 100% feature parity with requirements +- ✅ Provider portal: Claims submission success rate >95% +- ✅ SignalR notifications: <5s latency for claim updates +- ✅ Mobile responsive: All pages render correctly on iPhone/Android +- ✅ Premium conversion: >10% of free users upgrade within 30 days +- ✅ Accessibility: WCAG 2.1 AA passing (0 critical issues) + +## Timeline +- **Weeks 1-3:** Member Portal (pages, auth, SignalR) +- **Weeks 3-5:** Provider Portal (claims submission, performance dashboard) +- **Week 5:** Stripe premium features +- **Week 6:** Mobile responsiveness + PWA +- **Week 7:** FHIR R4 integration + +**Total:** 7 weeks (2 FTE) + +## References +- [MudBlazor Documentation](https://mudblazor.com/) +- [Azure AD B2C Docs](https://learn.microsoft.com/en-us/azure/active-directory-b2c/) +- [FHIR R4 Specification](https://hl7.org/fhir/R4/) +- [Stripe Checkout](https://stripe.com/docs/payments/checkout) diff --git a/.github/ISSUE_TEMPLATE/v4-mobile-apps.md b/.github/ISSUE_TEMPLATE/v4-mobile-apps.md new file mode 100644 index 00000000..63467699 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/v4-mobile-apps.md @@ -0,0 +1,619 @@ +--- +name: "[v4.0] Mobile Apps" +about: Develop cross-platform iOS/Android apps for member and provider access +title: "[v4.0] Develop Mobile Apps for Member and Provider Access" +labels: enhancement, mobile, v4.0, priority-low +assignees: aurelianware +--- + +## Overview +Create cross-platform mobile apps (iOS/Android) for on-the-go access to member and provider portals. Focus on core features like eligibility checks and claims tracking, integrating tenant management for secure authentication and Stripe for in-app purchases. + +## Objectives +- ✅ Native mobile experience for members and providers +- ✅ Core features: Eligibility, claims, prior auth, provider directory +- ✅ Push notifications for claim status updates +- ✅ Offline mode with local caching +- ✅ Stripe in-app purchases for premium features +- ✅ App Store and Google Play deployment + +## Tech Stack Decision + +### Option 1: .NET MAUI (Recommended) +**Pros:** +- Leverage existing .NET codebase (90% code reuse) +- Single codebase for iOS/Android/Windows +- Native performance +- Direct integration with existing microservices +- Team already familiar with C#/.NET + +**Cons:** +- Newer framework (some rough edges) +- Limited third-party component library vs React Native + +### Option 2: React Native +**Pros:** +- Mature ecosystem +- Large component library +- Hot reload for fast development + +**Cons:** +- Requires JavaScript expertise +- Less code reuse with .NET backend +- Bridge performance overhead + +**Decision:** Use .NET MAUI for maximum code reuse and native performance + +## Architecture + +``` +┌─────────────────────────────────────────────────┐ +│ Cloud Health Office Mobile │ +├─────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────┐ ┌─────────────┐ │ +│ │ Member │ │ Provider │ │ +│ │ App │ │ App │ │ +│ │ (iOS/And) │ │ (iOS/And) │ │ +│ └──────┬──────┘ └──────┬──────┘ │ +│ │ │ │ +│ └─────────────┬───────────┘ │ +│ │ │ +│ .NET MAUI Framework │ +│ │ │ +│ ┌─────────────┴─────────────┐ │ +│ │ │ │ +│ ┌────▼────┐ ┌────────┐ ┌──────▼──────┐ │ +│ │ API │ │ Azure │ │ SignalR │ │ +│ │ Client │ │ AD B2C │ │ (Push) │ │ +│ └─────────┘ └────────┘ └─────────────┘ │ +│ │ +│ Secure Storage (Keychain/Keystore) │ +│ Local Cache (SQLite) │ +│ Stripe Mobile SDK │ +└─────────────────────────────────────────────────┘ +``` + +## Implementation Steps + +### Phase 1: Project Setup (Week 1) + +#### 1.1 Create MAUI Projects + +```bash +# Create solution +dotnet new sln -n CloudHealthOfficeMobile + +# Create member app +dotnet new maui -n CloudHealthOffice.MemberApp +dotnet sln add CloudHealthOffice.MemberApp/CloudHealthOffice.MemberApp.csproj + +# Create provider app +dotnet new maui -n CloudHealthOffice.ProviderApp +dotnet sln add CloudHealthOffice.ProviderApp/CloudHealthOffice.ProviderApp.csproj + +# Create shared library +dotnet new classlib -n CloudHealthOffice.Mobile.Shared +dotnet sln add CloudHealthOffice.Mobile.Shared/CloudHealthOffice.Mobile.Shared.csproj +``` + +**Project Structure:** +``` +mobile/ +├── CloudHealthOffice.MemberApp/ +│ ├── Platforms/ +│ │ ├── Android/ +│ │ └── iOS/ +│ ├── Pages/ +│ │ ├── EligibilityPage.xaml +│ │ ├── ClaimsPage.xaml +│ │ └── PriorAuthPage.xaml +│ ├── ViewModels/ +│ └── Services/ +├── CloudHealthOffice.ProviderApp/ +│ ├── Pages/ +│ │ ├── ClaimSubmissionPage.xaml +│ │ ├── DirectoryPage.xaml +│ │ └── PerformancePage.xaml +│ └── ViewModels/ +└── CloudHealthOffice.Mobile.Shared/ + ├── Models/ (Claim, Member, Coverage - reuse from services) + ├── Services/ + │ ├── IApiClient.cs + │ ├── ApiClient.cs + │ ├── IAuthService.cs + │ └── AuthService.cs + └── Helpers/ + ├── SecureStorage.cs + └── CacheManager.cs +``` + +#### 1.2 Install Packages + +```xml + + + + + + + + + + +``` + +### Phase 2: Authentication (Week 1-2) + +#### 2.1 Azure AD B2C Integration + +```csharp +// CloudHealthOffice.Mobile.Shared/Services/AuthService.cs +using Microsoft.Identity.Client; + +public class AuthService : IAuthService +{ + private readonly IPublicClientApplication _pca; + + public AuthService() + { + _pca = PublicClientApplicationBuilder + .Create("member-app-client-id") + .WithB2CAuthority("https://cloudhealthofficemembers.b2clogin.com/tfp/cloudhealthofficemembers.onmicrosoft.com/B2C_1_susi") + .WithRedirectUri("msal{client-id}://auth") + .WithIosKeychainSecurityGroup("com.cloudhealthoffice.memberapp") + .Build(); + } + + public async Task SignInAsync() + { + try + { + // Try silent sign-in first + var accounts = await _pca.GetAccountsAsync(); + return await _pca.AcquireTokenSilent(new[] { "openid", "profile" }, accounts.FirstOrDefault()) + .ExecuteAsync(); + } + catch (MsalUiRequiredException) + { + // Interactive sign-in required + return await _pca.AcquireTokenInteractive(new[] { "openid", "profile" }) + .WithParentActivityOrWindow(GetParentWindow()) + .ExecuteAsync(); + } + } + + public async Task SignOutAsync() + { + var accounts = await _pca.GetAccountsAsync(); + foreach (var account in accounts) + { + await _pca.RemoveAsync(account); + } + + // Clear secure storage + SecureStorage.RemoveAll(); + } +} +``` + +#### 2.2 iOS Configuration + +```xml + +CFBundleURLTypes + + + CFBundleURLSchemes + + msal{client-id} + + + +``` + +#### 2.3 Android Configuration + +```xml + + + + + + + + + +``` + +### Phase 3: Member App Features (Weeks 2-4) + +#### 3.1 Eligibility Check Page + +```xml + + + + +