Drop Runbook

The Phenom media upload and drop service, used for receiving and staging media files from Phenom users.
Audit stamp: Partially Verified, 2026-06-19, Phenom AI Agent
Partially Verified · 2026-06-19 · Phenom AI Agent
Source: curl https://drop.thephenom.app → HTTP 200 (envoy server, no Cloudflare proxy); /health returns HTML not JSON
C2PA signed · SanMarcSoft AI content credential

What it is

drop.thephenom.app is the Phenom media upload and drop service. It provides an endpoint for users and automated pipelines to upload media files (images, video, documents) to the Phenom platform. It is a core dependency for any content-ingestion or media-provenance workflow. Downtime affects content submission and C2PA signing pipelines.

Deployment chain

Layer Value
URL https://drop.thephenom.app
DNS Cloudflare (DNS-only, grey-cloud) — not CF-proxied; server is envoy
Hosting HTTP service (AWS ECS Fargate or App Runner – verify in AWS console)
Region us-east-1
AWS profile phenom
Storage backend AWS S3 (phenom media bucket, us-east-1)

Note: Confirm the exact hosting mechanism (ECS Fargate service name or App Runner service ARN) via the AWS console under ECS or App Runner in us-east-1.

Common operations

Check service health (App Runner)

aws apprunner list-services \
  --profile phenom \
  --region us-east-1 \
  --query 'ServiceSummaryList[?contains(ServiceName,`drop`)].{Name:ServiceName,Status:Status,URL:ServiceUrl}'

Restart / redeploy (App Runner)

# Get the service ARN first
SERVICE_ARN=$(aws apprunner list-services \
  --profile phenom --region us-east-1 \
  --query 'ServiceSummaryList[?contains(ServiceName,`drop`)].ServiceArn' \
  --output text)

# Trigger a new deployment
aws apprunner start-deployment \
  --service-arn "$SERVICE_ARN" \
  --profile phenom \
  --region us-east-1

Restart / redeploy (ECS Fargate, if applicable)

aws ecs update-service \
  --cluster phenom-dev-cluster \
  --service phenom-drop \
  --force-new-deployment \
  --profile phenom \
  --region us-east-1

Check S3 upload bucket

# List recent uploads to verify ingestion is working
aws s3 ls s3://phenom-media-uploads/ \
  --recursive \
  --human-readable \
  --summarize \
  --profile phenom \
  --region us-east-1 | tail -20

View logs

aws logs tail /aws/apprunner/drop-thephenom-app \
  --follow \
  --profile phenom \
  --region us-east-1

Verify it is working

curl -si https://drop.thephenom.app/ | grep -E "^HTTP|^server"
# Expected: HTTP/2 200, server: envoy (no cf-ray — drop is NOT behind CF proxy)

curl -si https://drop.thephenom.app/health | grep -E "^HTTP"
# Expected: HTTP/2 200 (note: /health returns the app HTML, not a JSON payload)

Common failure modes

Symptom Likely cause Remediation
502 / 503 on upload App Runner or ECS task crashed Check CloudWatch logs; restart service
Upload succeeds but file not in S3 IAM role missing S3 write permissions Check task/service IAM role for s3:PutObject on the media bucket
Large file uploads timeout App Runner request timeout (default 120s) Increase timeout in App Runner service configuration
Cloudflare 524 (origin timeout) Origin taking too long for large uploads Check CF proxy timeout settings; consider bypassing CF proxy for large uploads
413 Request Entity Too Large CF or origin payload size limit Increase CF upload limit or implement chunked/multipart upload
Terraform apply reports success but the App Runner config does not change An env_secrets entry points at a secret AppRunnerInstanceRole cannot read. App Runner rejects the entire config update at validation and reports nothing back; Terraform prints Modifications complete. Check that AppRunnerInstanceRole’s SecretsAccess policy covers every ARN in env_secrets. See below.
Upload rejected as “invalid or expired passcode” The tier’s UPLOAD_PASSWORD is not in the password list the presign Lambda validates against (phenom-{project}-{environment}-video-upload-passwords) Rotate both together; they are two halves of one value
Upload succeeds but no row appears in drops HASURA_ENDPOINT or HASURA_ADMIN_SECRET unset. hasura_writer.py:26 returns early and only prints. Confirm both are set on the service

Secrets the drop service reads

AppRunnerInstanceRole’s SecretsAccess policy grants GetSecretValue on phenom-drop/*, phenom-drop-staging/* and phenom-dev-app-secrets-* only. Every ARN referenced from env_secrets must fall inside those prefixes.

HASURA_ADMIN_SECRET is a deliberate copy

Production drop reads HASURA_ADMIN_SECRET from the phenom-drop/env bag, not from phenom-prod-app-secrets where the value originates.

phenom-prod-app-secrets sits outside the instance role’s allowed prefixes, so pointing at it directly triggers the silent rejection above. The alternative fix, adding phenom-prod-app-secrets-* to the role, would also grant drop read access to database_url, jwt_secret, the Apple signing key and push_shared_secret, because Secrets Manager cannot scope a grant to a single JSON field. Drop is internet-facing, so the copy was chosen to keep its reach to the one value it actually needs.

When the Hasura admin secret rotates, update both places. random_password.admin_secret regenerates only when its inputs change, so this is rare, but a stale copy means drop silently stops recording drops. Copy the value across, then force a deployment so the container picks it up:

aws apprunner start-deployment --service-arn "$SERVICE_ARN"

Staging is unaffected: it reads its admin secret from phenom-dev-app-secrets, which the role already covers.