SmartStore AI — Phase 12 Implementation Guide

Production Hardening & AWS

What got built

backend/app/secrets_aws.py      — Secrets Manager integration
backend/tests/test_secrets_aws.py
infra/ecs-task-definition.json    — ECS Fargate task definition, secrets wired via Secrets Manager

Key design decisions

Tested against moto's mocked AWS, not a hand-rolled fake boto3 client. Every other phase's tests inject a fake client matching some SDK's shape by hand. For AWS specifically, moto provides an actual simulated backend that real boto3 code talks to over its real request/response machinery — test_get_secret_retrieves_real_value_from_mocked_aws is a genuine boto3 create_secret + get_secret_value round-trip, not an assertion about what a hand-written fake returns. This is meaningfully more trustworthy for AWS-specific code, where the SDK's actual request signing/serialization behavior is exactly the kind of thing worth not having to assume.

load_secrets_into_environment sets real environment variables, then app.config.Settings() picks them up exactly like a local .env file. This is the actual point of Volume 4, Chapter 5: application code (config.py) never needs to know or care whether a value came from a .env file or AWS Secrets Manager — that distinction lives entirely in a startup script, called once before the app initializes.

The ECS task definition references individual JSON keys within ONE secret (smartstore-ai/production:DATABASE_URL:: syntax), not six separate secrets. This matches a single secret holding the whole .env-equivalent payload as JSON, consistent with how secrets_aws.py reads it — six separate AWS secrets would work too, but would mean six separate places to rotate and manage instead of one.

Verified test results

tests/test_secrets_aws.py::test_get_secret_retrieves_real_value_from_mocked_aws PASSED
tests/test_secrets_aws.py::test_load_secrets_into_environment_sets_real_env_vars PASSED
tests/test_secrets_aws.py::test_get_secret_raises_clear_error_for_missing_secret PASSED

ecs-task-definition.json: valid JSON, all 6 secrets correctly wired (verified by parsing it directly)

Full suite: 42 passed

Honest limitation

No real AWS account exists in this sandbox — RDS, ElastiCache, ECS Fargate, the actual IAM roles referenced in the task definition (ACCOUNT_ID is a placeholder), and an actual deployed container were not, and could not be, created or tested here. What was verified: the Secrets Manager integration code's actual logic (via moto), and that the task definition JSON is syntactically valid and internally consistent (the same secret name format secrets_aws.py expects).

Setting this up for real

  1. Create the secret: aws secretsmanager create-secret --name smartstore-ai/production --secret-string file://prod-secrets.json
  2. Create an RDS Postgres instance, an ElastiCache Redis instance, and run Phase 1's migrations plus Phase 6's smartstore_app role setup against RDS
  3. Push the backend Docker image to ECR
  4. Create the IAM execution/task roles referenced in ecs-task-definition.json, scoped to read only the one secret (Volume 4, Ch.5's least-privilege principle)
  5. Register the task definition and create an ECS Fargate service behind an Application Load Balancer

What's next

Phase 13 — Launch, Governance & Iteration closes the loop: governance documentation, the PostHog review process, and continuous evaluation running against real production traffic.