Deployment
Docker
API Image
# apps/api/Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile
COPY . .
RUN pnpm build --filter api
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/apps/api/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3001
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s \
CMD wget -qO- http://localhost:3001/health || exit 1
CMD ["node", "dist/main.js"]
ECS Fargate Task Definition
{
"family": "syncad-api",
"cpu": "512",
"memory": "1024",
"containerDefinitions": [{
"name": "api",
"image": "<ECR_IMAGE>",
"portMappings": [{ "containerPort": 3001 }],
"environment": [
{ "name": "NODE_ENV", "value": "production" }
],
"secrets": [
{ "name": "DATABASE_URL", "valueFrom": "arn:aws:secretsmanager:...:DATABASE_URL" },
{ "name": "JWT_SECRET", "valueFrom": "arn:aws:secretsmanager:...:JWT_SECRET" }
],
"logConfiguration": {
"logDriver": "awslogs",
"options": { "awslogs-group": "/ecs/syncad-api", "awslogs-region": "ap-south-1" }
}
}]
}
GitHub Actions — Deploy API
# .github/workflows/deploy-api.yml
name: Deploy API
on:
push:
branches: [main, dev]
paths: ['apps/api/**']
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
with: { version: 8 }
- uses: actions/setup-node@v4
with: { node-version: 20, cache: pnpm }
- run: pnpm install --frozen-lockfile
- run: pnpm test --filter api
- name: Build and push Docker image
run: |
aws ecr get-login-password --region ap-south-1 | \
docker login --username AWS --password-stdin ${{ secrets.ECR_REGISTRY }}
docker build -t $ECR_REGISTRY/syncad-api:$GITHUB_SHA -f apps/api/Dockerfile .
docker push $ECR_REGISTRY/syncad-api:$GITHUB_SHA
docker tag $ECR_REGISTRY/syncad-api:$GITHUB_SHA $ECR_REGISTRY/syncad-api:latest
docker push $ECR_REGISTRY/syncad-api:latest
- name: Deploy to ECS
run: |
aws ecs update-service \
--cluster syncad \
--service api \
--force-new-deployment
GitHub Actions — Deploy UIs
# .github/workflows/deploy-ui.yml
name: Deploy School Admin UI
on:
push:
branches: [main, dev]
paths: ['apps/school-admin-ui/**']
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
- uses: actions/setup-node@v4
with: { node-version: 20, cache: pnpm }
- run: pnpm install --frozen-lockfile
- run: pnpm build --filter school-admin-ui
- name: Deploy to S3 + CloudFront
run: |
aws s3 sync apps/school-admin-ui/.next/static s3://$S3_BUCKET/static \
--delete --cache-control "max-age=31536000,immutable"
aws cloudfront create-invalidation --distribution-id $CF_ID --paths "/*"
Environment-Specific Deployments
| Branch | Environment | URL |
|---|---|---|
dev | Development | dev-api.metaonus.in |
main | Staging | staging-api.metaonus.in |
Tag v*.*.* | Production | api.metaonus.in |