Part 7 of 7 · AWS autoposting series ~3 min read

Engineering reference: the full architecture

Same system as the rest of the series, drawn purely for engineers. Service names, resource identifiers, region, and the actual flow operations — everything you’d need to recreate this in your own AWS account.

Posts 1–6 walk through the system in plain language. This page is the dense version — no softening, just the architecture as you’d sketch it on a whiteboard during a design review.

Full technical architecture: AWS autoposting + RAG reply system in ap-southeast-1 A detailed engineering diagram of the entire system. Three external surfaces at the top: GitHub (repo and Actions runner, OIDC token requestor), Google Drive (shared folder per page, files.watch push notifications), and Facebook (Page using Graph API and webhooks, both inbound webhook events and outbound posts/replies). All running in a single AWS account in region ap-southeast-1 (Singapore). The AWS account contains five subsystems. Build and Deploy strip at the top: GitHub Actions exchanges with IAM OIDC Provider for the github.com identity provider, assumes an IAM Role with a trust policy scoped to repo:owner/repo:ref:main, and runs SAM/CloudFormation to update the build-allanninal-prod stack. Three runtime subsystem columns below. Posting (scheduled): EventBridge Scheduler fires on cron 0 9, 12, 18 daily, invokes Lambda fn-publisher (python3.12 on arm64), which queries DynamoDB tbl-post-queue, fetches the page token from Secrets Manager secret/fb-page-token, runs the five-stage guardrails using Bedrock amazon.titan-embed-text-v2:0 and global.anthropic.claude-haiku-4-5, and POSTs to the Facebook Graph API at /{page-id}/feed. KB Sync: a Drive files.watch notification hits Lambda Function URL fn-drive-webhook, which invokes Lambda fn-sync to validate and write the document to S3 kb-raw bucket (versioned, partitioned by page). The S3 PutObject event triggers Lambda fn-chunker which embeds chunks via Bedrock Titan and upserts vectors to S3 Vectors index vec-kb per page (S3 Vectors went GA in December 2025). If the document fails validation, the Sync Lambda comments back into the Drive doc and the old version stays live. Reply (RAG): Meta webhook events hit Lambda Function URL fn-meta-webhook which verifies HMAC SHA256 and returns 200 within milliseconds, then enqueues to SQS q-replies (with q-replies-dlq dead letter queue). Lambda fn-reply-handler picks up the message, embeds the question via Bedrock Titan, searches the S3 Vectors index for top-k chunks, calls Bedrock global.anthropic.claude-haiku-4-5 with the retrieved chunks as grounded context, enforces a citation requirement, and POSTs the reply via the Graph API. Cross-cutting bottom strip: DynamoDB tbl-audit logs every action; CloudWatch Logs are configured with RetentionInDays of 7 across every log group; an SNS topic t-alarms emails the operator on failures; AWS Budgets has a $10 monthly alarm; Lambda fn-token-refresh runs on a separate weekly cron 0 3 SUN to rotate the Page Access Token in Secrets Manager before its 60-day expiry. GitHub github.com/owner/repo Actions runner · OIDC token requestor Google Drive shared folder per page files.watch push notifications Facebook Page (Graph API + webhooks) in: webhook events · out: posts/replies AWS Account Region: ap-southeast-1 (Singapore) · Bedrock via Global CRIS Build & Deploy IAM OIDC Provider token.actions.githubusercontent.com IAM Role trust: repo:owner/repo:ref:main SAM / CloudFormation stack: build-allanninal-prod git push & request token Actions runner AssumeRole sam deploy → creates stack resources below Posting (scheduled) EventBridge Scheduler cron(0 9,12,18 * * ? *) AWS Lambda fn-publisher (py3.12, arm64) Query DynamoDB tbl-post-queue GetSecretValue Secrets Manager secret/fb-page-token InvokeModel Bedrock (5-stage guardrails) amazon.titan-embed-text-v2:0 global.anthropic.claude-haiku-4-5 → Graph API: POST /{page-id}/feed KB Sync Lambda Function URL fn-drive-webhook files.watch notification AWS Lambda fn-sync (validates content) PutObject S3 kb-raw/{page}/*.md (versioned) PutObject event AWS Lambda fn-chunker → Bedrock Titan v2 PutVectors S3 Vectors vec-kb-{page} (GA Dec 2025) → Drive comment-back if invalid Reply (RAG) Lambda Function URL fn-meta-webhook (HMAC SHA256) Meta webhook events SendMessage SQS q-replies + q-replies-dlq AWS Lambda fn-reply-handler embed → query Bedrock Titan + S3 Vectors titan-embed-v2 → top-k chunks InvokeModel (grounded) Bedrock Haiku 4.5 global.anthropic.claude-haiku-4-5 → Graph API: POST reply (citation required) read brain Cross-cutting DynamoDB tbl-audit (every action) CloudWatch Logs RetentionInDays: 7 SNS t-alarms (email) AWS Budgets budget-monthly: $10 Lambda fn-token-refresh EventBridge cron(0 3 ? * SUN *) → rotates Page Access Token in Secrets Manager
Fig 7. Full architecture, ap-southeast-1. White boxes = AWS resources; dashed AWS container; dashed grey boxes = subsystem groupings; dashed grey arrow = cross-subsystem data dependency.

Read this top-down, then column-by-column

Top row is the three external surfaces. Below it, the AWS account contains five subsystems: Build & Deploy across the top, three runtime columns (Posting, KB Sync, Reply) in the middle, and a Cross-cutting strip at the bottom. The dashed grey arrow from the KB Sync output to the Reply column shows the only cross-subsystem data dependency — the Reply pipeline reads the same vectors index that KB Sync writes.

Naming conventions used in the diagram

  • Lambda functions: fn-<purpose> — e.g. fn-publisher, fn-sync, fn-reply-handler.
  • DynamoDB tables: tbl-<name>.
  • SQS queues: q-<name> with paired q-<name>-dlq.
  • SNS topics: t-<name>.
  • S3 Vectors indexes: vec-<purpose>-{page} — one index per Facebook page.
  • S3 buckets: kb-raw partitioned by {page}/ prefix.

Region and Bedrock model access

Everything runs in ap-southeast-1 (Singapore) for low latency from the Philippines. Bedrock model invocations use the Global cross-Region inference profile (model IDs prefixed with global.) — data at rest stays in Singapore; inference may route to other regions for capacity. Pricing is the same as on-demand Singapore pricing.

What’s deliberately not on the diagram

  • IAM policy details — per-Lambda execution role inline policies are minimal (one secret, one table, one bucket as appropriate).
  • Per-page configuration JSON in S3 (read by Publisher and Reply Lambdas; lets you tune thresholds without redeploys).
  • X-Ray tracing — on for the Reply Lambda only, sampling 10%.
  • The CloudFormation parameter for Bedrock model ID is templated, so swapping models doesn’t require code changes.

If you’re recreating this

Start with Build & Deploy alone (a single Lambda, no triggers). Once git push reliably updates an empty stack, add Posting next. Don’t add Reply until KB Sync is producing a usable vectors index — the Reply pipeline depends on that brain existing. Cross-cutting (audit, logs, alarms, budget) goes in from day one.

All posts