Skip to content

Every connection and what allows it

Every arrow on the map, with the exact rule that allows it. A connection works only when three things are true:

  1. Reach: a route exists. For example, the local route 10.0.0.0/16 joins the public and private subnets.
  2. Allowed: a rule lets it in. That is a security group inbound rule (port + source), an IAM permission (role + action), a resource policy, or a listener rule.
  3. Password: the caller holds the right secret, when one is needed.

These tables are generated from apps/book/src/data, the same data the map uses, so they cannot disagree with it. “Only when” means the arrow exists only with that config switch in infra/Pulumi.dev.yaml. The committed setting is ALB-only mode: cdnEnabled is false.

From → toWhat happensWhat allows it
Public subnets → VPC10.0.0.0/24 and 10.0.1.0/24 are slices of 10.0.0.0/16
  • config aws.ec2.Subnet vpcId = the VPC, one subnet per availability zonecreateNetwork
Private subnets → VPC10.0.10.0/24 and 10.0.11.0/24 are slices of 10.0.0.0/16
  • config aws.ec2.Subnet vpcId = the VPC, mapPublicIpOnLaunch falsecreateNetwork
Internet gateway → VPCthe internet gateway is attached to the VPC
Public subnets → Public route tableboth public subnets use this route table
  • route route table associations minitickets-dev-public-rta-1 and -2createNetwork
Public route table → Internet gatewaytraffic for the internet leaves through the internet gateway
  • route route 0.0.0.0/0 → minitickets-dev-igw (next to the local route 10.0.0.0/16)createNetwork
Private subnets → Private route tableboth private subnets use this route table: local route only
  • route route table associations minitickets-dev-private-rta-1 and -2; no 0.0.0.0/0 routecreateNetwork
Application Load Balancer → Public subnetsonly when entryEnabled = trueone ALB node in each public subnet
  • config internal: false, subnets = both public subnetscreateAlb
API ECS service → Public subnetsonly when computeEnabled = trueapi tasks get a private and a public IP in a public subnet
  • config networkConfiguration: subnets = public subnets, assignPublicIp: truecreateApiService
Web ECS service → Public subnetsonly when entryEnabled = trueweb tasks get a private and a public IP in a public subnet
  • config networkConfiguration: subnets = public subnets, assignPublicIp: truecreateWebService
RDS Postgres → Private subnetsonly when dataEnabled = truethe database lives in the private subnets
  • config DB subnet group minitickets-dev-db-subnets (both private subnets), publiclyAccessible: falsecreatePostgres
ElastiCache Valkey → Private subnetsonly when dataEnabled = truethe cache lives in the private subnets
  • config cache subnet group minitickets-dev-valkey-subnets (both private subnets)createCache
Browser → Public DNSonly when cdnEnabled = falselooks up minitickets.theversehub.in and gets the ALB's DNS name
  • dns CNAME minitickets.theversehub.in → the ALB's DNS name (stack output appDnsRecord), added by hand at Cloudflare, proxy offappDnsRecord
Browser → Application Load Balanceronly when cdnEnabled = falseHTTPS on port 443; plain HTTP on port 80 only gets a redirect
  • route public route table: 0.0.0.0/0 → minitickets-dev-igw. The task has a public IP; there is no NAT gateway and no VPC endpoint.createNetwork
  • sg-rule alb-sg inbound rule minitickets-dev-alb-in-443-0: TCP 443 from allowedCidrs (default 0.0.0.0/0)createAlbPublicIngress
  • sg-rule alb-sg inbound rule minitickets-dev-alb-in-80-0: TCP 80 from allowedCidrs, for the 301 redirect onlycreateAlbPublicIngress
  • certificate the :443 listener presents the ACM certificate for minitickets.theversehub.increateHttpsListener
Application Load Balancer → HTTPS listeneronly when cdnEnabled = falsethe ALB hands each request to the listener for its port
  • listener-rule listener :443 HTTPS, TLS policy ELBSecurityPolicy-TLS13-1-2-2021-06; listener :80 HTTP answers 301 → https://createHttpsListener
HTTPS listener → API target grouponly when cdnEnabled = false/trpc/* requests
  • listener-rule rule priority 100: path /trpc/* → forward to the api target groupcreateHttpsListener
HTTPS listener → Web target grouponly when cdnEnabled = falseevery other request: pages, /_next/static, /api/revalidate
Public DNS → ACM certificateACM finds its validation record and issues (and later renews) the certificate
  • dns validation CNAME _<random>.minitickets.theversehub.in (stack output certificateValidationRecord), kept forevercreateCertificate
Browser → CloudFront distributiononly when cdnEnabled = trueHTTPS to the nearest edge location, https://<id>.cloudfront.net
  • certificate the free default *.cloudfront.net certificate; viewerProtocolPolicy redirect-to-httpscreateCdn
CloudFront distribution → Application Load Balanceronly when cdnEnabled = truefetches from the origin over plain HTTP on port 80, adding the X-Origin-Verify header
  • sg-rule alb-sg inbound rule minitickets-dev-alb-in-80: TCP 80 from the AWS managed prefix list com.amazonaws.global.cloudfront.origin-facingcreateSecurityGroups
  • secret origin customHeaders: X-Origin-Verify = the origin secretcreateCdn
Application Load Balancer → HTTP listener with the origin headeronly when cdnEnabled = truethe ALB hands each request to its :80 listener
  • listener-rule listener :80 HTTP, default action: fixed response 403 ForbiddencreateListener
HTTP listener with the origin header → API target grouponly when cdnEnabled = true/trpc/* requests that carry the secret header
  • listener-rule rule priority 100: header X-Origin-Verify = origin secret AND path /trpc/* → api target groupcreateListener
HTTP listener with the origin header → Web target grouponly when cdnEnabled = trueevery other request that carries the secret header
  • listener-rule rule priority 200: header X-Origin-Verify = origin secret → web target groupcreateListener
Web ECS service → ECS Service Connectonly when entryEnabled = trueweb offers the name web and may call api
  • service-connect serviceConnectConfiguration: namespace minitickets.internal, discoveryName web, clientAlias port 3000, proxy port 13000createWebService
API ECS service → ECS Service Connectonly when entryEnabled = trueapi offers the name api and may call web
  • service-connect serviceConnectConfiguration: namespace minitickets.internal, discoveryName api, clientAlias port 4000, proxy port 14000createApiService
SES email identities → Public DNSreceiving mail servers check the DKIM signature against our DNS
  • dns 3 CNAMEs <token>._domainkey.minitickets.theversehub.in → <token>.dkim.amazonses.com (stack output sesDkimRecords)createEmail

Security groups: who may open a connection

Section titled “Security groups: who may open a connection”
From → toWhat happensWhat allows it
Application Load Balancer → ALB security grouponly when entryEnabled = truethe ALB's network interfaces use the ALB security group
API ECS service → API security grouponly when computeEnabled = trueevery API task (and the migration task) uses the api security group
  • config networkConfiguration.securityGroups: [apiSgId]; run-migrations.sh uses the same groupcreateApiService
Web ECS service → Web security grouponly when entryEnabled = trueevery web task uses the web security group
RDS Postgres → Database security grouponly when dataEnabled = truethe database uses the db security group
ElastiCache Valkey → Cache security grouponly when dataEnabled = truethe cache uses the redis security group
ACM certificate → HTTPS listeneronly when cdnEnabled = falsethe listener uses this certificate for TLS
  • certificate certificateArn from CertificateValidation: Pulumi waits up to 10 minutes for status ISSUEDcreateHttpsListener
API target group → API ECS serviceonly when entryEnabled = truethe ALB forwards to a healthy api task on port 4000 and checks GET /health
  • sg-rule api-sg inbound rule minitickets-dev-api-in-4000: TCP 4000 from alb-sgcreateSecurityGroups
  • registration the api service registers each task IP: loadBalancers container api, port 4000; health check grace 60 screateApiService
Web target group → Web ECS serviceonly when entryEnabled = truethe ALB forwards to a healthy web task on port 3000 and checks GET /
  • sg-rule web-sg inbound rule minitickets-dev-web-in-3000: TCP 3000 from alb-sgcreateSecurityGroups
  • registration the web service registers each task IP: loadBalancers container web, port 3000; health check grace 60 screateWebService
Web ECS service → API ECS serviceonly when entryEnabled = trueserver-side rendering: the web server calls http://api:4000
  • service-connect API_INTERNAL_URL http://api:4000 → web's proxy → the api's proxy on 14000 → the api containercreateServiceConnect
  • sg-rule api-sg inbound rule minitickets-dev-api-in-14000: TCP 14000 from web-sgcreateServiceConnect
API ECS service → Web ECS serviceonly when entryEnabled = truerevalidate: POST http://web:3000/api/revalidate after an event or seat count changes
  • service-connect WEB_INTERNAL_URL http://web:3000 → the web proxy on 13000 → the web containercreateServiceConnect
  • sg-rule web-sg inbound rule minitickets-dev-web-in-13000: TCP 13000 from api-sgcreateServiceConnect
  • secret the call carries REVALIDATE_SECRET; both tasks read it from minitickets/dev/revalidate-secretrevalidateEventsPages
API ECS service → RDS Postgresonly when computeEnabled = trueSQL over TLS on port 5432
  • sg-rule db-sg inbound rule minitickets-dev-db-in-5432: TCP 5432 from api-sgcreateSecurityGroups
  • route local route 10.0.0.0/16: a public subnet reaches a private subnet without leaving the VPCcreateNetwork
  • secret DB_USER and DB_PASSWORD from the RDS master secret (<arn>:username::, <arn>:password::)createApiTask
API ECS service → ElastiCache Valkeyonly when computeEnabled = truethe Redis protocol over TLS (rediss://) on port 6379
  • sg-rule redis-sg inbound rule minitickets-dev-redis-in-6379: TCP 6379 from api-sgcreateSecurityGroups
  • route local route 10.0.0.0/16: a public subnet reaches a private subnet without leaving the VPCcreateNetwork
  • secret REDIS_URL from minitickets/dev/redis-url, which holds the Valkey auth tokencreateSecrets
Migration task definition → RDS Postgresonly when computeEnabled = trueruns node dist/migrate.js against the database
From → toWhat happensWhat allows it
API ECS service → ECR repositoriesonly when computeEnabled = trueECS pulls the api image when a task starts
  • iam api execution role: AmazonECSTaskExecutionRolePolicy (ECR pull, CloudWatch Logs write)createIamRoles
  • route public route table: 0.0.0.0/0 → minitickets-dev-igw. The task has a public IP; there is no NAT gateway and no VPC endpoint.createNetwork
  • sg-rule api-sg outbound rule minitickets-dev-api-out-all: all traffic to 0.0.0.0/0createSecurityGroups
Web ECS service → ECR repositoriesonly when entryEnabled = trueECS pulls the web image when a task starts
  • iam web execution role: AmazonECSTaskExecutionRolePolicy (ECR pull, CloudWatch Logs write)createWebIamRole
  • route public route table: 0.0.0.0/0 → minitickets-dev-igw. The task has a public IP; there is no NAT gateway and no VPC endpoint.createNetwork
  • sg-rule web-sg outbound rule minitickets-dev-web-out-all: all traffic to 0.0.0.0/0createSecurityGroups
Worker Lambda → ECR repositoriesonly when computeEnabled = truethe Lambda service pulls the worker image when the function is created or updated
  • resource-policy repository policy LambdaPullWorkerImage on minitickets-dev-worker: lambda.amazonaws.com may ecr:BatchGetImage and ecr:GetDownloadUrlForLayer when aws:SourceArn is function:minitickets-dev-*allowLambdaPull
Tickets Lambda → ECR repositoriesonly when computeEnabled = truethe Lambda service pulls the same worker image for the tickets function
  • resource-policy the same repository policy: function:minitickets-dev-* matches minitickets-dev-ticketsallowLambdaPull
API task definition → API task execution roleonly when computeEnabled = trueECS assumes the execution role to start each api task
  • iam trust policy: ecs-tasks.amazonaws.com may sts:AssumeRole, only when aws:SourceAccount is our accountcreateIamRoles
API task definition → API task roleonly when computeEnabled = truethe running api code gets this role's credentials
  • iam trust policy: ecs-tasks.amazonaws.com may sts:AssumeRole, only when aws:SourceAccount is our accountcreateIamRoles
Web task definition → Web task execution roleonly when entryEnabled = trueECS assumes it to start each web task (web has no task role)
  • iam trust policy: ecs-tasks.amazonaws.com may sts:AssumeRole, only when aws:SourceAccount is our accountcreateWebIamRole
Migration task definition → API task execution roleonly when computeEnabled = truethe migration borrows the api execution role (no task role)
  • iam trust policy: ecs-tasks.amazonaws.com may sts:AssumeRole, only when aws:SourceAccount is our accountcreateIamRoles
Worker Lambda → Worker Lambda execution roleonly when computeEnabled = truethe worker function runs with this role
Tickets Lambda → Tickets Lambda execution roleonly when computeEnabled = truethe tickets function runs with this role
API ECS service → CloudWatch log groupsonly when computeEnabled = truethe awslogs driver sends every api line to /minitickets/dev/api
  • iam api execution role managed policy: logs:CreateLogStream, logs:PutLogEventscreateIamRoles
  • route public route table: 0.0.0.0/0 → minitickets-dev-igw. The task has a public IP; there is no NAT gateway and no VPC endpoint.createNetwork
Web ECS service → CloudWatch log groupsonly when entryEnabled = truethe awslogs driver sends every web line to /minitickets/dev/web
  • iam web execution role managed policy: logs:CreateLogStream, logs:PutLogEventscreateWebIamRole
  • route public route table: 0.0.0.0/0 → minitickets-dev-igw. The task has a public IP; there is no NAT gateway and no VPC endpoint.createNetwork
Worker Lambda → CloudWatch log groupsonly when computeEnabled = trueworker lines go to /minitickets/dev/worker
  • iam worker role WriteWorkerLogs: logs:CreateLogStream, logs:PutLogEvents on /minitickets/dev/worker:*createWorkerRole
  • config loggingConfig logGroup /minitickets/dev/worker (not the default /aws/lambda/…)createWorkerLambda
Tickets Lambda → CloudWatch log groupsonly when computeEnabled = truetickets lines go to /minitickets/dev/tickets
  • iam tickets role: logs:CreateLogStream, logs:PutLogEvents on /minitickets/dev/tickets:*createTicketRole
API ECS service → Booking-events SNS topiconly when computeEnabled = truethe outbox relay publishes each booking-confirmed event
  • iam api task role, policy send-jobs: sns:Publish on minitickets-dev-booking-events onlycreateIamRoles
  • route public route table: 0.0.0.0/0 → minitickets-dev-igw. The task has a public IP; there is no NAT gateway and no VPC endpoint.createNetwork
Booking-events SNS topic → Jobs SQS queueSNS delivers a copy to the email queue
  • resource-policy queue policy: sns.amazonaws.com may sqs:SendMessage on this queue, only when aws:SourceArn is the topic and aws:SourceAccount is ourscreateBookingEvents
  • trigger SNS subscription protocol sqs, rawMessageDelivery truecreateBookingEvents
Booking-events SNS topic → Tickets SQS queueSNS delivers a copy to the tickets queue
  • resource-policy queue policy: sns.amazonaws.com may sqs:SendMessage on this queue, only when aws:SourceArn is the topic and aws:SourceAccount is ourscreateBookingEvents
  • trigger SNS subscription protocol sqs, rawMessageDelivery truecreateBookingEvents
Jobs SQS queue → Worker Lambdaonly when computeEnabled = truethe event source mapping polls the queue and calls the worker with batches
  • trigger event source mapping: batchSize 10, functionResponseTypes ReportBatchItemFailures, maximumConcurrency 5createQueueTrigger
  • iam worker role ReadJobsQueue: sqs:ReceiveMessage, sqs:DeleteMessage, sqs:ChangeMessageVisibility, sqs:GetQueueAttributes on minitickets-dev-jobscreateWorkerRole
Tickets SQS queue → Tickets Lambdaonly when computeEnabled = truethe event source mapping calls the tickets function with one message at a time
  • trigger event source mapping: batchSize 1, ReportBatchItemFailures, maximumConcurrency 2createTicketLambda
  • iam tickets role: sqs:ReceiveMessage, sqs:DeleteMessage, sqs:GetQueueAttributes on minitickets-dev-ticketscreateTicketRole
Worker Lambda → Processed-jobs tableonly when computeEnabled = trueGetItem before sending; a conditional PutItem after sending
  • iam worker role ProcessedJobsTable: dynamodb:GetItem, dynamodb:PutItem on minitickets-dev-processed-jobscreateWorkerRole
Worker Lambda → SES email identitiesonly when computeEnabled = trueSendEmail from no-reply@minitickets.theversehub.in
  • iam worker role SendBookingEmails: ses:SendEmail on our identity ARNs, condition ses:FromAddress = no-reply@minitickets.theversehub.increateWorkerRole
  • config env MAILER ses and MAIL_FROM no-reply@minitickets.theversehub.increateWorkerLambda
Tickets Lambda → Tickets tableonly when computeEnabled = truereserves and completes the ticket items
  • iam tickets role: dynamodb:GetItem, dynamodb:PutItem, dynamodb:UpdateItem on minitickets-dev-ticketscreateTicketRole
Tickets Lambda → Ticket assets bucketonly when computeEnabled = truewrites the QR PNGs under tickets/
API ECS service → Tickets tableonly when computeEnabled = truereads one user's tickets for My tickets
  • iam api task role ReadTickets: dynamodb:Query on minitickets-dev-tickets (no Scan, no writes)createIamRoles
  • route public route table: 0.0.0.0/0 → minitickets-dev-igw. The task has a public IP; there is no NAT gateway and no VPC endpoint.createNetwork
API ECS service → Ticket assets bucketonly when computeEnabled = truesigns GET and PUT URLs, and copies a checked upload to posters/
  • iam api task role: s3:GetObject on tickets/*, posters/*, poster-uploads/*; s3:PutObject on posters/* and poster-uploads/* only with x-amz-server-side-encryption AES256createIamRoles
  • resource-policy bucket policy: Deny every s3:* request when aws:SecureTransport is falsecreateTicketStorage
CloudWatch alarms → Alerts SNS topiceach alarm publishes on ALARM and on OK
  • resource-policy topic policy OurCloudWatchAlarmsMayPublish: cloudwatch.amazonaws.com may sns:Publish, only for aws:SourceArn alarm:minitickets-dev-* in our accountcreateAlertTopic
  • config alarmActions and okActions = [alert topic ARN]createAlarms
CD publish job → GitHub publish roleswaps its GitHub OIDC token for 1-hour AWS credentials
  • iam trust policy: Federated = the GitHub OIDC provider, sts:AssumeRoleWithWebIdentity, aud = sts.amazonaws.com, sub = <subject prefix>:ref:refs/heads/maincreateCicd
CD deploy job → GitHub deploy roleswaps its GitHub OIDC token for 2-hour AWS credentials
  • iam deploy role trust: sts:AssumeRoleWithWebIdentity; Federated = the GitHub OIDC provider, aud = sts.amazonaws.com, sub = <subject prefix>:environment:devcreateCicd
GitHub publish role → GitHub OIDC identity providerthe role trusts tokens from this provider only
  • config Principal Federated = the OIDC provider ARN; clientIdLists [sts.amazonaws.com]createCicd
GitHub deploy role → GitHub OIDC identity providerthe role trusts tokens from this provider only
  • config Principal Federated = the OIDC provider ARNcreateCicd
CD publish job → ECR repositoriesdocker push api, web and worker :<git sha>
  • iam publish role push-images: ecr:GetAuthorizationToken (*), and push/pull actions on the 3 repositories onlypublishPolicyDocument
CD deploy job → ECR repositorieschecks the tag exists and adds the tag deployed-<sha>
  • iam deploy role OurEcrRepos: ecr:* on the 3 repository ARNscreateCicd
CD deploy job → Release parametersreads deployed-commit for the guard; normally writes image-tag in phase B (phase A if no current image); records deployed-commit at the end if an infrastructure apply ran, including failure or cancellation
  • iam deploy role OurReleaseParameters grants ssm:GetParameter and ssm:PutParameter on the two parameter ARNs; ReadOurParameterPath grants ssm:GetParametersByPath under /minitickets/devcreateCicd
CD deploy job → Migration task definitiononly when computeEnabled = trueruns the migration task (scripts/run-migrations.sh) with launch type FARGATE
  • iam deploy role StackServices ecs:* and PassOurRolesToEcsTasksAndLambda: iam:PassRole on minitickets-dev-* to ecs-tasks.amazonaws.comcreateCicd
CD deploy job → API ECS serviceonly when computeEnabled = truephase B pulumi up rolls the services; aws ecs wait services-stable
  • iam deploy role StackServices grants ecs:* on Resource *; PassOurRolesToEcsTasksAndLambda grants iam:PassRole on minitickets-dev-* to ECS tasks; DenyOtherRegions blocks calls outside us-east-1createCicd
From → toWhat happensWhat allows it
Origin secret → CloudFront distributiononly when cdnEnabled = trueCloudFront sends this value as X-Origin-Verify
  • config createOriginSecret().headerValue → createCdn originHeaderValue (a Pulumi secret, never a stack output)createOriginSecret
Origin secret → HTTP listener with the origin headeronly when cdnEnabled = truethe listener rules compare the header with this value
  • config createOriginSecret().headerValue → createListener originHeaderValuecreateOriginSecret
API ECS service → RDS master password secretonly when computeEnabled = trueECS reads the database user and password when a task starts
  • iam api execution role, policy read-secrets: secretsmanager:GetSecretValue on this secret's ARNcreateIamRoles
  • route public route table: 0.0.0.0/0 → minitickets-dev-igw. The task has a public IP; there is no NAT gateway and no VPC endpoint.createNetwork
API ECS service → Redis URL secretonly when computeEnabled = trueECS reads REDIS_URL when a task starts
  • iam api execution role, policy read-secrets: secretsmanager:GetSecretValue on minitickets/dev/redis-urlcreateIamRoles
  • route public route table: 0.0.0.0/0 → minitickets-dev-igw. The task has a public IP; there is no NAT gateway and no VPC endpoint.createNetwork
API ECS service → Revalidate secretonly when entryEnabled = trueECS reads REVALIDATE_SECRET for the api when a task starts
  • iam api execution role, policy read-secrets: secretsmanager:GetSecretValue on minitickets/dev/revalidate-secretcreateIamRoles
  • route public route table: 0.0.0.0/0 → minitickets-dev-igw. The task has a public IP; there is no NAT gateway and no VPC endpoint.createNetwork
Web ECS service → Revalidate secretonly when entryEnabled = trueECS reads REVALIDATE_SECRET for web when a task starts
  • iam web execution role, policy read-revalidate-secret: secretsmanager:GetSecretValue on this ARN onlycreateWebIamRole
  • route public route table: 0.0.0.0/0 → minitickets-dev-igw. The task has a public IP; there is no NAT gateway and no VPC endpoint.createNetwork
Tickets Lambda → Ticket signing secretonly when computeEnabled = truethe tickets code reads the HMAC key at run time
  • iam tickets role: secretsmanager:GetSecretValue on minitickets/dev/ticket-signingcreateTicketRole

Data and code: what runs where, and in-process calls

Section titled “Data and code: what runs where, and in-process calls”
From → toWhat happensWhat allows it
API ECS service → API task definitiononly when computeEnabled = truethe service starts tasks from the newest revision
  • config taskDefinition = minitickets-dev-api:<revision>; a new revision rolls the servicecreateApiService
Web ECS service → Web task definitiononly when entryEnabled = truethe service starts tasks from the newest revision
API ECS service → ECS clusteronly when computeEnabled = truethe api service runs in cluster minitickets-dev on FARGATE_SPOT
  • config capacityProviderStrategies: FARGATE_SPOT weight 1 (attached to the cluster)createCluster
Web ECS service → ECS clusteronly when entryEnabled = truethe web service runs in cluster minitickets-dev on FARGATE_SPOT
  • config capacityProviderStrategies: FARGATE_SPOT weight 1createCluster
Saved Logs Insights queries → CloudWatch log groupsonly when computeEnabled = truethe saved queries run over /minitickets/dev/api and /worker
  • config logGroupNames on each QueryDefinition; whoever runs a query needs logs:StartQuerycreateLogQueries
Jobs SQS queue → Jobs dead-letter queueafter the 3rd failed receive, SQS moves the message to the DLQ
  • config redrivePolicy: maxReceiveCount 3, deadLetterTargetArn = minitickets-dev-jobs-dlqcreateJobQueues
  • resource-policy redrive allow policy on the DLQ: byQueue, only minitickets-dev-jobs may use itcreateJobQueues
Browser → Ticket assets bucketdownloads a ticket PNG or uploads a poster with a presigned URL
  • url presigned URL signed with the api task role's credentials, valid 120 s (ASSET_URL_SECONDS)signAssetGet
  • resource-policy CORS rule: allowed origin = appUrl, methods GET and PUT, max age 120 screateAssetCors
Web ECS service → Web apponly when entryEnabled = trueeach web task runs the Next.js server on port 3000
API ECS service → API apponly when computeEnabled = trueeach api task runs the Fastify server on port 4000
Browser → Web apploads the pages
  • url same origin https://minitickets.theversehub.in; the listener's default action sends pages to webcreateHttpsListener
Browser → API appcalls /trpc/* with the sid cookie
  • url same origin, so no CORS question; every mutation must carry the exact Origin (CSRF check, mutationAllowed)mutationAllowed
Web app → API appserver-side rendering of /events calls the api
API app → Sessionsreads the session of every request
  • code createContext reads the sid cookie and asks queries/sessions.tscreateContext
Sessions → ElastiCache Valkeyonly when dataEnabled = truesession:<hash> keys with a 7-day TTL
  • code only queries/sessions.ts touches the session keyscreate
API app → Events list cacheevents.list asks the cache first
Events list cache → ElastiCache Valkeyonly when dataEnabled = truethe cached lists and the generation key
API app → Rate limiterlog-in and booking take a token first
Rate limiter → ElastiCache Valkeyonly when dataEnabled = trueone token bucket per scope and caller
  • code queries/rate-limits.ts runs the TAKE_TOKEN Lua scripttakeToken
API app → Inventory gatea booking asks the gate before the database transaction
Inventory gate → ElastiCache Valkeyonly when dataEnabled = trueseat counters and leases per event
  • code queries/inventory.ts runs the RESERVE and SETTLE Lua scriptsreserve
API app → RDS Postgresonly when dataEnabled = truequeries/*.ts run the SQL; a booking locks the event row (SELECT … FOR UPDATE)
API app → Transactional outboxthe booking and its outbox row are written in one transaction
  • code createBookingTx inserts the booking and the BookingConfirmedMessage row togethercreateBookingTx
Transactional outbox → RDS Postgresonly when dataEnabled = truethe outbox is a Postgres table
  • code queries/outbox.ts deliverBatch reads pending rows in a transactiondeliverBatch
Transactional outbox → Booking-events SNS topicthe relay publishes each pending row once to SNS
Jobs dead-letter queue → CloudWatch alarmsApproximateNumberOfMessagesVisible > 0 for 1 minute → jobs-dlq-not-empty
  • metric AWS/SQS ApproximateNumberOfMessagesVisible, Maximum, period 60 s, treatMissingData ignorealarmSpecs
Jobs SQS queue → CloudWatch alarmsApproximateAgeOfOldestMessage ≥ 300 s → jobs-oldest-message-age
  • metric AWS/SQS ApproximateAgeOfOldestMessage, Maximum, period 60 salarmSpecs
Worker Lambda → CloudWatch alarmsonly when computeEnabled = trueErrors > 0 in 5 minutes → worker-errors
  • metric AWS/Lambda Errors, Sum, period 300 salarmSpecs
Application Load Balancer → CloudWatch alarmsonly when entryEnabled = truetarget 5xx + ALB 5xx ≥ 5 in 5 minutes → alb-5xx
  • metric AWS/ApplicationELB FILL(HTTPCode_Target_5XX_Count, 0) + FILL(HTTPCode_ELB_5XX_Count, 0), period 300 salarmSpecs
CloudWatch dashboard → CloudWatch alarmsthe dashboard's alarm status widget
  • config dashboard body built from the alarm ARNs, queue names and service namescreateDashboard
Monthly cost budget → AWS account and regionwatches the whole account's monthly cost
  • metric COST budget 20 USD per month; emails at 25%, 50%, 100% actual and 100% forecastcreateBudget
CI workflow → CD publish jobCD starts after CI finished on main
  • trigger workflow_run: workflows [CI], types [completed], branches [main]; the job checks CI's conclusionpublish
CD publish job → CD deploy jobdeploy runs after publish; waits for approval when environment dev has a required reviewer
  • trigger needs: publish; environment: dev; the required reviewer is configured in GitHub, outside the workflowdeploy
Release parameters → API task definitiononly when computeEnabled = truepulumi reads image-tag, so the task definitions use image :<tag>
  • config readDeployedImageTag lists /minitickets/dev and picks image-tag (config apiImageTag would override it)readDeployedImageTag

Read this book online: https://book.theversehub.in/