Skip to content

AWS Resource Architecture (client-facing)

This is the AWS resource diagram we share with universities: what a standard CampusCore deployment actually provisions in the institution's own AWS account, from the network layer through compute, with the data, messaging, and supporting services drawn where they attach. It is the infrastructure companion to the component-level Architecture Overview - that diagram says what the platform does; this one says what backs it. The Terraform under infrastructure/ is the source of truth; the mapping table below ties every box to its defining files.

The diagram

The AWS resources of a standard CampusCore deployment: the WAF and load balancer edge, the VPC with public and private subnets, the Fargate services, the data stores, and three full-width function layers below the VPC - application services, observability, and security and compliance

The editable source is assets/aws-resource-architecture.drawio, a draw.io (diagrams.net) file drawn with the official AWS 2019 icon set. The PNG above is its 2x export; when the diagram changes, both files change together. The "Exporting the image" section below covers regeneration.

Reading the diagram

The diagram uses AWS's own icon language rather than the overview's house style, so an institution's cloud or security reviewer sees the notation they already know.

  • The dark-bordered box carrying the AWS logo is the institution's own AWS account; every resource inside it is created by our Terraform, and nothing is shared with any other institution.
  • Outside the account sit the campus users at the top and, drawn as dark clouds, the two external parties: the AI model providers and the DNS name that points at the deployment.
  • Inside the account, the purple border is the VPC; the green-edged band at the top holds the public subnets, and the blue band below it the private subnets, where the application tasks, the database, and the cache live without public IP addresses.
  • The dashed orange box is the ECS cluster.
  • Below the VPC, three dashed full-width bands layer the rest of the account by function: the gray application-services band (storage, queues, images, schedules), the pink observability layer, and the red security & compliance layer. The two lower bands stretch across the whole diagram because their services watch or guard everything above them rather than sitting on any one data path.
  • An italic (optional) in a label marks a resource that only some deployments have; the "Optional per deployment" section below names the exact switch for each.
  • The VPC endpoints icon is plumbing rather than a traffic hop: it keeps the tasks' traffic to S3, ECR, CloudWatch Logs, SQS, and SSM on AWS's own network instead of the public internet.
  • The observability layer holds CloudWatch and CloudTrail with the alarm-notification path. The in-app trace store (OpenTelemetry spans in PostgreSQL, read by the agent traces console) is deliberately not drawn: the diagram is client-facing, and from a client's perspective observability is CloudWatch.
  • The security & compliance layer holds the optional security posture services - GuardDuty threat detection with malware scanning of the upload bucket, Security Hub with Inspector and AWS Config, and the account-wide hardening settings - plus IAM's least-privilege task and deploy roles and the encryption-at-rest box, which is a statement rather than a resource: RDS encrypts with the AWS-managed KMS key, S3 and SQS use their service-managed server-side encryption, and the CloudTrail stream uses a customer-managed key. AWS WAF belongs to this layer too but stays at the top of the diagram, on the request path it filters.
  • Arrow labels carry behavior where the path alone does not state it; the unlabeled arrows - the services into their database and cache, and the ECS cluster into the NAT gateway - are plain reads-and-writes and routing.

What each box maps to in Terraform

The reusable resource shapes live in infrastructure/modules/; the infrastructure/base/ layer instantiates the stable resources and infrastructure/app/ the per-deploy ones.

Diagram box AWS resources Terraform home
VPC, subnets, NAT gateway(s), routing, flow logs aws_vpc, aws_subnet x4, aws_internet_gateway, aws_nat_gateway (one shared, or one per AZ with enable_per_az_nat), route tables, aws_flow_log infrastructure/modules/networking/, via infrastructure/base/networking.tf
VPC endpoints 5 aws_vpc_endpoint (Interface) + 1 (Gateway, S3) infrastructure/base/endpoints.tf; the S3 gateway in infrastructure/modules/networking/main.tf
Application Load Balancer aws_lb (deletion-protected, invalid header fields dropped), target group, HTTP listener (301 to HTTPS when SSL is on, otherwise a forward), security groups; HTTPS listener when SSL is on infrastructure/modules/ecs_cluster/main.tf, infrastructure/base/alb.tf
AWS WAF aws_wafv2_web_acl (REGIONAL) + ALB association + logging infrastructure/modules/waf/, via infrastructure/base/waf.tf
DNS + certificate Route53 CNAME (CampusCore admin account) + aws_acm_certificate (client account) infrastructure/modules/subdomain/, via infrastructure/base/dns.tf
ECS cluster aws_ecs_cluster with Container Insights + the shared log group infrastructure/modules/ecs_cluster/main.tf, via infrastructure/base/ecs.tf
Web service task definition + service + CPU-target autoscaling infrastructure/app/web.tf
Worker service task definition + service + queue-backlog autoscaling infrastructure/app/worker.tf
On-demand tasks task definitions launched via ecs:RunTask infrastructure/app/crawler.tf, infrastructure/app/ops_task.tf, infrastructure/app/custom_domain_reconciler.tf
RDS PostgreSQL aws_db_instance + parameter groups + optional replica infrastructure/modules/rds/, via infrastructure/base/rds.tf
ElastiCache Serverless aws_elasticache_serverless_cache (Valkey) infrastructure/modules/elasticache/, via infrastructure/base/cache.tf
S3 buckets 4 aws_s3_bucket with SSE, public-access blocks, TLS-only policies infrastructure/modules/s3_bucket/, via infrastructure/base/s3.tf
SQS queues 2 work queues + 2 dead-letter queues, SSE on infrastructure/modules/sqs_queue/, via infrastructure/base/sqs.tf
ECR repositories 2 aws_ecr_repository with scan-on-push and a four-rule lifecycle policy: the two most recent images per base-cache family are protected, deploy builds keep a floor of the last 5, and untagged orphans expire after 7 days infrastructure/modules/ecr_repo/, via infrastructure/base/ecr.tf
EventBridge schedules aws_scheduler_schedule + per-schedule IAM role, one pair per job infrastructure/modules/scheduled_ecs_task/, via infrastructure/app/schedules.tf
CloudWatch + CloudTrail log groups, 22 metric alarms, the availability dashboard, aws_cloudtrail into the log archive infrastructure/app/monitoring.tf, infrastructure/app/availability.tf, infrastructure/base/cloudtrail.tf
Route 53 health check external /readiness probe feeding the availability number infrastructure/app/availability.tf
SNS alerts aws_sns_topic + optional email subscription + optional EventBridge-to-Slack delivery infrastructure/modules/sns_alert_topic/, infrastructure/modules/slack_alarm_notifier/
GuardDuty, Security Hub, Inspector, AWS Config aws_guardduty_detector + feature resources + malware protection plan, aws_securityhub_account + FSBP standard subscription, aws_inspector2_enabler + documented suppression filters for CVEs with no shipped fix, Config recorder + delivery channel infrastructure/modules/guardduty/, aws_config/, security_hub/, inspector/, via infrastructure/base/security_services.tf
Account-wide hardening S3 account public-access block, EBS encryption by default, snapshot public-access block, SSM document public sharing disabled, IAM password policy, SECURITY alternate contact infrastructure/base/account_hardening.tf
CloudTrail encryption + monitoring aws_kms_key with rotation + alias, the trail's CloudWatch log group, and the write-only delivery role infrastructure/base/cloudtrail.tf
IAM shared task + execution roles, reconciler role, per-schedule roles; the deploy role is the CloudFormation stack infrastructure/deploy-roles/deploy-role.yaml infrastructure/modules/ecs_iam/, infrastructure/app/custom_domain_reconciler.tf

Optional per deployment

A standard deployment creates everything above except the pieces behind these switches. Each switch is a Terraform variable fed from the deployment's GitHub Environment.

Optional piece Switch Default
HTTPS listener, the HTTP listener's 301 to it, env.campuscoreai.com CNAME, ACM certificate ssl_mode (off / self_managed / managed) off in test environments; real client deployments run self_managed or managed
Custom-domain reconciler task, its schedule, and its IAM role ssl_mode other than off; certificate management only under managed follows ssl_mode
RDS read replica enable_read_replica off
Alarm email delivery alert_email off (the SNS topic always exists)
Alarm Slack delivery (EventBridge API destination) slack_alert_webhook_url off
Nightly vector-index auto-rebuild schedule enable_index_maintenance_schedule on
CloudTrail S3 data events enable_cloudtrail_data_events on
Security posture services: GuardDuty (threat detection, upload malware scanning, runtime monitoring), AWS Config recording, Security Hub (FSBP standard), Inspector scanning of images, instances and functions with documented no-fix suppressions, the account-wide hardening settings, and CloudTrail's encryption key + CloudWatch Logs delivery enable_full_aws_security_services off; production client environments run it on
One NAT gateway per AZ instead of a single shared one enable_per_az_nat off

Scheduled jobs

EventBridge Scheduler launches standalone Fargate tasks from the worker image; none of these run inside the web or worker services. Times are UTC. In AWS the names carry the environment: campuscore-env-audit-export and so on, except the domain reconciler, which is named custom-domain-reconciler-env.

Schedule What it runs Cadence Optional
abandoned-reconcile reconcile_abandoned_ingestion_runs daily 05:00 no
ops-reconcile reconcile_operation_runs every 5 min no
crawl-reconcile reconcile_crawl_runs every 10 min no
audit-export export_audit_logs daily 01:30 no
audit-prune prune_audit_logs daily 02:00 no
analytics-rollup rollup_analytics daily 02:45 no
traces-prune prune_traces daily 03:15 no
guest-chat-cleanup cleanup_guest_conversations + clearsessions daily 03:45 no
under-extracted-sweep sweep_under_extracted daily 07:00 no
auto-rebuild auto_rebuild_if_justified daily 06:00 yes - enable_index_maintenance_schedule
custom-domain-reconciler reconcile_custom_domains every 5 min, created disabled and toggled at runtime yes - ssl_mode

Alarms

Twenty-two CloudWatch alarms watch the deployment, all delivering to the SNS topic; custom metrics live in the CampusCore namespace, dimensioned by deployment. The availability probe alarm is created in us-east-1 (where Route 53 metrics live) and only for us-east-1 deployments - see Availability Measurement for the caveat.

Family Alarms
Availability external readiness probe failing
HTTP 5xx error rate, p95 latency
Chat error rate, p95 latency
Agent error rate, max-iterations rate, p95 iterations
Retrieval p99 latency, empty-result rate, hard-error rate
Model providers LLM call error rate
Web tasks unhealthy count, CPU, memory
Worker tasks unhealthy count, CPU, memory
Queues bulk queue depth, bulk dead-letter queue not empty, interactive queue stalled, bulk queue stalled

How the resources get created

Deploys run from GitHub Actions with no long-lived AWS keys. The workflow assumes CampusCore-Admin-Role in the CampusCore admin account through GitHub's OIDC provider; that role holds only the Terraform state and the campuscoreai.com DNS zone, and its one cross-account permission is assuming the CampusCore-Deploy-Role that the institution created in its own account from our CloudFormation template. Terraform then applies the base layer (network, data stores, cluster, edge) and the app layer (task definitions, services, schedules, alarms) with that role. Application data never leaves the institution's account; the only artifact stored on our side is the Terraform state.

Exporting the image

Edit assets/aws-resource-architecture.drawio in draw.io - app.diagrams.net or the desktop app - and export with File -> Export as -> PNG at 200% zoom, background on. Overwrite assets/aws-resource-architecture.png with the export and commit both files together: the PNG is the render that GitHub, the docs portal, and client decks all show, so the pair must never drift. Expect a noisy diff after an editor round-trip - draw.io rewrites the XML on save - so small label edits are easier made directly in the file. Unlike the Architecture Overview there is no export harness page - draw.io's own exporter replaces it.

Where this diagram is published

The client docs portal serves a client-worded page, product/aws-resource-architecture.md, which pulls the image embed from this file via a snippet include - the Markdown between the --8<-- markers above is the single source, and both pages show the same committed PNG. The image path inside the markers is written relative to a sibling of docs/project/ (../project/assets/...) so that the identical text resolves from this file and from the including page under docs/product/. The .drawio source ships in the portal build too - static files are not audience-filtered - which is fine: it holds nothing beyond the diagram the page already shows.