All work
Enterprise Correspondence PlatformIn productionFull stack engineer

A secure platform for formal correspondence in a large organization: drafting, approval, dispatch, notes, tasks and search.

  • Less paper

    Formal correspondence moves into one platform, reducing paper-based correspondence.

  • Every letter searchable

    Full-text search across all correspondence makes any letter easy to find.

  • A modern experience

    A new interface in place of the old system’s dated one.

  • Drafting with the AI Copilot

    Helps with official correspondence and reduces the time it takes.

  • Services that scale on their own

    Independent services over a shared database, so each component scales individually.

Existing system
One monolith
Version 2.0
  • Core
  • Mail and notes
  • Search
  • Chat
  • Support
  • Tasks
  • Files
  • Integration
  • Copilot
  • Job engine
  • Doc renderer
  • Templating
Shared database

Client

  • Next.js
  • React
  • TypeScript

Services

  • Node.js
  • TypeScript
  • GraphQL

Cache and queue

  • Redis
  • RabbitMQ

Data and search

  • SQL database
  • Elasticsearch
  • Object storage

Identity

  • OIDC provider
  • LDAP directory

AI and documents

  • LLM and OCR
  • Word to PDF rendering
  • Template rendering

Step through a request one hop at a time, or switch to Trace and break to see which flows a service takes part in.

CLIENTSERVICESCACHE AND QUEUEDATAEXTERNALWeb clientNext.js, /bffIdentityOIDC providerDirectoryLDAPLegacy & peersLetter exchangeLLM & OCRCloud, on-premCoreAuth, users, todosChatToken authMail & notesIn, out, notesSearchIndex, accessSupportAlerts, calendarTasksTasks, exportIntegrationLegacy, peersFilesSigned linksCopilotAI, extractionJob engineSchedulerDoc rendererWord to PDFCacheSessions, locksTemplatingTemplate rendererQueueRabbitMQ, DLQDatabasePer-service tablesSearch indexElasticsearchObject storageAttachmentsPod volumeFile cache

The whole system. Pick a scenario, then step through it. The view zooms to the services each step involves.

  • Request
  • Search
  • Events

  1. Sessions

    Server-side sessions instead of tokens in the browser

    Chose

    A backend-for-frontend signs the user in and keeps the session on the server, in the database and then the cache. The browser holds only a session cookie.

    Rejected

    Keeping tokens in the browser.

    Why

    What a person can see depends on the role they sign in under, for example executive or non-executive, and the identity provider cannot supply that. People can also switch roles mid-session, which a server-side session can follow. Tokens held in a browser can be stolen.

  2. Messaging

    Events instead of direct calls

    Chose

    Dispatching a letter, and tagging, publish events to RabbitMQ. Search indexing, notifications and document tracking consume them afterward.

    Rejected

    The mail service calling each of those services directly.

    Why

    Dispatching does not wait on indexing, notifying or tracking, and each event waits in the queue until its consumer has processed it.

  3. API layer

    One generic CRUD factory with authorization built in

    Chose

    A generic GraphQL factory that generates the endpoints for an entity, with the authorization setup included.

    Rejected

    Writing list queries and authorization separately for each entity and service.

    Why

    The platform also needed a user-management module where admins read and write records. One factory gave many endpoints out of the box and removed the same list queries being written again and again.