Skip to content

01 — Prerequisites

Scope: Per-client. Sit with the client and collect everything needed before any technical setup begins.

The output of this phase is all the values needed to configure the deployment pipeline in Step 02. Go through each section with the client.


Checklist

Required from Client

  • AWS Account ID — 12-digit account identifier (AWS Console > top-right > Account ID)
  • Custom domain name — e.g., ai.university.edu
  • DNS access — ability to create a CNAME record pointing to our subdomain or ALB
  • SSL mode - the SSL_MODE deployment variable; pick one:
  • managed (recommended) - CampusCore provisions HTTPS on {env}.campuscoreai.com and can issue certificates for the client's own domain added in-app
  • self_managed - the subdomain and HTTPS are provisioned, but the client terminates TLS for their own domain themselves (e.g. Cloudflare)
  • off - HTTP only, for throwaway test environments
  • OpenAI API key — for embeddings and LLM (platform.openai.com/api-keys)
  • Gemini API key — for document OCR processing (ai.google.dev)
  • Cohere API key — for search reranking (cohere.com)

Required from Client (Branding)

These are used in the post-deployment setup wizard (Step 04).

  • Institution name — full name (e.g., "Howard University")
  • Institution abbreviation — short form (e.g., "HU")
  • Logo image - the institution logo as an image file (it is uploaded in the setup wizard, not linked by URL)
  • Brand color - the primary color as a hex value (the wizard takes one color)
  • Assistant name — what to call the AI assistant (e.g., "Bison", "Beacon")

Internal Decisions (CampusCore Engineering)

These don't involve the client but should be settled before Step 04 so the deploy carries the right config from the first push.

  • Sentry project — one Sentry project per client, named after the client (e.g. vsu-troy); every environment of that client reports into it, told apart by the environment tag. Create now or note "deferred." See Sentry Setup.
  • Slack workflow_runs channel — every client environment posts to the one shared #client_workflow_runs channel. Confirm it exists and that the bot @campuscoreplatform is a member; a private channel needs the invite. The slack section of scripts/onboard-client.sh resolves the channel ID and sets it as a GitHub variable, not a secret — the classic mistake when done by hand. A dedicated per-client channel is the exception, not the rule. See Slack Setup.
  • Auto-rebuild schedule — decide whether to disable the daily auto-rebuild schedule for this tenant. It is on by default; set ENABLE_INDEX_MAINTENANCE_SCHEDULE to false only if this environment should not check or rebuild its vector index automatically. See Vector Index Observability.
  • Security posture services - production client environments set ENABLE_FULL_AWS_SECURITY_SERVICES=true (GuardDuty, Config recording, Security Hub, Inspector; ~$50-120/month on the client's AWS bill). The Terraform default is off, so a sandbox that sets nothing carries no cost. See GitHub Environment Variables Reference. Before setting it true, check whether the account already runs any of these - an Organizations auto-enable policy or a past console click means GuardDuty, Config, or Security Hub may already be on, and Terraform fails creating what exists. Ask the client (or check the three consoles with a client profile), and terraform import the existing detector/recorder/hub account into module.security_services[0] before the first apply with the gate on.

What Gets Created in the Client's AWS Account

For transparency, share this with the client so they know what the deploy role provisions:

Resource Purpose
Dedicated VPC (2 AZs) Public + private subnets; app, RDS, and cache run in private subnets
NAT Gateway (single by default; optional per-AZ mode) Outbound internet for private-subnet tasks (AI provider APIs)
VPC Interface Endpoints (5) Private links to ECR (api + dkr), CloudWatch Logs, SQS, SSM; free S3 gateway endpoint
ECS Cluster + Services Web app (1 vCPU/2 GB) + document worker (1 vCPU/4 GB) on Fargate
ECR Repositories Docker image storage (web + worker)
RDS PostgreSQL 18 Database with pgvector (db.t3.large, 20 GB by default; sizing configurable per environment); optional read replica off by default
ElastiCache Serverless (Valkey) Shared in-memory cache (storage capped at 1 GB)
S3 Buckets App storage + user file uploads
SQS Queue Document processing job queue + dead-letter queue
ALB Load balancer (HTTP, 180s idle timeout for streaming)
AWS WAF WAFv2 web ACL on the ALB (4 AWS managed rule sets + per-IP rate limit)
CloudWatch Logs Application logging (14-day retention)
IAM Roles ECS task execution and task roles
Security posture services (optional; on for production) GuardDuty (threat detection, upload malware scanning, runtime monitoring), AWS Config recording, Security Hub (FSBP standard), Inspector ECR scanning

Encryption by default: All storage resources are created with encryption enabled — RDS uses AWS-managed KMS encryption, S3 buckets use AES-256 server-side encryption, and SQS queues use AWS-managed SSE. No additional configuration is needed from the client. See Security & SOC 2 Compliance for details.

Not in their account: Terraform state is stored in our admin account's S3 bucket.

Estimated AWS Costs

Baseline monthly cost for a single-instance deployment (us-east-1, desired_count 1, light traffic), at current on-demand pricing:

Service Configuration Approximate Cost
RDS PostgreSQL db.t3.large + 20 GB (default sizing) ~$108
ECS Fargate (web + worker) 1 vCPU/2 GB + 1 vCPU/4 GB ~$79
VPC interface endpoints 5 services × 2 AZs @ $0.01/hr ~$73
NAT gateway single @ $0.045/hr + data ~$33
ALB $0.0252/hr + LCUs ~$20
ElastiCache Serverless (Valkey) $0.084/GB-hr, capped 1 GB ~$10
AWS WAF web ACL + 5 rules ~$10
S3 + SQS + CloudWatch + transfer usage-based ~$15
Total (default configuration) ~$350/month
Security posture services (optional) GuardDuty + Security Hub + Inspector + Config ~$50-120, usage-scaled
Second NAT gateway (optional, ENABLE_PER_AZ_NAT) 1 more @ $0.045/hr + IPv4 ~$37

Costs scale with usage: the worker auto-scales 1-10 and web 1-5 under bulk ingestion (the largest variable), and NAT/endpoint data processing, egress, and WAF requests grow with traffic. AI provider usage (OpenAI/Gemini/Cohere) is billed to the client's own accounts, separate from AWS. Enabling the read replica adds the replica instance's cost (default db.t3.medium, about half the primary's line).


Output of This Phase

By the end of this step, you should have values for every secret and variable listed below. These map directly to the GitHub Environment configuration in Step 02.

Collected Value Maps to GitHub Secret/Variable
AWS Account ID Used to derive AWS_ROLE_ARN (after client deploys role in Step 03)
Custom domain Added self-service in Settings > Custom Domain after deployment (see Custom Domain Setup)
SSL mode SSL_MODE
OpenAI API key OPENAI_API_KEY
Gemini API key GEMINI_API_KEY
Cohere API key COHERE_API_KEY
Slack channel ID (per-client) SLACK_CHANNEL_WORKFLOW_RUNS (variable, not secret)

See GitHub Environment Variables Reference for the complete specification — including the Slack and index-maintenance variables added by recent work, and the SLACK_BOT_TOKEN repo-level secret shared across all tenants.


Next: 02 — Pipeline Setup