Exchange API Core Features Implementation
Story and Technical Design Document
Table of Contents
Overview
Purpose
Implement the core Exchange/Outlook monitoring API endpoints following the existing Node.js/TypeScript architecture pattern established in /src/api/exchange. This stage ports functionality from the Python FastAPI implementation to match the Fastify-based structure.
Scope
-
OAuth Authorization flow (GET /auth, GET /auth/callback)
-
Webhook notification handling (POST /webhook/inbox)
-
Inbox subscription management (GET /list_inboxes, DELETE /unsubscribe/inbox/:id)
-
Blocked senders management (GET, POST, DELETE /blocked_senders)
-
Exchange options/configuration (GET, POST /exchange_options)
Dependencies
-
Existing architecture in
/src/api/exchange -
Python implementation reference in
/temp/test.py -
Microsoft Graph API integration
-
SQL Server database with existing schema
User Stories
US-2.1: OAuth Authorization Initiation
As a system administrator
I want to initiate OAuth authorization for monitoring an Exchange inbox
So that I can connect my organization’s email account to the monitoring system
Acceptance Criteria:
-
GET
/exchange/authendpoint generates Microsoft OAuth URL -
State parameter is generated and stored with 10-minute expiration
-
Optional email_hint query parameter pre-fills login
-
Returns authorization URL or redirects to Microsoft login
-
Requires Administrator role and EXCHANGE_READ scope
-
State includes client_id, initiated_by_user, requested_inbox, expires_at
Technical Notes:
-
Store state in memory (Map) with cleanup mechanism
-
Generate UUID v4 for state parameter
-
Build OAuth URL with proper scopes and tenant configuration
US-2.2: OAuth Authorization Callback
As a system administrator
I want to complete the OAuth flow after Microsoft login
So that the system can obtain access tokens and create inbox subscriptions
Acceptance Criteria:
-
GET
/exchange/auth/callbackreceives code and state parameters -
Validates state parameter exists and hasn’t expired
-
Exchanges authorization code for access tokens
-
Extracts monitored inbox email from ID token
-
Validates requested inbox matches authenticated inbox (if specified)
-
Creates Microsoft Graph subscription for inbox monitoring
-
Stores subscription details in
exchange_inbox_subscriptionstable -
Encrypts and stores access/refresh tokens in
exchange_inbox_tokenstable -
Redirects user to frontend settings page on success
-
Properly handles errors (invalid state, token failure, subscription creation failure)
Technical Notes:
-
Use MD5 hash of client_name for client_id storage
-
Subscription expires in 4230 minutes (configurable)
-
Webhook URL points to
/exchange/webhook/inbox -
Monitor
/me/mailFolders('inbox')/messagesresource -
Token expiration calculated from
expires_inresponse
US-2.3: Webhook Notification Processing
As a system
I want to receive and process webhook notifications from Microsoft Graph
So that new emails can be detected and processed automatically
Acceptance Criteria:
-
POST
/exchange/webhook/inboxhandles validation token requests -
Processes notification payloads with ‘value’ array
-
Extracts clientState, subscriptionId, and message ID from notifications
-
Validates required fields are present
-
Retrieves access token using subscription_id
-
Fetches email details from Microsoft Graph API
-
Checks sender against blocked senders list
-
Fetches and decodes PDF attachments
-
Classifies attachments using Azure Document Intelligence
-
Applies event actions (mark as read, move to folder) based on classification
-
Processes invoices through workflow engine
-
Returns 200 status for successful processing
-
Handles errors gracefully without blocking webhook acknowledgment
Technical Notes:
-
Return validation token immediately as plain text
-
Process notifications asynchronously if possible
-
Use background tasks for email processing
-
Implement proper timeout handling (30s for Graph API calls)
-
Log all processing steps for debugging
US-2.4: List Inbox Subscriptions
As a system administrator
I want to view all monitored inbox subscriptions
So that I can see which inboxes are currently being monitored
Acceptance Criteria:
-
GET
/exchange/list_inboxesreturns list of subscriptions -
Filters results by authenticated client_name
-
Returns inbox_address and subscription_id for each subscription
-
Requires Administrator role and EXCHANGE_READ scope
-
Returns empty array if no subscriptions exist
-
Handles database errors gracefully
Technical Notes:
-
Join with Clients table to get ClientId from client_name
-
Return standardized response format:
{ result: InboxListItem[] }
US-2.5: Unsubscribe from Inbox
As a system administrator
I want to remove an inbox subscription
So that emails from that inbox are no longer monitored
Acceptance Criteria:
-
DELETE
/exchange/unsubscribe/inbox/:subscription_idremoves subscription -
Deletes subscription from Microsoft Graph (if still active)
-
Removes subscription from local database
-
Removes associated tokens from database
-
Returns success message on completion
-
Returns 404 if subscription doesn’t exist
-
Handles expired subscriptions (skip Graph deletion, still delete from DB)
-
Requires Administrator role
Technical Notes:
-
Check subscription expiration before attempting Graph API deletion
-
Always delete from local database even if Graph deletion fails
-
Use refresh token to get access token for Graph deletion
US-2.6: List Blocked Senders
As a system administrator
I want to view all blocked email senders/domains
So that I can see which senders are being filtered
Acceptance Criteria:
-
GET
/exchange/blocked_sendersreturns list of blocked senders -
Filters by authenticated client_name
-
Returns id, value, reason, created_on for each entry
-
Supports both email addresses and domain patterns (@domain.com)
-
Orders results by created_on DESC
-
Requires Administrator role and EXCHANGE_READ scope
Technical Notes:
-
Use MD5 hash of client_name for client_id filtering
-
Return standardized format:
{ result: BlockedSenderItem[] }
US-2.7: Add Blocked Sender
As a system administrator
I want to add an email address or domain to the blocked list
So that emails from that sender are automatically filtered
Acceptance Criteria:
-
POST
/exchange/blocked_sendersadds new blocked sender -
Validates value is either valid email or domain pattern (@domain.com)
-
Requires ‘value’ field in request body
-
Optional ‘reason’ field for documentation
-
Associates with authenticated client
-
Returns success message on completion
-
Returns 400 for invalid email/domain format
-
Prevents duplicate entries
-
Requires Administrator role and EXCHANGE_WRITE scope
Technical Notes:
-
Email regex:
^[^@\s]+@[^@\s]+\.[^@\s]+$ -
Domain regex:
^@[^@\s]+\.[^@\s]+$ -
Store created_on timestamp automatically
US-2.8: Remove Blocked Sender
As a system administrator
I want to remove a sender from the blocked list
So that emails from that sender are no longer filtered
Acceptance Criteria:
-
DELETE
/exchange/blocked_senders/:sender_idremoves blocked sender -
Validates sender_id is valid integer
-
Returns success message on completion
-
Returns 404 if sender_id doesn’t exist
-
Requires Administrator role and EXCHANGE_WRITE scope
Technical Notes:
-
Consider adding client_id check to prevent cross-client deletion
US-2.9: Get Exchange Options
As a system administrator
I want to retrieve configuration for a specific inbox subscription
So that I can view how emails are being processed
Acceptance Criteria:
-
GET
/exchange/exchange_options?subscription_id=xxxreturns configuration -
Returns classifier parameters and classified event actions
-
Returns invoice and other email handling rules
-
Includes markAs (read/unread) and moveTo (folder path) settings
-
Returns 404 if subscription doesn’t exist
-
Requires Administrator role
Technical Notes:
-
Load from both database and Cosmos DB (client config)
-
Merge classifier parameters with event actions
-
Return format:
{ classified: {invoice: {...}, other: {...}}, classifier: {...} }
US-2.10: Update Exchange Options
As a system administrator
I want to update email processing rules for an inbox
So that I can control how invoices and other emails are handled
Acceptance Criteria:
-
POST
/exchange/exchange_optionsupdates configuration -
Requires subscription_id and classified object in request body
-
Updates event_actions fields in exchange_inbox_subscriptions table
-
Supports invoice and other email actions configuration
-
Returns success message on completion
-
Validates classified object structure
-
Returns 400 for missing/invalid data
-
Requires Administrator role
Technical Notes:
-
Update fields: event_actions_invoice_mark_as_read, event_actions_invoice_move_to, event_actions_other_mark_as_read, event_actions_other_move_to
-
Convert markAs string to boolean for database storage
Technical Architecture
Directory Structure
Layer Responsibilities
Route Layer (exchanges.route.ts)
-
Define HTTP routes and methods
-
Apply authentication/authorization middleware
-
Map requests to controller methods
-
Configure OpenAPI schema from exchanges.schema.ts
Controller Layer (exchanges.controller.ts)
-
Extract and validate request parameters
-
Call service layer methods
-
Format responses
-
Handle HTTP-specific concerns (status codes, headers)
-
Catch and format errors
Service Layer (exchanges.service.ts)
-
Implement business logic
-
Orchestrate operations across multiple models
-
Handle Microsoft Graph API integration
-
Manage token refresh and encryption
-
Process email attachments and classification
-
Apply email actions (mark as read, move to folder)
Model Layer (exchanges.model.ts)
-
Execute database queries
-
Map database results to TypeScript types
-
Handle database errors
-
Use parameterized queries for security
Schema Layer (exchanges.schema.ts)
-
Define Zod schemas for validation
-
Define OpenAPI documentation
-
Export reusable type definitions
API Endpoints Design
1. OAuth Authorization Initiation
Endpoint: GET /exchange/auth
Query Parameters:
Headers:
Response: 200 OK
Security:
-
Roles: Administrator
-
Scopes: EXCHANGE_READ
Implementation Notes:
-
Generate UUID v4 for state
-
Store state with 10-minute expiration
-
Build Microsoft OAuth URL with configured client_id, redirect_uri, scopes
-
Include state parameter in OAuth URL
2. OAuth Authorization Callback
Endpoint: GET /exchange/auth/callback
Query Parameters:
Response: 302 Redirect
Error Responses:
-
400 Bad Request- Invalid or expired state, authorization failed -
409 Conflict- Inbox mismatch (requested vs authenticated) -
504 Gateway Timeout- Token request or subscription creation timeout
Implementation Notes:
-
Validate state parameter
-
Exchange code for tokens with Microsoft token endpoint
-
Decode ID token to extract email
-
Create Graph API subscription
-
Store subscription and encrypted tokens
-
Clean up state after use
3. Webhook Notification Handler
Endpoint: POST /exchange/webhook/inbox
Query Parameters (for validation):
Request Body (notification):
Response: 200 OK
Validation Response: 200 OK (plain text)
Error Responses:
-
400 Bad Request- Invalid JSON, missing required fields -
403 Forbidden- Access token not found -
500 Internal Server Error- Processing error
Implementation Notes:
-
Handle validation token immediately
-
Process notifications asynchronously
-
Fetch email details from Graph API
-
Check blocked senders
-
Classify attachments
-
Apply event actions
-
Trigger workflow for invoices
4. List Inbox Subscriptions
Endpoint: GET /exchange/list_inboxes
Headers:
Response: 200 OK
Security:
-
Roles: Administrator
-
Scopes: EXCHANGE_READ
5. Unsubscribe from Inbox
Endpoint: DELETE /exchange/unsubscribe/inbox/:subscription_id
Path Parameters:
Headers:
Response: 200 OK
Error Responses:
-
404 Not Found- Subscription doesn’t exist -
504 Gateway Timeout- Microsoft Graph deletion timeout
Security:
-
Roles: Administrator
6. List Blocked Senders
Endpoint: GET /exchange/blocked_senders
Headers:
Response: 200 OK
Security:
-
Roles: Administrator
-
Scopes: EXCHANGE_READ
7. Add Blocked Sender
Endpoint: POST /exchange/blocked_senders
Headers:
Request Body:
Response: 200 OK
Error Responses:
-
400 Bad Request- Missing value, invalid email/domain format -
500 Internal Server Error- Database error
Validation Rules:
-
value must be valid email:
user@example.com -
OR value must be valid domain:
@example.com
Security:
-
Roles: Administrator
-
Scopes: EXCHANGE_WRITE
8. Remove Blocked Sender
Endpoint: DELETE /exchange/blocked_senders/:sender_id
Path Parameters:
Headers:
Response: 200 OK
Error Responses:
-
404 Not Found- Sender ID doesn’t exist -
500 Internal Server Error- Database error
Security:
-
Roles: Administrator
-
Scopes: EXCHANGE_WRITE
9. Get Exchange Options
Endpoint: GET /exchange/exchange_options
Query Parameters:
Headers:
Response: 200 OK
Error Responses:
-
404 Not Found- Subscription not found -
500 Internal Server Error- Configuration load failure
Security:
-
Roles: Administrator
10. Update Exchange Options
Endpoint: POST /exchange/exchange_options
Headers:
Request Body:
Response: 200 OK
Error Responses:
-
400 Bad Request- Missing or invalid subscription_id or classified object -
500 Internal Server Error- Update failed
Security:
-
Roles: Administrator
Data Models & Schemas
TypeScript Interfaces
Zod Schemas
Service Layer Design
Core Service Methods
Microsoft Graph API Integration
Token Encryption Utilities
Database Schema
Table: exchange_inbox_subscriptions
Table: exchange_inbox_tokens
Table: exchange_blocked_senders
Database Queries
Security & Authentication
Authentication Flow
-
Client authenticates with JWT token
-
JWT contains client_name and roles
-
Fastify middleware validates JWT and extracts user
-
Authorization middleware checks roles and scopes
Required Roles & Scopes
| Endpoint | Roles | Scopes |
|----------|-------|--------|
| GET /auth | Administrator | EXCHANGE_READ |
| GET /auth/callback | None (public) | - |
| POST /webhook/inbox | None (public) | - |
| GET /list_inboxes | Administrator | EXCHANGE_READ |
| DELETE /unsubscribe/inbox/:id | Administrator | - |
| GET /blocked_senders | Administrator | EXCHANGE_READ |
| POST /blocked_senders | Administrator | EXCHANGE_WRITE |
| DELETE /blocked_senders/:id | Administrator | EXCHANGE_WRITE |
| GET /exchange_options | Administrator | - |
| POST /exchange_options | Administrator | - |
Token Security
-
Access tokens encrypted at rest using AES-256-CBC
-
Refresh tokens encrypted at rest using AES-256-CBC
-
Encryption key stored as base64-encoded environment variable
-
OAuth state parameters have 10-minute expiration
-
State parameters validated to prevent CSRF attacks
Input Validation
-
All request bodies validated with Zod schemas
-
Email addresses validated with regex
-
Domain patterns validated with regex
-
UUIDs validated with Zod
-
Path parameters sanitized
Error Handling
Error Response Format
HTTP Status Codes
| Status | Usage |
|--------|-------|
| 200 OK | Successful operation |
| 201 Created | Resource created (rare in this API) |
| 204 No Content | Successful deletion |
| 400 Bad Request | Validation error, invalid input |
| 401 Unauthorized | Missing or invalid JWT token |
| 403 Forbidden | Insufficient permissions |
| 404 Not Found | Resource doesn’t exist |
| 409 Conflict | State conflict (inbox mismatch) |
| 500 Internal Server Error | Unexpected server error |
| 504 Gateway Timeout | External API timeout |
Error Handling Strategy
Logging Requirements
-
Log all OAuth flow events with state tracking
-
Log all webhook notifications received
-
Log all email processing steps
-
Log all Graph API calls with timing
-
Log all database operations
-
Log all errors with full context
-
Use structured logging (Pino)
-
Include correlation IDs for tracing
Implementation Checklist
Task 2.1 - OAuth Authorization Endpoints
-
Create state store with expiration (Map or Redis)
-
Implement state generation (UUID v4)
-
Implement GET /auth endpoint
-
Build Microsoft OAuth URL with proper parameters
-
Add Zod schema for query parameters
-
Implement GET /auth/callback endpoint
-
Add state validation logic
-
Implement token exchange with Microsoft
-
Add ID token decoding
-
Implement inbox validation logic
-
Add error handling for all failure cases
-
Update exchanges.schema.ts with OpenAPI docs
-
Test OAuth flow end-to-end
Task 2.2 - Webhook Endpoint
-
Implement POST /webhook/inbox endpoint
-
Handle validation token requests
-
Parse webhook notification payload
-
Validate required fields (clientState, subscriptionId, resourceData.id)
-
Implement email fetching from Graph API
-
Implement attachment fetching and decoding
-
Add PDF validation (check %PDF header)
-
Integrate blocked sender checking
-
Implement email actions (mark as read, move to folder)
-
Add background task processing
-
Add comprehensive error handling
-
Update exchanges.schema.ts with OpenAPI docs
-
Test webhook with real notifications
Task 2.3 - Inbox Management Endpoints
-
Implement GET /list_inboxes endpoint
-
Add client_name to ClientId resolution
-
Query exchange_inbox_subscriptions table
-
Implement DELETE /unsubscribe/inbox/:id endpoint
-
Add subscription expiration checking
-
Implement Graph API subscription deletion
-
Implement database subscription deletion
-
Add cascade token deletion
-
Update exchanges.schema.ts with OpenAPI docs
-
Test subscription lifecycle
Task 2.4 - Blocked Senders Endpoints
-
Implement GET /blocked_senders endpoint
-
Query exchange_blocked_senders table
-
Implement POST /blocked_senders endpoint
-
Add email/domain validation with Zod
-
Implement database insertion with duplicate handling
-
Implement DELETE /blocked_senders/:id endpoint
-
Add blocked sender checking utility
-
Update exchanges.schema.ts with OpenAPI docs
-
Test blocked sender filtering
Task 2.5 - Exchange Options Endpoints
-
Implement GET /exchange_options endpoint
-
Query exchange_inbox_subscriptions for event actions
-
Load classifier config from Cosmos DB (or config file)
-
Merge configuration objects
-
Implement POST /exchange_options endpoint
-
Validate classified object structure
-
Update event_actions fields in database
-
Update exchanges.schema.ts with OpenAPI docs
-
Test configuration updates
Task 2.6 - Service Layer Implementation
-
Create GraphService for Microsoft Graph API calls
-
Implement token encryption/decryption utilities
-
Implement token refresh logic
-
Create email processing service methods
-
Implement attachment fetching and decoding
-
Implement folder creation/retrieval logic
-
Implement email update operations (mark as read)
-
Implement email move operations
-
Add proper timeout handling (30s for Graph API)
-
Add retry logic for transient failures
Task 2.7 - Zod Schemas & Validation
-
Create AuthQuerySchema
-
Create AuthCallbackQuerySchema
-
Create BlockedSenderBodySchema with custom validation
-
Create ExchangeOptionsQuerySchema
-
Create ExchangeOptionsBodySchema
-
Create SubscriptionIdParamSchema
-
Create SenderIdParamSchema
-
Add custom email/domain regex validators
-
Update all schemas in exchanges.schema.ts
Task 2.8 - Error Handling & Logging
-
Add structured error classes (ValidationError, NotFoundError, etc.)
-
Implement consistent error response format
-
Add comprehensive logging to all service methods
-
Add correlation IDs for request tracing
-
Add timing metrics for Graph API calls
-
Add error context (subscription_id, message_id, etc.)
-
Test error scenarios
Task 2.9 - Integration & Testing
-
Test OAuth flow with real Microsoft account
-
Test webhook validation token response
-
Test webhook notification processing
-
Test blocked sender filtering
-
Test email actions (mark as read, move to folder)
-
Test token refresh logic
-
Test error handling for all endpoints
-
Verify database operations
-
Load test webhook endpoint
Task 2.10 - Documentation
-
Update OpenAPI schemas in exchanges.schema.ts
-
Add JSDoc comments to all public methods
-
Document environment variables
-
Create Postman collection
-
Document Graph API integration
-
Document token encryption approach
-
Create deployment notes
Environment Variables
Dependencies
Required npm Packages
Testing Strategy
Unit Tests
-
Test token encryption/decryption
-
Test email/domain validation
-
Test state management
-
Test blocked sender checking
-
Test configuration merging
Integration Tests
-
Test OAuth flow end-to-end
-
Test webhook processing
-
Test Graph API integration
-
Test database operations
-
Test email actions
Manual Testing
-
Test with real Microsoft account
-
Test webhook with ngrok
-
Test various email scenarios
-
Test blocked sender filtering
-
Test folder creation
Next Steps
-
Review and approve this design document
-
Create detailed implementation tickets for each task
-
Set up development environment with required credentials
-
Begin implementation with Task 2.1 (OAuth endpoints)
-
Implement tasks sequentially with testing after each
-
Conduct code review after each major component
-
Perform end-to-end integration testing
-
Update documentation with any design changes
Document Version: 1.0
Created: January 9, 2026
Author: GitHub Copilot