You now have the two architectural constraints that matter most: a clear growth-workflow blueprint and a tenant-access policy. This lesson turns them into a deployable system shape: where each responsibility lives, which components may communicate, and where tenant security, AI governance, and operational reliability are enforced.
The goal is not to choose every AWS setting today. It is to create a reference architecture that remains valid as you build lead research, qualification, outreach approvals, CRM synchronization, analytics, and recommendations.
By the end, you will have a diagram and a concise architecture document for a production-oriented, multi-tenant command center.
Start with the architectural decision record
Your system is a hybrid SaaS architecture:
- AWS runs your application compute, async workers, secrets, logs, queues, container images, and tenant-scoped files.
- Supabase provides authentication and the shared PostgreSQL system of record for product data.
- Anthropic Claude is an external model provider, accessed only by trusted backend services.
- GoHighLevel and Airtable are external systems integrated through backend connector code.
- Next.js is the client-facing command center.
- FastAPI is the product’s policy-enforcement and orchestration boundary.
This division matters because it avoids two common failures:
- Putting sensitive logic in the frontend, such as Claude calls, connector tokens, or direct CRM mutation.
- Treating an external system as if it were your canonical product database.
For your SaaS, Supabase is the canonical source of truth for your workflow and governance records. GoHighLevel remains authoritative for live CRM delivery and opportunity state; Airtable is an intake source. FastAPI is responsible for translating between these systems while enforcing the organization boundary from the previous lesson.
Here is the proposed v1 deployment decision:
| Concern | Chosen component | Architectural rule |
|---|---|---|
| Client dashboard | Next.js on AWS Amplify Hosting | No provider keys, service keys, or connector credentials reach the browser. |
| Authentication | Supabase Auth | Users authenticate globally; FastAPI validates each request and resolves active organization membership. |
| Product API | FastAPI on Amazon ECS Fargate | All protected product operations pass through FastAPI. |
| Long-running automation | Python worker on ECS Fargate | Workers consume only durable jobs and re-validate tenant context before acting. |
| Durable job queue | Amazon SQS with dead-letter queue | Queue messages identify work; they should not carry unnecessary customer data. |
| Product data | Supabase Postgres | Tenant-owned tables use organization_id, RLS, and tenant-consistent relationships. |
| AI features | Claude API from FastAPI or workers | Claude is never called directly from the browser and never receives authority to act on its own. |
| Integration credentials | AWS Secrets Manager | Credentials are decrypted only by narrowly permitted backend task roles. |
| Files and export artifacts | Amazon S3 | The API issues scoped access; object paths and policies remain tenant-aware. |
| Observability | Amazon CloudWatch | API, worker, queue, and connector failures are observable by tenant and run. |
This makes the central boundary easy to remember:
Next.js presents the workspace; FastAPI enforces product policy; workers perform durable work; Supabase preserves the tenant-scoped record of what happened.
Study the AWS execution model
Guidance for Building a Containerized and Scalable Web ...
Read AWS’s reference guidance to anchor the ECS, load-balancing, autoscaling, and operational parts of your design. It is a general three-tier example, so focus on the operational roles of the services rather than copying its identity or data-store choices.
In Overview, read the overview and inspect the accompanying architecture diagram. Then, in Well-Architected Pillars, find the Reliability discussion. Read the ALB and Fargate discussion. Relate the load-balanced service to FastAPI and the independently scaled background service to your automation worker.
A useful distinction is that API scaling and worker scaling solve different problems.
- The FastAPI service scales with interactive demand: dashboard reads, approval actions, contact edits, and short AI drafting requests.
- The worker service scales with queued work: imports, enrichment, CRM synchronization, multi-step automation, and retries.
- The SQS queue absorbs bursts. A large Airtable import should not slow an operator trying to review an outreach draft.
- A dead-letter queue preserves jobs that repeatedly fail, rather than retrying them forever without visibility.

Your API and worker should run as separate ECS services even if they initially share much of the same Python package. They have different inbound access, scaling signals, timeout profiles, and permissions:
| Service | Receives | May initiate | Must not do |
|---|---|---|---|
| FastAPI API | Authenticated browser requests and verified webhooks | Short database work, Claude requests, job submission | Block on a long import or expose credentials |
| Automation worker | SQS messages only | Connector calls, long-running research, retries, status updates | Accept public internet traffic |
| Webhook handler | Signed external provider webhook requests | Verification, idempotent event persistence, downstream job submission | Treat a provider payload as already authorized tenant data |
For v1, deploy FastAPI and worker tasks in private subnets. An internet-facing Application Load Balancer terminates HTTPS and routes only public API and webhook requests to FastAPI. The worker has no public listener.
Because Claude, Supabase, GoHighLevel, and Airtable are managed external services, private tasks need controlled outbound network access. The important principle at this stage is not the exact networking product selection; it is that outbound access is deliberate, logged where practical, and paired with least-privilege credentials.
The end-to-end reference architecture
The following is the architecture to place in your product documentation. It deliberately separates the public UI, trusted application runtime, managed data, and external providers.
Read the diagram from the trust boundaries inward:
- The browser is untrusted. It can request actions and supply an active organization identifier, but it cannot establish its own authority.
- Next.js renders the command center and manages client experience. It does not become the location for privileged integrations.
- FastAPI is the public product boundary. It validates tokens, resolves the organization, checks role and workflow state, and decides whether work is immediate or asynchronous.
- The worker is trusted infrastructure, but still not omnipotent. It must re-load the automation run and verify its organization, connector connection, state, and allowed action.
- Supabase stores the durable, tenant-scoped evidence of work: contacts, campaigns, approvals, events, automation runs, outputs, and audit entries.
- Claude and integration providers are outside your trust boundary. Inputs are minimized, validated, and tied to one authorized organization.
Keep Claude behind the service boundary
For product automation, Claude is a dependency of your backend, not a frontend feature.

The diagram’s main lesson is ownership: your application owns business rules and tool definitions. An AI integration SDK can reduce plumbing, but it cannot decide whether an operator may access Client A’s CRM record or activate Client B’s campaign.
Your v1 rule should therefore be:
- Next.js may show a Claude-generated result.
- FastAPI or a worker sends the Claude request.
- FastAPI constructs the request using validated tenant configuration, source evidence, and user intent.
- FastAPI validates the response before storing or displaying it.
- A model-proposed tool action returns to backend code for authorization.
- Connector code, not Claude, performs a GoHighLevel or Airtable action.
How To Build an API with Python (LLM Integration, FastAPI, Ollama & More)
Watch “How To Build an API with Python (LLM Integration, FastAPI, Ollama & More)” by Tech With Tim for the core reason to place an API between a frontend and a language model: central control of secrets, access, and usage.
Watch the opening rationale. Focus on the architectural principle rather than the tutorial’s particular local-model tooling: an application API is where you protect model credentials and apply user-level access or usage controls.
Use two execution modes for AI features:
| Mode | Suitable examples | Where it runs |
|---|---|---|
| Interactive | Draft outreach copy, summarize review evidence, answer a dashboard question | FastAPI, with a strict timeout and optional streamed response |
| Durable | Research a lead list, enrich many companies, generate a campaign asset batch, retry a failed external API request | Worker, initiated from SQS and recorded as an automation run |
A short interactive request can return a validated draft to a reviewer. A lead-enrichment batch should create a durable run first and return promptly with a status the command center can monitor.
Make the four key flows explicit
An architecture diagram is valuable only if the important flows have clear contracts. These are the four that your product needs from day one.
1. Authenticated dashboard request
- The user signs in through Supabase Auth and receives a session access token.
- Next.js renders the workspace and its typed API client includes that token when calling FastAPI.
- FastAPI validates the token, resolves the requested active organization through an active membership, and checks the required permission.
- FastAPI queries only records belonging to that organization and returns a role-appropriate response.
- Supabase RLS remains a second enforcement layer for browser-accessible data and accidental query mistakes.
The browser should not use a Supabase service key, AWS credential, GoHighLevel credential, Airtable token, or Anthropic API key.
2. Claude-assisted product action
Consider an operator who asks for an outreach draft.
- The browser sends the prospect ID, campaign context, and requested action to FastAPI.
- FastAPI validates the user, role, active organization, prospect ownership, campaign state, and consent-related workflow conditions.
- FastAPI retrieves approved tenant context and evidence from Supabase.
- FastAPI sends only the necessary information to Claude using a typed request.
- FastAPI validates the returned structure, stores the draft as a tenant-owned version, and records model usage metadata.
- The UI displays the draft for review; it does not automatically publish it.
Later lessons will make the prompt contract, response schema, tool allowlist, cost metering, and prompt-injection defenses explicit. The architecture already reserves the correct enforcement point for all of them.
3. Durable automation run
Consider importing 5,000 leads from Airtable or synchronizing campaign results from GoHighLevel.
- FastAPI authorizes the request and inserts an
automation_runin Supabase with the activeorganization_id, initiator, action type, and idempotency key. - FastAPI sends a minimal SQS message containing the run ID and enough routing metadata to locate it safely.
- The worker receives the message and re-loads the automation run from Supabase.
- The worker verifies state, tenant ownership, connector scope, and idempotency before any external call.
- The worker records step status and connector attempts in Supabase.
- If retries are exhausted, SQS places the message in the dead-letter queue and CloudWatch raises an operational signal.
The queue should not become a hidden database. Store the durable state in Supabase; use SQS to reliably schedule processing.
4. Incoming integration webhook
GoHighLevel may send contact, opportunity, or delivery events to your platform.
- GoHighLevel sends a webhook to a dedicated FastAPI webhook route behind the Application Load Balancer.
- FastAPI verifies the provider signature and identifies the linked tenant integration connection.
- FastAPI persists a provider event ID for idempotency before processing the business payload.
- FastAPI records a normalized tenant-scoped event in Supabase.
- If follow-up work is required, FastAPI submits a worker job rather than blocking the webhook acknowledgment.
Never identify a tenant from a provider payload field alone. The integration connection configuration, signature verification result, and stored external-account linkage must all agree on the organization.
Frontend environment and deployment boundaries
You have chosen AWS Amplify Hosting for the production Next.js client, not a self-hosted Next.js container. That is a good v1 choice because it keeps frontend hosting operationally separate from your Python services.
Still, the Next.js environment-variable rules are essential: whether the app is hosted by Amplify or a container platform, a value exposed to browser JavaScript is public by design.
Read the “Environment Variables” section in the official Next.js documentation. Although this architecture uses Amplify Hosting rather than a self-hosted Next.js service, the public-versus-server environment boundary and promotion principle apply directly.
In Environment Variables, read the environment-variable guidance. Pay particular attention to the NEXT_PUBLIC_ convention: treat every such value as visible to a user of your SaaS.
For the command center, the only frontend configuration values likely to be public are values such as:
- The API base URL, for example
https://api.yourdomain.com - The Supabase project URL
- The Supabase anonymous browser key
- A non-secret deployment or release identifier
These are never public:
ANTHROPIC_API_KEY- Supabase
service_rolekey - GoHighLevel access tokens
- Airtable personal access tokens
- Webhook signing secrets
- Encryption keys
- AWS access credentials
- Database passwords
Put private runtime values in AWS Secrets Manager, and grant each ECS task role access only to the secrets it requires. For example, a worker that performs Airtable intake should not automatically be able to read a GoHighLevel credential for every client.
Do not add Redis merely because Next.js documentation discusses shared caches for multi-instance self-hosting. Amplify avoids that specific self-hosted-cache decision. Add a shared cache only when you identify a real performance need and can define tenant-safe cache keys and invalidation behavior.
Turn the diagram into a build artifact
Create this document now:
docs/product/reference-architecture.md
Use this outline:
# Reference Architecture
## Purpose
- Multi-tenant B2B growth command center
- AWS execution environment with Supabase as the product data system of record
- Explicit non-goals for v1
## System diagram
- Insert the Mermaid diagram from this lesson
- Record diagram version and last-reviewed date
## Component responsibilities
- Next.js on Amplify
- FastAPI API service
- Python worker service
- Supabase Auth and Postgres
- SQS and dead-letter queue
- Secrets Manager, S3, ECR, CloudWatch
- Claude, GoHighLevel, and Airtable
## Trust boundaries
- Browser
- Public API and webhook routes
- Private ECS services
- Managed data services
- External AI and integration providers
## Request and event flows
- Authenticated dashboard request
- Claude-assisted request
- Durable automation run
- Incoming webhook
## Tenant-safety invariants
- FastAPI derives active organization from validated membership
- Every worker job re-validates organization context
- External connection belongs to the same organization as the record
- Browser never receives privileged credentials
- Claude has no independent authority to mutate product or CRM records
## Deployment and operations
- Amplify for Next.js
- ALB plus ECS Fargate for FastAPI
- ECS Fargate worker scaled from SQS metrics
- ECR for backend images
- CloudWatch logs, metrics, alarms, and run correlation
- Secrets Manager for runtime credentials
## Open decisions
- Exact AWS networking layout
- Object retention and export-deletion policy
- Tenant rate limits and usage budgets
- Streaming UX requirements
Before accepting the architecture, use this checklist:
- The browser has no direct route to Claude, GoHighLevel, Airtable, Secrets Manager, or privileged Supabase access.
- Every external CRM or AI action passes through FastAPI or the worker.
- Every tenant-owned action can be tied to an active organization and, when relevant, an automation run.
- FastAPI and workers are separate ECS services with distinct scaling and permissions.
- Webhooks are verified and idempotent before they affect the product state.
- Supabase remains the source of truth for product workflow, approvals, events, and run history.
- The architecture includes a durable failure path through SQS, dead-letter handling, and CloudWatch visibility.
Key takeaways
Your command center is a multi-tenant system with a deliberately narrow control plane:
- Next.js on Amplify provides the client workspace.
- Supabase Auth identifies users; FastAPI validates tokens, memberships, roles, and workflow state.
- Supabase Postgres holds canonical product and governance data under tenant-scoped controls.
- FastAPI on ECS Fargate handles interactive, authenticated API work and verified webhooks.
- Workers on ECS Fargate execute durable automation from SQS, with run state stored in Supabase and failures routed to a dead-letter queue.
- Claude, GoHighLevel, and Airtable are external dependencies, reached only through trusted backend paths.
- Secrets Manager, S3, ECR, and CloudWatch provide the operational backbone for a deployable AWS system.
Next, you will scaffold the repository that embodies these boundaries: a FastAPI backend and a Next.js frontend, organized so this reference architecture can become working code rather than remain a diagram.
Can't find a good explanation? Sign up and we'll make it for you
Sign up