Global Clinic Docsv1.0
Back to app
Docs / Developer Documentation

1. Architecture Documentation

1.1 High-level system architecture

As built today

The platform is a single Next.js application with three surfaces (public site, patient portal, clinic console) plus authentication, exported to a fully static site and served from a CDN. There is no application server and no backend at runtime; all data is static.

flowchart TD
  subgraph Client[Browser]
    SITE[Public site /]
    PORTAL[Patient portal /portal/*]
    CLINIC[Clinic console /clinic/*]
    AUTH[Auth /signin /register ...]
    HELP[In-app help + walkthrough]
    DOCSITE[Docs /docs/*]
  end
  SITE --> DATA[lib/data.ts]
  PORTAL --> DATA
  CLINIC --> DATA
  DATA --> JSON[(static JSON /data)]
  AUTH --> MOCK[lib/auth.tsx mock + localStorage]
  Client --> CDN[CloudFront CDN]
  CDN --> S3[(S3 static bucket)]

Target production architecture

Production introduces an API layer, a relational database, identity and access management, object storage, a payments and escrow partner, a messaging and notification layer, and a set of external integrations. The static front-end stays; the lib/data.ts seam is repointed at the API.

flowchart TD
  subgraph Edge
    CDN[CloudFront CDN] --> WEB[Static Next.js app]
  end
  WEB --> GW[API Gateway / BFF]
  GW --> AUTHZ[AuthN/AuthZ service]
  GW --> SVC[Domain services]
  subgraph Services
    SVC --> PAT[Patient & Case]
    SVC --> CLIN[Clinic & Provider]
    SVC --> VISA[Visa engine + Country Packs]
    SVC --> PAY[Payments & Escrow]
    SVC --> DOC[Documents]
    SVC --> MSG[Messaging & Notifications]
    SVC --> CAT[Catalogue & Reviews]
    SVC --> RPT[Reporting & Analytics]
  end
  PAT --> DB[(PostgreSQL, multi-tenant)]
  CLIN --> DB
  VISA --> DB
  PAY --> DB
  DOC --> OBJ[(Encrypted object storage)]
  MSG --> BUS[(Event bus / queue)]
  RPT --> WH[(Analytics warehouse)]
  PAY --> PSP[Payment & escrow partner]
  VISA --> GOV[Government visa channels]
  MSG --> COMMS[WhatsApp / Email / SMS]
  SVC --> EXT[Travel / Hotel / Translation / Insurance / CRM]

Architectural principles:

  • Schema-first. lib/schema.ts is the contract shared by the UI and the API. Domain services own their data but conform to these shapes at the boundary.
  • One data seam. The front-end reads through lib/data.ts only. Components never import data directly. This is the single place the backend is wired in.
  • Stateless services, stateful stores. Domain services are horizontally scalable; state lives in PostgreSQL, object storage, and the event bus.
  • Event-driven side effects. Milestone releases, notifications, and analytics are driven by domain events rather than synchronous chains, so an external outage degrades gracefully.
  • Manual fallback for every integration. Visa, travel and payments each have an operations fallback path so a provider outage never blocks a patient.

1.2 Component architecture (front-end)

The front-end is organised by surface, with a shared design system and a single data and help layer.

LayerLocationResponsibility
Atoms (design system)components/ui/Icon, Button, Card, Badge, Avatar, Progress, SectionLabel, Toast, InfoTip. Mostly presentational.
Public sitecomponents/site/SiteHeader, SiteFooter, page heroes, and explorers (Treatments, Pricing, Reviews).
Marketplacecomponents/marketplace/ClinicCard, ClinicExplorer, CompareTable, MatchWizard.
Authcomponents/auth/AuthShell, RequireAuth, RoleToggle, verify forms.
Patient portalcomponents/portal/PortalProvider (state), PortalShell, Sidebar, Topbar, NotifPanel, StageDrawer, nav.ts.
Portal viewscomponents/views/One component per portal screen (JourneyView, CareView, VisaView, DocsView, PayView, TravelView, MessagesView, etc.).
Clinic consolecomponents/clinic/ClinicProvider, ClinicShell, sidebar and topbar, and one view per clinic screen.
Help systemcomponents/help/HelpProvider, HelpPanel, Walkthrough, registry.ts, and the content/* source of truth.
Docs sitecomponents/docs/, app/docs/The published documentation route, navigation and search.
Data and configlib/schema.ts (types), data.ts (access seam), auth.tsx (mock auth), tokens.ts (design tokens).

Routing uses the Next.js App Router. Public pages share SiteHeader; auth pages share AuthShell; the patient app is wrapped by PortalShell; the clinic app by ClinicShell. The portal and clinic providers persist across navigation because their layout never remounts; HelpProvider sits at the root for the same reason. Design tokens live in app/globals.css (mirrored in lib/tokens.ts); changing a token updates the whole app.

flowchart TD
  ROOT[app/layout.tsx] --> AUTHP[AuthProvider]
  AUTHP --> HELPP[HelpProvider]
  HELPP --> SURFACES{Surface}
  SURFACES --> SITEL[Public pages + SiteHeader/Footer]
  SURFACES --> AUTHL[AuthShell]
  SURFACES --> PORTL[PortalShell + PortalProvider]
  SURFACES --> CLINL[ClinicShell + ClinicProvider]
  PORTL --> PV[Portal views read lib/data.ts]
  CLINL --> CV[Clinic views read lib/data.ts]

1.3 Deployment architecture

The app builds to static output and ships to S3 behind CloudFront, provisioned with AWS CDK (Python). One CDK file per resource keeps each concern isolated.

flowchart TD
  R53[Route 53: mock.globalclinic.app A/AAAA] --> CF[CloudFront distribution]
  CF -->|Origin Access Control, HTTPS| S3[(Private S3 bucket gc-mocks-account-region)]
  CF --> FN[CloudFront Function: URL rewrite to index.html]
  ACM[ACM cert in us-east-1] --- CF
  BUILD[next build -> out/] --> DEPLOY[CDK BucketDeployment]
  DEPLOY --> S3
  DEPLOY --> INVAL[CloudFront invalidation /*]

Key points:

  • output: "export" emits a fully static site into out/ with trailingSlash: true, so each route exports as route/index.html. A CloudFront Function appends index.html to directory-style and extensionless URLs, with a fallback to /index.html for client-side routes.
  • cdk deploy runs next build itself, uploads out/ to a private S3 bucket via Origin Access Control, and issues a CloudFront invalidation, so visitors always get the latest build.
  • The ACM certificate is in us-east-1 (required by CloudFront). The bucket name is derived as gc-mocks-<account>-<region_without_dashes>.
  • The bucket is private; only CloudFront can read it. The bucket uses a destroy removal policy because its contents are reproducible from next build (switch to retain for a long-lived bucket).

For production, the static front-end deployment is unchanged; the API, database and services deploy as separate stacks (containers or serverless), and the front-end is configured with an API base URL.

1.4 Multi-tenant architecture

The product is multi-sided (patients, clinics, agents) and multi-corridor. Tenancy is modelled along two axes: the clinic tenant (a partner organisation and its users, cases, pricing and reviews) and the case tenant boundary (a patient case and the staff assigned to it). The current build has a single hard-coded patient and a single clinic; production must isolate them.

flowchart TD
  subgraph TenantA[Clinic tenant A]
    A1[Clinic users] --> A2[Own cases / inquiries / pricing / team]
  end
  subgraph TenantB[Clinic tenant B]
    B1[Clinic users] --> B2[Own cases / inquiries / pricing / team]
  end
  subgraph Patients
    P1[Patient: own case only]
  end
  RBAC[AuthZ: tenant + case scoping] --> A2
  RBAC --> B2
  RBAC --> P1
  CORRIDOR[Country Pack config per corridor] --> CASES[(Cases carry corridor + dataRegime + riskTier)]

Isolation requirements:

  • Row-level tenant scoping. Every tenant-owned row carries a tenant key (clinic id) and, for case data, a case id. All queries are scoped by the caller's tenant and assigned cases. Deny by default.
  • Patient isolation. A patient can read and act only on their own case.
  • Clinic isolation. A clinic sees only its own clinic, inquiries, cases, pricing, reviews and team.
  • Agent isolation. An agent sees only its own attributed referrals.
  • Staff case-scoping. Coordinator, specialist, visa, travel and finance roles see only assigned cases.
  • Data residency per corridor. A case carries its corridor dataRegime; storage and processing honour residency constraints encoded in the Country Pack.

The recommended database approach is a single PostgreSQL cluster with row-level security (a tenant id and case id on every relevant table, enforced by policies), which balances isolation with operational simplicity. Strong-isolation tenants (if required by a corridor's data-residency rules) can be placed in a separate schema or database.

1.5 Security architecture

Security is layered from the edge to the data.

flowchart TD
  U[User] -->|TLS| CF[CloudFront + WAF]
  CF --> GW[API Gateway: authN, rate limiting]
  GW --> AZ[AuthZ: RBAC + tenant/case scoping]
  AZ --> SVC[Domain services]
  SVC --> ENC[(Encrypted Postgres + object storage)]
  SVC --> AUD[(Append-only audit log)]
  SEC[Secrets manager] --- SVC
  SIEM[Security monitoring] --- AUD

Layers:

  • Edge. TLS everywhere, a web application firewall, and DDoS protection at CloudFront.
  • Gateway. Authentication, request validation, and rate limiting before any domain logic runs.
  • Authorization. Role-based access control plus tenant and case scoping, deny by default, enforced server-side on every request.
  • Data. Encryption in transit and at rest; field-level encryption for the most sensitive PII; encrypted object storage for documents.
  • Secrets. No secrets in source or in the static bundle; all secrets in a managed secrets store, rotated.
  • Audit. An append-only audit log for every clinical, financial, consent and visa action, with actor, timestamp and before and after state.
  • Monitoring. Security events flow to monitoring with alerting on anomalies (failed auth spikes, escrow or visa failures, screening hits).

The full model, including the RBAC matrix, encryption requirements, secret management, PII handling and secure API design standards, is in Security Documentation.