Infrastructure
This is the platform infrastructure — the AWS estate and the deploy control plane that runs it. It complements two neighbouring pages: How deployment works (how a change ships) and Observability & infrastructure (the application integrations — Sentry, GA4, S3, Redis, etc.). Everything here is as-built, current as of 2026-07-22.
Everything runs in one AWS account — 907815021625, region eu-central-1 (Frankfurt).
The estate on one diagram
Section titled “The estate on one diagram”flowchart TB
subgraph GH["GitHub · OrascomDevelopment"]
REPO[App repos]:::src
GHA[GitHub Actions]:::ci
end
subgraph AWS["AWS · account 907815021625 · eu-central-1"]
OIDC{{OIDC · 3 gh-deploy roles<br/>no long-lived keys}}:::sec
CD[CodeDeploy<br/>Orascom-Prod-app · ODH-UAT · ODH-UAT-CRM<br/>ODH-Prod-Supervisor · ODH-Pdf]:::deploy
S3REV[(S3 orascom-deploy-bucket<br/>revisions)]:::store
ECR[(ECR backend-pdf-service)]:::store
SM[Secrets Manager<br/>portals/<env>/<app> · CMK]:::sec
subgraph COMPUTE["Compute — Graviton t4g behind the shared ALB + WAF"]
BEASG[Backend ASG<br/>blue/green]:::compute
CRMASG[CRM ASG<br/>blue/green]:::compute
SUP[Supervisor box<br/>queue workers · scheduler · PDF container]:::compute
AMP[Frontend · AWS Amplify]:::compute
end
RDS[(RDS MySQL · Multi-AZ)]:::data
REDIS[(Redis EC2)]:::data
MEDIA[(S3 media → CloudFront)]:::store
OBS[CloudWatch alarms · CloudTrail · GuardDuty<br/>Access Analyzer · Teams notify Lambda]:::sec
end
REPO --> GHA -->|assume via OIDC| OIDC --> CD
GHA -->|build revision| S3REV --> CD
GHA -->|buildx arm64 push| ECR --> SUP
REPO -->|autoBuild| AMP
CD -->|blue/green| BEASG & CRMASG
CD -->|in-place| SUP
BEASG & CRMASG --> RDS
BEASG --> REDIS
BEASG --> MEDIA
CD -.render env.-> SM
BEASG & CRMASG & SUP -.-> OBS
classDef src fill:#e7eef6,stroke:#2563A8,color:#0b1b2b;
classDef ci fill:#efe7f7,stroke:#7A4FB5,color:#0b1b2b;
classDef deploy fill:#dff0f0,stroke:#0C7C84,color:#0b1b2b;
classDef compute fill:#f7efdc,stroke:#B7791F,color:#0b1b2b;
classDef data fill:#eceff1,stroke:#5B6B7A,color:#0b1b2b;
classDef store fill:#eceff1,stroke:#5B6B7A,color:#0b1b2b;
classDef sec fill:#f6e7dc,stroke:#C4622D,color:#0b1b2b;Compute
Section titled “Compute”- Backend & CRM run on EC2 Auto Scaling groups (AWS Graviton
t4g) behind one shared Application Load Balancer (orascom-prod-ecommerce-lb), with AWS WAF on the prod ALB. Both are blue/green in production and UAT (CodeDeploy stands up a fresh “green” ASG, health-checks it, shifts ALB traffic, then terminates the old “blue”); staging is a single in-place box. - The supervisor box (
ODH-Supervisorin prod,ODH-UAT-Supervisorin UAT) is a stable pet, not an ASG. It runs, under supervisord: the backend queue workers (odh-queue), the Laravel scheduler (odh-schedule— its only home, so scheduled commands don’t duplicate across a scaled-out fleet), thepdf-service-queueworker, and the PDF service Docker container (see Storage & registry). Deploys to it are in-place. - Frontend = AWS Amplify (serverless static hosting), auto-building from GitHub
Orascom-Portals-Frontend. Not on the CodeDeploy rail.
- RDS MySQL, Multi-AZ (
orascom-prod-rds) — the single shared relational store for backend and CRM. Automated backups + point-in-time recovery. Database migrations run once per deploy under a fleet-safeGET_LOCKmutex on this instance. - A dedicated Redis EC2 instance (
ODH-Redis) for cache / queues / sessions where an environment routes them to Redis (the app also supports file/database drivers — see the Observability & infrastructure page).
Storage & registry
Section titled “Storage & registry”- S3 (media) → CloudFront — user/media assets, served via the CDN.
- Amazon ECR —
backend-pdf-servicenew 2026-07-21 — the private registry for the PDF service’s arm64 image. GitHub Actions cross-builds the image (buildx --platform linux/arm64) and pushes it here; the supervisor box pulls it during a PDF deploy. Lifecycle policy expires untagged images after 14 days. - S3 —
orascom-deploy-bucket— holds the CodeDeploy revisions (self-contained deploy artifacts), env-prefixed (staging/,uat/,prod/).
Config & secrets
Section titled “Config & secrets”Deploy control plane
Section titled “Deploy control plane”-
GitHub Actions builds every deploy; AWS CodeDeploy rolls it out. No long-lived AWS keys exist in GitHub — Actions assumes one of three OIDC roles (
gh-deploy-staging/gh-deploy-uat/gh-deploy-prod), each trust-bound to the exactrepo:…:environment:<env>claim of the deploying repo. -
CodeDeploy applications:
App Groups Style Runs Orascom-Prod-apporascom-backend-deploy-group,orascom-crm-deploy-groupblue/green prod backend + CRM ODH-Prod-Supervisorprodin-place prod queue workers/scheduler ODH-UATbackend + supervisor groups blue/green + in-place UAT backend + workers ODH-UAT-CRMuatin-place UAT CRM ODH-Pdfnew 2026-07-21uat,prodin-place PDF service container swap ODH-Staging-Backend/ODH-Staging-CRMstagingin-place staging box -
The PDF service has its own rail: push →
buildxarm64 → ECR →ODH-Pdfin-place → a fail-safe container swap (build-and-smoke-test the new container, then swap — a bad image leaves the old one running). Full detail on How deployment works.
Observability & audit
Section titled “Observability & audit”- CloudWatch alarms — for both prod target groups: ALB 5xx and unhealthy-host count
(
prod-backend-ALB-*+prod-crm-ALB-*), plus backend CPU / memory (7 alarms today). A 5xx or unhealthy-host spike during a deploy drives auto-rollback, and they page one channel. Broader coverage from the planned floor — RDS storage/CPU/connections and queue-depth / failed-jobs custom metrics — is a follow-up, not yet stood up. - CloudTrail (
odh-account-trail, multi-region, own encrypted bucket), GuardDuty, and IAM Access Analyzer (odh-analyzer) — the account-level audit/threat-detection floor, stood up before the Robusta handover. - Deploy notifications — every deploy posts a status card (✅ / ❌) to the “Orascom Portals
Deployments” Microsoft Teams channel: backend & CRM (a notify step in GitHub Actions), frontend
(an EventBridge rule on Amplify build events → the
portals-amplify-teams-notifyLambda), the docs site (a GitHub Actionscheck_runworkflow on the Cloudflare Pages build), and the PDF service (its own workflow). All share one card format and theportals/shared/notify-webhooksecret. - Application error tracking/analytics (Sentry, GA4) is documented on the Observability & infrastructure page.
DNS & certificates
Section titled “DNS & certificates”- Root
orascomdh.comis on Orascom IT’s Cloudflare;my.orascomdh.comis delegated to a Route53 zone. Moving that zone into this account (a one-time NS delegation flip by IT) is the one remaining DNS task — bounded by themedia.my.orascomdh.comACM cert expiry (2026-10-29). See the handoff tracker for status. - ACM provides the TLS certs for the
*.my.orascomdh.comfamily (ALB + CloudFront).
What’s retired / being decommissioned
Section titled “What’s retired / being decommissioned”- GitLab (CI + runners) — fully retired, zero runtime role.
- AWS CodePipeline (3 pipelines) — disconnected, kept as a short-term rollback lever, then delete.
- DigitalOcean staging +
*.robustastudio.comhosts — slated for retirement once DNS + external callback re-registrations complete (tracked separately). - Robusta-hosted tooling (SonarQube, Dependency-Track, self-hosted Sentry, Grafana, Mattermost) — replaced by GitHub-native quality gates + CloudWatch + Orascom’s own Sentry as the handover completes.
