GPLink Platform Infrastructure

GPLink Phase 1 · SOW-B

Platform infrastructure

The server architecture behind the integration layer between the clinical side, the commerce side and the payer — drawn as trust boundaries rather than as a vendor's product catalogue.

4 compute units4 data stores3 environments1 correlation idap-southeast-5 · 3 AZ

The architecture as it is specified and costed — capability by capability, with no provider named. This is the version the quotation is written against.

The same architecture as it would be built on AWS in the Malaysia region. Nothing in the design changes; only the names of the managed services behind each box.

Production topology

Three vendor systems, one platform, four stores. The heavy line around the middle is a trust boundary, not a network diagram convenience — what crosses it is enumerated, and what does not cross it is the point.

Click Interactive to walk the diagram: five guided views, presenter mode, PNG and SVG export.

CLINICAL · FEV3R Clinical system Consultation · EMR Prescribing & signature Clinician identity, MMC-bound H1 · H2 · H3 Stock & price · prescription payload · fulfilment events mTLS PAYER · MEDILINK Not connected Conditional scope · no credentials GPLINK PLATFORM · TRUST BOUNDARY AWS ap-southeast-5 · KUALA LUMPUR · 3 AZ Load balancer · CDN · WAF CloudFront · AWS WAF · Application Load Balancer COMPUTE — 4 APP INSTANCES API gateway Service auth, rate limits, idempotency ECS Fargate Orchestrator Cross-vendor saga, money split, ledger ECS Fargate Identity Three-way mapping, session handoff ECS · Cognito Master data Drug ↔ SKU, Rx guardrail, code lists ECS Fargate DATA STORES PostgreSQL Orders, ledger, mappings, audit RDS PostgreSQL Redis Idempotency keys, sessions ElastiCache Event bus Handoff events, dead letters MSK or SQS Object store Audit archive, payout files Amazon S3 Secrets manager & KMS One secret per integration, per environment Observability Logs, traces, metrics · one correlation id Secrets ManagerAWS KMSCloudWatch Logs, metrics & alarms ADR-004 No clinical data at rest. The platform holds a reference, never the record. Every box above is a costed line: 4 app instances at 2 vCPU / 4 GB, 1 database, 1 cache node, 1 broker, 1 bucket. No cloud provider is named — data residency is undecided, and it changes the provider list. One VPC per environment, private subnets across three Availability Zones. No public address in the platform or data tier. COMMERCE · PRIME Commerce platform Catalogue · pricing · stock Orders & fulfilment Pharmacy portal SOW-A SCOPE Own infrastructure, own staff directory OAuth2 client credentials EXTERNAL SERVICES — OUTSIDE THE PLATFORM BOUNDARY Payment gateway FPX · card · refunds Courier Delivery & tracking Messaging SMS · WhatsApp · email Identity provider Not selected — see below
Pricing and stock are synchronous; fulfilment is event-driven — a pharmacy counter must never block a basket (ADR-001). Every cross-vendor action carries one correlation id, generated at the clinical boundary (ADR-011). One VPC per environment, private subnets across three Availability Zones, and no public address below the load balancer.
Guided views, Present mode and PNG/SVG export live in this version. Same topology, drawn from a typed specification and validated against nine composition checks. Open full screen ↗

ap-southeast-5 — ASIA PACIFIC (MALAYSIA)

An in-country region with three Availability Zones, generally available since August 2024. Around 150 AWS services run in-region, including every managed service this architecture depends on.

Request path

What the topology does, rather than what it contains. One money-bearing call — dispense.partial — from the vendor's network to a durable row, then the asynchronous half that cannot change the answer the vendor already has.

Click Interactive to walk the diagram: five guided views, presenter mode, PNG and SVG export.

PRIME COMMERCE POST /v1/commerce/events dispense.partial v1.2 OAuth2 client credentials GPLINK PLATFORM · AWS ap-southeast-5 SYNCHRONOUS · THE VENDOR IS WAITING EDGE AWS WAF ALB 403 blocked · 429 rate 503 no healthy target API GATEWAY TASK · FIVE GUARDS, IN ORDER credential 401 partner state 403 quota 429 schema 400 idempotency 409 mTLS · OAuth2 · HMAC | IP allow-list + lifecycle Live | Zod schema from @gplink/contracts 409 = same key, different body — nothing is processed DURABLE WRITE RDS PostgreSQL event_record stored BEFORE any rule runs ASYNCHRONOUS · AFTER 202 ACCEPTED · NOTHING HERE CHANGES THE RESPONSE SQS FIFO group = episode Orchestrator saga · compensation Ledger double entry Outbound adapter through the gateway DLQ + replay operator, audited 1 2 4 5 6 7 8 9 10 3
Steps 1–5 happen while the vendor waits. Steps 6–10 happen afterwards and cannot change the 202 already returned. The five chips inside the gateway are the guards, each with the status code it answers with.
1

A partner calls

Prime Commerce presents OAuth2 client credentials; FEV3R presents mTLS; the payment gateway an API key + HMAC. No shared secret spans two vendors.

2

The edge filters before anything is understood

Managed rule sets and a rate rule per partner, then TLS termination and a healthy target. Idle timeout is set above the slowest vendor call, so a slow partner never reads as a 504.

3

Five guards, in this order

Each returns its own status code, shown on the chips. The 409 is the one that matters: same idempotency key, different body — nothing is processed, because handling that politely is how a pharmacy gets paid twice.

4

The envelope is written before any rule runs

This is the decision the design rests on. It is why replay comes from PostgreSQL rather than a queue with a retention window, and why a partner's retry storm is cheap instead of dangerous.

5

202 Accepted

Accepted means stored, not processed. Nothing downstream can make this response wrong — which is the whole reason the write comes first.

6

Handed to the queue

MessageGroupId = episode_id: strict order inside one episode, parallel across episodes. The guarantee is a queue attribute, not a convention a developer has to remember.

7

The saga runs

Step committed, compensation armed, split rules applied. This is the only service allowed to write money.

8

The ledger is posted

Double entry, both sides, one episode id. If the ledger and the rule engine disagree, settlement halts — it does not warn and continue.

9

Back out through the gateway

Outbound calls to FEV3R, commerce or the courier carry their own idempotency key and their own retry budget.

10

Dead letter and replay

On exhausted retries: full envelope, attempt history, and a replay a named operator presses. The replay is itself an audited action with its own event.

Guided views, Present mode and PNG/SVG export live in this version. Open full screen ↗

What each unit is

Sizing comes from the quotation's infrastructure sheet, where every line carries a unit price and a quantity. Change the quantity, not the total.

Sizing comes from the quotation's infrastructure sheet, where every line carries a unit price and a quantity. The right-hand column is the AWS service each line resolves to and the configuration it runs at — the sizing is unchanged by it.

ComponentOne unit isMVPSizing basisOn AWS · configuration
ComputeApp instance, 2 vCPU / 4 GB, container runtime4Gateway, orchestrator, identity, master dataAmazon ECS on FargateAmazon ECR

4 tasks · rolling deployment with circuit-breaker rollback · images immutable, scanned on push · no host to patch

Managed PostgreSQL2 vCPU / 8 GB + 200 GB storage + backup1One primary with daily backup; a read replica at FULLAmazon RDS for PostgreSQL 16

Multi-AZ · 200 GB gp3 · point-in-time recovery · no UPDATE grant on the ledger table

RedisCache node, 2 GB1Idempotency keys, sessions, hot inventory cacheAmazon ElastiCache for Redis 7

One node, shared across tasks so a deploy never loses a key · keys expire on a fixed window, longer than any partner retry cycle

Message broker
allowance
Managed queue or stream, ~10M messages a month. Held as an allowance, not a metered pass-through — it covers the upgrade to a streaming cluster should volume require it.1One message per handoff eventAmazon SQS FIFOAmazon MSK — upgrade path

MessageGroupId = episode_id · 5-minute deduplication · dead-letter queue. SQS FIFO is what MVP is built on; MSK stays behind the same internal port as the upgrade path if cross-company volume ever justifies a cluster.

Object storage500 GB stored plus egress1Audit archive, payout files, onboarding documentsAmazon S3

Versioning on · Object Lock on the audit prefix · lifecycle to Glacier

Observability25 GB ingested a month, 30-day retention250 GB at 30 days; 125 GB at 90 days for traces at FULLAmazon CloudWatch

OpenTelemetry writes here, so the backend can change without touching application code

Load balancer, CDN, WAFLB + 200 GB CDN + WAF rule set1Sized on page and API trafficALBCloudFrontAWS WAF

HTTPS only · idle timeout above the slowest vendor call · managed rules plus per-partner rate rules

Secrets manager & KMS50 secrets + 5 encryption keys1One secret per integration, per environmentAWS Secrets ManagerAWS KMS

Injected at task start, never in an image or repository · key policy separate from the application role · expiry alerts before it expires

Backup, snapshots, DR500 GB snapshot storage1A warm standby in a second zone at FULLAWS Backup

Cross-AZ snapshots

Three environments

Production is not a special snowflake built by hand. It is the same infrastructure template with different inputs — which is the only reason a cutover rehearsal means anything, and why the build-phase figure is a fraction of the run rate.

Production

100%

Live traffic, switched on at cutover. Its own account, its own VPC, Multi-AZ database. No credential is shared with a lower environment.

Staging / UAT

40%

The shared three-vendor sandbox. Same services, smaller instance classes, single-AZ database.

Development / CI

20%

Ephemeral. Torn down and rebuilt from the same template. The FEV3R mock and contract tests live here, so one team never waits on another.

Security

Three lifecycles in one picture: a secret reaching a running process, a partner credential being enforced on every call, and what actually happens in the hour a credential leaks.

Click Interactive to walk the diagram: five guided views, presenter mode, PNG and SVG export.

THIRD PARTIES FEV3R clinical Prime Commerce orders · pharmacy Payment gateway FPX · card DELIVERY PIPELINE GitHub Actions Terraform secret name and policy only GPLINK PLATFORM · AWS ap-southeast-5 · 3 AVAILABILITY ZONES EDGE AWS WAF managed + rate ALB TLS · health the only public address APPLICATION TIER · ECS ON FARGATE · PRIVATE SUBNETS Gateway Identity Master data Orchestrator credential · IP allow-list · scope · quota · schema · idempotency no public address · egress through NAT SECRETS & KEYS Secrets Manager 50 secrets AWS KMS 5 CMKs one integration, one environment DATA & EVIDENCE RDS PostgreSQL event_record SQS · DLQ preserved S3 · Object Lock audit archive nothing is dropped during containment OBSERVABILITY CloudWatch logs · metrics every decision logged secrets redacted by the logger, every line ALARMS allow-list miss rate anomaly credential expiry dead-letter depth 1 2 3 4 5 6 7 8 9 10
Steps 1–2 are a partner arriving; 3–4 are a secret reaching a process; 5–6 are the record being made; 7–10 are containment and repair. The delivery pipeline sits outside the platform boundary on purpose — a secret travels in, its value never travels back out.
1

A partner calls

Each vendor's own credential type. No shared secret spans two vendors, so a compromise at one company cannot be replayed at another.

2

The edge filters first

Managed rule sets plus a rate rule per partner — a coarse net before the gateway's precise one.

3

Terraform declares the secret

Its name, scope and key policy are reviewed like code. The value never enters the repository, the image or a CI variable.

4

The secret reaches one task, at boot

Encrypted under a customer-managed key whose policy is separate from the application role. The task definition carries the ARN; only the running task sees the value, and the logger redacts it.

5

The envelope is stored first

The same write as step 4 of the request path — here it is what makes a replay after containment possible weeks later.

6

Every decision is logged

Allowed or refused, with the correlation id. Secrets are redacted by the logger, not by developers remembering to.

7

An alarm suspends the partner

Allow-list miss, rate anomaly, or a credential used from two regions. The gateway refuses that credential on the next request — no deploy, no restart, no code change.

8

Held traffic is preserved

Everything the suspended partner sends is dead-lettered with its full envelope. Containment costs availability, never data.

9

Rotate, then replay

A new secret version, the task restarted, the old version disabled — then the held events replay. One secret per integration keeps the blast radius one partner wide.

10

Evidence, and an alarm on the evidence

Suspension, rotation and each replay are audit lines of their own, archived under Object Lock. Dead-letter depth is itself an alarm.

Guided views, Present mode and PNG/SVG export live in this version. Open full screen ↗

Partner lifecycle

Third parties are the largest attack surface in a three-company platform, because each one is a door somebody else holds the key to. A credential's rights come from its stage, not from its validity.

StageMay doExit condition
SandboxSandbox endpoints and scopes only. No route to production traffic.Conformance suite runnable end to end
CertificationReal contracts, sandbox traffic. The key expires on a date whether or not certification finishes.All five conformance checks pass. Not four.
LiveProduction credential and scopes, with IP allow-list and per-endpoint rate limits enforced on every call.Breach, expiry or offboarding
SuspendedNothing. Inbound events are dead-lettered, not discarded — a suspension must never lose a partner's data.Reinstatement or offboarding
OffboardedNothing. Records retained per policy; credentials revoked and keys destroyed.Terminal