Platform Architecture
How the application layers connect, how users authenticate, and how data flows through the system.
Application Layers
Clevermore is split into three layers, each deployed independently:
| Layer | Technology | Hosted On |
|---|---|---|
| Outlook Taskpane | React (Next.js) rendered inside Outlook's iframe | Vercel |
| Discovery Endpoint | A small Next.js route that resolves which deployment a signed-in user belongs to. Holds no firm data and has no database. | Vercel |
| Backend Services | Express server running all business logic, AI processing, and durable background jobs | Azure Container Apps |
The Outlook taskpane is a standard web application loaded by Outlook via a manifest file. On sign-in it calls the discovery endpoint once to learn which deployment it belongs to, then talks directly to that deployment’s Container App over HTTPS for the rest of the session.
Authentication Model
All authentication flows through Microsoft Entra ID (Azure AD). Clevermore uses the OAuth 2.0 On-Behalf-Of (OBO) flow to obtain delegated tokens for accessing Microsoft Graph and other services.
Add-in Permissions (Delegated)
| Permission | Purpose |
|---|---|
| openid, profile, email, offline_access | Standard OpenID Connect sign-in, plus refresh tokens so users are not re-prompted every session. |
| User.Read | Read the signed-in user's own profile (display name, mail, ID). |
| Mail.Read | Read message bodies, subjects, and recipients to extract tasks, build catch-up summaries, and enrich contact profiles. |
| Mail.ReadWrite | Apply Outlook categories, toggle flags, and mark messages read/unread when the user accepts a Clevermore suggestion. |
| Mail.ReadWrite.Shared | The same operations on shared and delegated mailboxes (executive-assistant scenarios). |
| Mail.Send | Send drafts the user has explicitly composed or approved. |
| Mail.Send.Shared | Send from a delegated or shared mailbox the user holds send-as rights on. |
| MailboxFolder.ReadWrite | Enumerate existing mail folders to map client matters onto the folders the firm already uses, and file a conversation when the user asks. |
| MailboxItem.Read | Read item-level metadata for reliable thread reconstruction across moves and re-files. |
| MailboxSettings.ReadWrite | Read the user's time zone and signature, and maintain the mailbox master category list so applied categories render correctly. |
| Calendars.ReadWrite | Read upcoming events for meeting context in summaries and tasks, and create entries when the user accepts a scheduling suggestion. |
| Contacts.ReadWrite | Read Outlook contacts to seed contact profiles, and write back enriched details when the user accepts a suggestion. |
| People.Read, User.Read.All, User.ReadBasic.All | Resolve email participants to display names and basic profile fields. The directory is never enumerated and extended attributes are never read. |
| Group.Read.All | Resolve distribution-list and Microsoft 365 group display names so participant lists are readable rather than raw object IDs. |
| Files.ReadWrite.AppFolder | Read and write only inside Clevermore's own folder in the user's OneDrive. Grants no access to any other file, folder, or SharePoint content. |
| OnlineMeetings.ReadWrite | Reserved for Teams meeting creation. Declared now so the feature can ship without a tenant-wide re-consent cycle — not called by any code path today. |
| Tasks.ReadWrite | Reserved for opt-in Microsoft To Do sync. Declared now for the same reason — not called by any code path today. |
These permissions are delegated (not application-level), meaning they act on behalf of the signed-in user and can never exceed that user’s own mailbox access. Consent is granted once, tenant-wide, by a Global Administrator — the consent dialog displays every permission above, and nothing is requested at runtime outside that initial grant.
Files.ReadWrite.AppFolder rather than Files.ReadWrite.All), and the consent, revocation, and audit procedures are documented in the Microsoft Graph Permissions Policy. The app registration is defined as Bicep in source control, so the deployed set can be verified at any time with az ad app permission list or in the Entra ID portal.Admin Portal Permissions
| Permission | Purpose |
|---|---|
| openid, profile, email, User.Read | Standard OIDC login for admin users |
| User.Read.All (optional) | Enables user directory search when adding managed users |
The admin portal requires only standard OIDC scopes to sign in — no elevated permissions or admin consent ceremony is needed. User.Read.All is an optional enhancement that can be enabled incrementally from within the portal.
App Registrations
Clevermore uses two multi-tenant app registrations in Clevermore’s Azure AD tenant: one for the Outlook add-in (with OBO flow and Mail.Read) and one for the admin portal (OIDC login only). Both are multi-tenant, so no app registration needs to be created in the client’s tenant.
When a firm deploys the add-in via Integrated Apps, a service principal is created in their tenant automatically. The admin portal creates its own service principal on first admin sign-in.
Data Flow
When a user opens an email in Outlook, the following sequence occurs:
- Outlook provides the email’s metadata (sender, recipients, subject, date) to the taskpane via the Office.js API.
- The taskpane sends the email ID to the Clevermore API, which uses the delegated token to fetch the full email body from Microsoft Graph.
- The backend processes the email content through AI models (with zero data retention) to extract tasks, update contact profiles, and build wiki entries.
- Extracted data is stored in the tenant’s PostgreSQL database, isolated via row-level security policies.
- Real-time updates are pushed to all connected clients via Azure Web PubSub (WebSocket-based).
Deployment Resolution
In a multi-tenant environment, Clevermore needs to route each request to the correct backend infrastructure. This is handled by the deployment resolver:
- User authenticates → JWT
tidclaim identifies their Azure AD tenant. - The resolver maps
tenantId + orgIdto the organization’s deployment config. - The deployment config provides all infrastructure endpoints: PostgreSQL host, Redis prefix, Web PubSub endpoint, and Container App URL.
For firms with multiple offices (e.g., different Dentons offices), each office maps to its own organization and potentially its own deployment with fully isolated infrastructure.
Real-Time Updates
Clevermore uses Azure Web PubSub for real-time communication between the backend and connected Outlook clients. When the backend processes an email and extracts tasks, it publishes events to Web PubSub, which fans them out to all clients belonging to that user.
Web PubSub is configured with OAuth-only authentication (no access keys). Messages pass through without being stored — Web PubSub acts as a pure relay.
AI Processing
AI processing is handled by external providers (Google Vertex AI, OpenAI) configured with zero data retention. Email content is sent to the AI provider for analysis, and the response is processed immediately. No email content is stored by the AI provider, logged, or used for model training.
The AI provider is configurable per deployment, allowing firms to choose their preferred provider or use a private Azure OpenAI instance within their own tenant for maximum data sovereignty.
Outlook Performance
Clevermore is a Microsoft 365 web add-in. No Clevermore code runs inside outlook.exe; its taskpane is a separate WebView2 (Windows) or WKWebView (Mac) process managed by the Office host, visible under Outlook in Task Manager or Performance Monitor.
| Concern | Behavior |
|---|---|
| Outlook launch | Web add-ins are not loaded at startup. The taskpane process starts when a user first opens it, so cold launch is unaffected. |
| Memory | Bounded by the taskpane process, typically tens of MB, and reclaimed in full when it exits. Outlook’s own memory is unaffected. |
| CPU at idle | Effectively zero. The taskpane is event-driven and never polls the mailbox; email is analyzed on the server after Exchange delivers it. |
This is why Clevermore avoids the memory problems firms associate with VSTO add-ins. VSTO add-ins load into outlook.exe as in-process COM components, so a missed reference release pins memory until Outlook restarts. A web add-in reaches Outlook only through the sandboxed Office.js bridge, with no shared object references to leak, and if its taskpane ever crashed or hung, Outlook itself would keep running. Microsoft documents this model in the Office Add-ins overview.