Skip to content

Infrastructure

All infrastructure is provisioned with Terraform from terraform/environments/production/, composed of seven reusable modules. The remote state lives in S3 (appointment-system-tfstate) with DynamoDB locking (terraform-locks). Terraform version: 1.9.8; AWS provider: ~> 5.0.


Network Topology

Network Topology

VPC Layout

  • 3 Availability Zones, 9 subnets total (3 per AZ tier)
  • CIDR blocks carved from the VPC CIDR using /4 increments, allocated by the networking module via cidrsubnet
  • VPC endpoints for S3, ECR, and CloudWatch — traffic to these services stays on the AWS backbone
Tier Subnets Contents
Public (3) One per AZ ALB, NAT Gateways (one per AZ for AZ-local egress), Internet Gateway
Private (3) One per AZ EKS worker nodes, ElastiCache, OpenSearch, MSK brokers
Database (3) One per AZ RDS Aurora clusters only; route through private NAT

Compute — Amazon EKS

Terraform module: terraform/modules/eks/

All six services run as Kubernetes Deployments on EKS with managed node groups.

Node Group Instance Taint Workloads
general m6i.xlarge None Booking, Availability, Patient, Practitioner, Notification
search r6i.xlarge workload=search:NoSchedule Search Service only

The search node group uses memory-optimised instances because the Search Service holds large OpenSearch client caches. The NoSchedule taint prevents general workloads from landing there; the Search Service values-search.yaml adds the matching toleration and nodeSelector.

EKS control plane logging is enabled for all log types: api, audit, authenticator, controllerManager, scheduler.

An OIDC provider is provisioned alongside the cluster to support IRSA. Each service's ServiceAccount is annotated with its dedicated IAM role ARN, granting least-privilege AWS API access without node-level credentials.


Database — Amazon RDS Aurora PostgreSQL

Terraform module: terraform/modules/rds/

Three independent Aurora clusters, one per domain. The Availability Service shares the practitioner cluster for its schedule/exception data.

Cluster Writer Reader Replicas Tables
booking db.r6g.xlarge 1 bookings
practitioner db.r6g.large 1 practitioners, schedules, exceptions
patient db.r6g.large 1 patients

Common configuration across all clusters:

  • Aurora PostgreSQL engine
  • Storage encryption enabled
  • Deletion protection enabled
  • Automated backups — 7-day retention, daily backup window 03:00–04:00 UTC
  • Master credentials managed by AWS Secrets Manager with automatic rotation
  • Tables partitioned by country_code for multi-country isolation

Cache — Amazon ElastiCache (Redis)

Terraform module: terraform/modules/elasticache/

Setting Value
Mode Cluster mode enabled
Shards 3
Replicas per shard 2
Instance type cache.r6g.xlarge
Failover Multi-AZ with automatic failover
Encryption At rest and in transit
Snapshot retention 3 days (daily window 04:00–05:00 UTC)

Use cases:

  • Availability bitmaps — 24-bit integer per practitioner per day (7M keys ≈ 2–4 GB)
  • Search result caching — TTL 30–60 seconds
  • Booking slot pre-checks — reduces RDS contention under load

Search — Amazon OpenSearch

Terraform module: terraform/modules/opensearch/

Setting Value
Data nodes 3 × r6g.xlarge.search with 100 GB EBS each
Master nodes Dedicated (managed by AWS)
Indices Per-country (practitioners_fr, practitioners_de, …)
Access control Fine-grained; EKS pods authenticate via SigV4 through IRSA
Ingestion Kafka consumer (availability-events, practitioner-events)

Replica shards on each index allow read scaling without a separate replica cluster. If a data node is lost, replica shards are promoted and the cluster self-heals.


Event Bus — Amazon MSK (Managed Kafka)

Terraform module: terraform/modules/msk/

Setting Value
Brokers 3 × kafka.m5.xlarge across 3 AZs
Replication factor 3
Min in-sync replicas 2
Partitions per topic 6 (default)
Partitioning key practitioner_id
Retention 7 days / 168 hours
Encryption TLS client-to-broker and in-cluster
Auto topic creation Disabled — topics provisioned explicitly via Terraform
Broker logs Shipped to CloudWatch (/aws/msk/{project}, 14-day retention)

Topics: booking-events, practitioner-events, availability-events


Notifications — SES + SNS

Terraform module: terraform/modules/notifications/

  • Amazon SES — transactional email (confirmations, reminders, cancellations). Domain identity configured and verified via Terraform.
  • Amazon SNS — SMS and mobile push notifications.

The Notification Service is the sole producer to SES and SNS. It has an IRSA role scoped to only the ses:SendEmail and sns:Publish actions.


Tagging Strategy

All resources receive the following default tags via the AWS provider default_tags block:

Tag Value
Project appointment-system (from var.project)
Environment production
ManagedBy terraform