Skip to content

Deployment Overview (platform-wide)

How the Someli platform is built and deployed across dev → UAT → production, spanning all repos. The single most important thing to understand:

There are two deploy targets, split by environment. dev_* branches deploy to Lightsail/EC2 (SSH + PM2). uat_* and production deploy to ECS (Docker image → ECR → ECS service). They are different platforms with different tooling.

The per-repo mechanics live in each repo's build-and-deploy.md (or someli-api/deployment.md for the largest service). This page is the cross-cutting map they all point back to.


1. AWS coordinates (shared by every repo)

Value
Account 255061853867
Region us-west-2
ECR registry 255061853867.dkr.ecr.us-west-2.amazonaws.com

ECR repositories — one per environment

ECR repo Environment Notes
dev_crons Development Dev cron/worker images
uat UAT / testing Multi-purpose — holds the someli-platform frontend image (tags uapp-<sha>) and the someli-api image (tag uapi)
live_crons Production Production cron/worker fleet images
designers (designer side) designer-api service image (tag dapi) — separate from the crons repos
designers-crons (designer side) Designer cron/worker fleet images

⚠️ Hyphen-vs-underscore footgun. The production ECR repo is live_crons (underscore) but the production ECS cluster is live-crons (hyphen). They are different identifiers for related things — don't assume one spelling works for the other.

ECS clusters

Cluster Environment Services
UAT UAT uapp (someli-platform frontend) — see Path B
live-crons Production 9 domain services (below)

Production cluster live-crons — 9 services

The production worker/cron fleet is partitioned into 9 ECS services by functional domain:

AI_CONTENT, Billing-Payments, Carousel, Content_Media, Dynamic_Post, Post_Schedule, Rag, Social_Media_Connection, User_Specific_Content.

One image, many services — but far more jobs than services. someli-api has 100+ job_*.js scripts (see someli-api/jobs-inventory.md); they are grouped into these 9 services by domain, so each service runs many jobs — there is no 1:1 job↔service mapping. Each service pulls the same ECR image and overrides the container CMD/args to select which scripts it runs. The exact job→service assignment lives in the ECS task definitions in AWS — not committed in any repo — and is too large to enumerate here. This mirrors the Dockerfile comment "Default command — override with specific job script using docker run args."


2. The two deploy paths

                ┌─────────────────────────────────────────────┐
  dev_* branch  │  Lightsail / EC2   +  PM2   (SSH or SSM)     │
  ───────────►  │  someli-api/dev-api-deploy.yml  (SSH+PM2)    │
                │  someli-platform/dev_app.yml    (SSM)        │
                └─────────────────────────────────────────────┘

                ┌─────────────────────────────────────────────┐
  uat_* branch  │  ECS UAT  (cluster: UAT)                     │
  ───────────►  │  docker build → ECR `uat` → ECS service uapp │
                │  someli-platform/uat_app_ecs.yml  (GH Action)│
                └─────────────────────────────────────────────┘

                ┌─────────────────────────────────────────────┐
  production    │  ECS PROD (cluster: live-crons, 9 services)  │
  (manual)      │  docker build → ECR `live_crons` → 9 services│
  ───────────►  │  MANUAL — no committed workflow              │
                └─────────────────────────────────────────────┘

Path A — dev → Lightsail/EC2 (SSH/SSM + PM2)

Committed in: - someli-api/.github/workflows/dev-api-deploy.yml — push to dev_api, SSH to the Lightsail host, git pull + pm2 reload. OIDC is not used here — relies on LIGHTSAIL_* SSH secrets. (Also a legacy Jenkinsfile targets the same branch — see someli-api/deployment.md §6.1.) - someli-platform/.github/workflows/dev_app.yml — "Deploy to Lightsail", push to dev_app, deploy via SSM. OIDC role arn:aws:iam::255061853867:role/GitHubActionsLightsailRole.

Path B — UAT → ECS (automated, frontend)

someli-platform/.github/workflows/uat_app_ecs.ymlname: Deploy to ECS UAT, push to uat_app. This is the only fully-automated ECS pipeline committed anywhere:

  1. OIDC auth — arn:aws:iam::255061853867:role/GitHubActionsECSRole
  2. aws-actions/amazon-ecr-login@v2
  3. docker builddocker push $ECR_REGISTRY/uat:uapp-<sha>
  4. aws-actions/amazon-ecs-render-task-definition@v1 (container uapp)
  5. aws-actions/amazon-ecs-deploy-task-definition@v2 → cluster UAT, service uapp, then waits for service stability
  6. Teams/Slack deployment summary

Config (env block): AWS_REGION=us-west-2, ECR_REPOSITORY=uat, ECS_CLUSTER=UAT, ECS_SERVICE=uapp, ECS_TASK_DEFINITION=uapp, CONTAINER_NAME=uapp.

Path C — production → ECS (manual)

Production deploys to the live-crons cluster (9 services, ECR repo live_crons) are manual — there is no committed production workflow in any repo. The image-build helpers that exist:

  • someli-api/push.shpython deploy_image.py --image-tag uapi --repository-uri …/uat … (currently points at the uat repo; the prod equivalent targets live_crons)
  • designer-api/push.shpython deploy_image.py --image-tag dapi --repository-uri …/designers …
  • deploy_image.py authenticates to ECR via boto3, runs docker build, tags, and pushes.

After the image is pushed, each of the 9 ECS services must be updated to the new image (in the AWS Console or via CLI). Verify with ops the exact prod release runbook — the repos only contain the image-build half.

UAT may also be triggered automatically via GitHub Actions (the committed uat_app_ecs.yml covers the frontend); the cron/worker side of UAT and all of production are manual today.


3. Per-repo summary

Repo Dockerfile Dev deploy UAT/Prod deploy Detail doc
someli-api ✅ (no install step — see caveat) GH Actions → Lightsail (SSH+PM2) push.sh → ECR uat/live_crons → ECS (manual) deployment.md
someli-platform ✅ (artifacts pre-built, node_modules from EFS) GH Actions → Lightsail (SSM) GH Actions → ECS UAT (uapp), prod manual (in deployment.md + this page)
designer-api ✅ (multi-stage; .env baked in ⚠️) none in repo push.sh → ECR designers / designers-crons (manual) build-and-deploy.md
Someli-Designer ✅ (artifacts pre-built, node_modules from EFS) none in repo image build opaque (manual) build-and-deploy.md
Someli-admin-api ❌ none none in repo not containerised build-and-deploy.md
admin_console_R ❌ none none in repo not containerised build-and-deploy.md
someli-dashboard-be ❌ none none in repo runs in-process inside someli-api in prod build-and-deploy.md

The three repos with no Dockerfile (Someli-admin-api, admin_console_R, someli-dashboard-be) are not part of the ECR/ECS flow — they deploy by other means (or, for the dashboard, run inside someli-api).


4. Cross-cutting risks

  1. Production is manual, no committed runbook. The 9 live-crons services are updated by hand after a manual push.sh. No automated rollback, no audit trail, no health-gating. This is the highest-priority deployment gap.
  2. No image versioning on the manual path. push.sh tags :uapi/:dapi (overwritten each push). Only the automated uat_app_ecs.yml path uses a git-SHA tag (uapp-<sha>). Adopt SHA tags on the manual paths so prod rollback is well-defined.
  3. live_crons (repo) vs live-crons (cluster) naming mismatch invites copy-paste errors in scripts and IAM policies.
  4. someli-api Dockerfile has no yarn install — relies on node_modules present in the build context, producing non-reproducible images. designer-api's multi-stage Dockerfile does it correctly; align them. See someli-api/deployment.md §6.3.
  5. designer-api/Dockerfile bakes .env into the image — anyone with ECR pull access to designers reads all secrets. See designer-api/build-and-deploy.md D-1 and the repo's security.md.
  6. Two CI systems on someli-api's dev branch (Jenkins + GH Actions). Retire one.