Skip to content

Multi-Country Expansion

The platform is designed so that launching a new country requires no code changes — only configuration, an OpenSearch index, a database partition, and practitioner onboarding.

Multi-Country Architecture Diagram

Multi-Country Expansion

The diagram shows which resources are shared across countries and which are isolated per country, along with the GDPR regional deployment strategy.


Shared vs. Per-Country Resources

Resource Shared Per-Country
EKS cluster All services
RDS clusters Cluster infra country_code partition
ElastiCache All caches Keyspace prefix by country
MSK (Kafka) All topics Topic partitioned by practitioner_id (includes country)
OpenSearch Cluster infra One index per country (practitioners_{cc})
API Gateway Base config Path prefix per country (/{cc}/v1/…)

New Country Launch Checklist

Launching a new country involves five steps, all achievable without a service deployment:

Add the country to the platform config: timezone, locale, regulatory fields, and feature flags.

{
  "country_code": "es",
  "timezone": "Europe/Madrid",
  "locale": "es-ES",
  "regulatory_fields": ["colegiado_number"],
  "features": {
    "online_payments": true,
    "video_consult": false
  }
}

Create the per-country index with country-specific field mappings:

PUT /practitioners_es
{
  "mappings": {
    "properties": {
      "location":         { "type": "geo_point" },
      "specialty":        { "type": "keyword" },
      "next_available_slot": { "type": "date" },
      "colegiado_number": { "type": "keyword" }
    }
  }
}

Add a partition to the practitioners and bookings tables for the new country_code:

ALTER TABLE practitioners
  ADD PARTITION (PARTITION p_es VALUES IN ('es'));

ALTER TABLE bookings
  ADD PARTITION (PARTITION p_es VALUES IN ('es'));

Bulk import practitioner profiles via the Practitioner Service API, or enable self-service registration. The import triggers practitioner-events Kafka events which the Search Service consumes to populate the new OpenSearch index.

Enable the country in the API Gateway routing table. Country is passed as a path prefix:

https://api.appointment-system.io/es/v1/search
https://api.appointment-system.io/es/v1/bookings

GDPR and Data Residency

For markets requiring strict data residency (e.g., Germany, France under national GDPR implementations), the platform supports isolated regional stacks.

When to use a regional stack

A regional stack is only needed when data must not leave a specific AWS region. For countries that can share the eu-west-1 region, the shared-cluster approach with country_code partitioning is sufficient.

A regional stack reuses the same seven Terraform modules with region-specific variables:

# terraform/environments/production-de/main.tf
provider "aws" {
  region = "eu-central-1"   # Frankfurt
}

module "networking" {
  source   = "../../modules/networking"
  project  = "appointment-system-de"
  vpc_cidr = "10.1.0.0/16"
}
# ... same modules, different region + CIDR

What is isolated per regional stack:

  • VPC and all subnets
  • RDS clusters (patient data never leaves the region)
  • ElastiCache cluster
  • MSK cluster
  • OpenSearch domain

What remains shared (non-personal data, no residency requirement):

  • ECR image repositories
  • GitHub Actions runners
  • Terraform state bucket (can be cross-region replicated for DR)