Architecture Overview¶
Subscribe Flow is a multi-tenant SaaS platform following a layered architecture with strict per-organization data isolation.
System Architecture¶
graph TB
subgraph "Layer 1: Clients"
PC[Preference Center UI]
AD[Admin Dashboard]
SDK[SDK / API Client]
MCP[MCP Server]
EXT[External Systems]
end
subgraph "Layer 2: API Gateway"
FA[FastAPI Application]
AUTH[Dual Auth: Magic Link + API Key]
RL[Per-Org Rate Limiter]
VAL[Request Validation]
TENANT[Tenant Resolution]
end
subgraph "Layer 3: Business Logic"
SS[Subscriber Service]
TS[Tag Service]
PS[Preference Service]
RS[Resend Sync Service]
WH[Webhook Service]
OS[Organization Service]
BS[Billing / Payment Service]
US[User Service]
MLS[Magic Link Service]
DS[Domain Service]
EU[Email Utils]
end
subgraph "Layer 4: Data Layer"
REPO[Repositories]
CACHE[Cache Layer]
PG[(PostgreSQL)]
RD[(Redis)]
end
subgraph "Layer 5: External Services"
RESEND[Resend API]
STRIPE[Stripe API]
WEBHOOKS[Webhook Endpoints]
end
PC --> FA
AD --> FA
SDK --> FA
MCP --> FA
EXT --> FA
FA --> AUTH
AUTH --> TENANT
TENANT --> RL
RL --> VAL
VAL --> SS
VAL --> TS
VAL --> PS
VAL --> WH
VAL --> OS
VAL --> BS
VAL --> US
SS --> REPO
TS --> REPO
PS --> REPO
OS --> REPO
BS --> REPO
US --> REPO
SS --> CACHE
MLS --> CACHE
RS --> RESEND
DS --> RESEND
BS --> STRIPE
WH --> WEBHOOKS
REPO --> PG
CACHE --> RD Multi-Tenant Isolation¶
All data access is scoped to the authenticated organization. The tenant resolution flow works as follows:
- API Key Auth: API key is looked up, the associated
organization_idis extracted - Magic Link Auth (Dashboard): User session contains
organization_idviaOrganizationMembers - Service Layer: Every service method receives the
organization_idand filters all queries accordingly - Database: All tenant-scoped tables include an
organization_idforeign key with indexed lookups
sequenceDiagram
participant C as Client
participant G as API Gateway
participant A as Auth (Dual)
participant T as Tenant Resolution
participant S as Service Layer
participant R as Repository
participant D as Database
C->>G: HTTP Request
G->>A: Authenticate (API Key or Session)
A->>T: Resolve Organization
T-->>G: Org Context (organization_id, tier, limits)
G->>S: Business Operation (org-scoped)
S->>R: Data Operation (filtered by org_id)
R->>D: SQL Query (WHERE organization_id = ...)
D-->>R: Result
R-->>S: Domain Object
S-->>G: Response DTO
G-->>C: HTTP Response Components¶
Layer 1: Clients¶
| Component | Description |
|---|---|
| Preference Center UI | Embeddable React component for self-service |
| Admin Dashboard | React SPA dashboard for administrators |
| SDK | TypeScript/Python SDK for developers |
| MCP Server | Model Context Protocol server for LLM agents |
| External Systems | CRM, e-commerce, marketing automation |
Layer 2: API Gateway¶
| Component | Responsibility |
|---|---|
| FastAPI | Request routing, OpenAPI documentation |
| Dual Auth | Magic Link sessions (Dashboard) + API Key auth (SDK/API) |
| Tenant Resolution | Extract organization_id from auth context |
| Per-Org Rate Limiter | Rate limiting scoped to organization tier |
| Validation | Pydantic request/response validation |
Layer 3: Business Logic¶
| Service | Responsibility |
|---|---|
| Subscriber Service | CRUD, validation, status management (org-scoped) |
| Tag Service | Tag hierarchy, categories (org-scoped) |
| Preference Service | Subscription logic, audit trail |
| Resend Sync | Bidirectional synchronization |
| Webhook Service | Event dispatching (org-scoped) |
| Organization Service | Org CRUD, settings, member management |
| Billing / Payment Service | Stripe integration, tier management, usage tracking |
| User Service | User CRUD, org membership |
| Magic Link Service | Magic link generation, email sending, token verification |
| Domain Service | Custom email domain verification via Resend API |
| Email Utils | Per-org from address resolution, send domain management |
Layer 4: Data Layer¶
| Component | Technology | Purpose |
|---|---|---|
| Repositories | SQLAlchemy | Data access abstraction |
| Cache | Redis | Session, rate limits, magic link tokens |
| PostgreSQL | PostgreSQL 15 | Primary data storage |
| Redis | Redis 7 | Caching, queue, Celery broker |
Layer 5: External Services¶
| Service | Integration |
|---|---|
| Resend API | Email sending, contact sync, domain verification |
| Stripe API | Billing, checkout, customer portal, webhooks |
| Webhooks | Event notifications to customer endpoints |
Dual Authentication¶
Subscribe Flow supports two authentication mechanisms:
| Method | Used By | Flow |
|---|---|---|
| Magic Link | Admin Dashboard users | Request -> Email -> Click -> Session cookie |
| API Key | SDK, API clients, MCP | X-API-Key: sf_live_xxx header |
Both methods resolve to an organization_id that scopes all subsequent operations.
Design Principles¶
1. API-First¶
The API is the primary interface. All functionality is available via REST.
| Text Only | |
|---|---|
2. Multi-Tenant by Default¶
Every resource belongs to an organization. There is no global data access.
3. Event-Driven¶
Changes trigger events that are communicated via webhooks:
flowchart LR
A[Preference Change] --> B[Event Created]
B --> C[Webhook Dispatched]
C --> D[External System] 4. Audit Trail¶
Every change is logged:
Scaling¶
Horizontal Scaling¶
- API Server: Stateless, scales horizontally without limits
- Background Workers: Celery for async tasks
- Celery-Beat: Scheduled tasks (e.g., monthly email counter reset)
- Database: Read replicas for read operations
Caching Strategy¶
flowchart LR
A[Request] --> B{Cache Hit?}
B -->|Yes| C[Return Cached]
B -->|No| D[Query DB]
D --> E[Update Cache]
E --> F[Return Response]