C4 container view — bc-subscriptions (Phase 1, Cloudflare)¶
Generated from a canonical source
This page is a read-only projection of docs/architecture/c4-container.md.
Edit the canonical file, then run npm --prefix tools/project-knowledge-derive run derive.
@generated — mechanically parsed from infra/cloudflare/wrangler.toml,
apps/api/src/types.ts (the Env binding contract), and the sibling
apps/*/wrangler.toml / tools/*/worker/wrangler.toml deploy configs by
tools/arch-derive/. Do not hand-edit —
regenerate with npx tsx tools/arch-derive/derive.ts whenever a wrangler.toml or
the Env interface changes. CI (arch-derive-ci.yml) fails if the committed
docs drift from a fresh derive, which is what makes the derives_from contract
above real (mirrors the pattern proven by tools/erd-derive/ for the ERD).
Anti-fabrication note. Every node below traces to a binding declared in a
real wrangler.toml. ARCHITECTURE.md §0 lists a Cloudflare object-storage
binding as part of the Phase-1 product stack, but no product-runtime
wrangler.toml (apps/api, apps/storefront-svelte, apps/email-consumer)
declares that binding type — only the tools/archaeology/worker/ substrate
tool (not a product deployable) does. This generator therefore correctly
omits that binding from the product container view below; §0 is stale on
this point pending a spec fix, not this diagram.
5 deployable configs parsed, 12 apps/ directories enumerated.
Cross-cutting context: see
ARCHITECTURE.md §0 — Current Architecture (as built).
C4 legend. This is a flowchart-style rendering of a C4 container diagram (GitHub does not render Mermaid
C4Container/C4Contextblocks, so a plainflowchartstands in). Rectangles are containers (independently deployable units); cylinders are datastores; the diagram omits the C4 component layer. Person actors are drawn as((...))circles.
flowchart TD
Merchant((Merchant / Staff))
Subscriber((Subscriber))
subgraph containers ["Product-runtime containers"]
Admin["Admin UI\napps/admin\nCF Pages"]
API["API + Webhooks Worker\napps/api (subs-api)\nCF Workers"]
Portal["Subscriber Portal\napps/storefront-svelte (subs-storefront-svelte)\nCF Pages (assets) + Workers routing"]
Catalyst["Catalyst Storefront Integration\napps/storefront-catalyst\nCF Pages"]
Docs["Docs Site\napps/docs-site (MkDocs)\nCF Pages"]
EmailConsumer["Email Consumer Worker\napps/email-consumer (subs-email-consumer)\nCF Workers (queue consumer)"]
end
subgraph data ["Bindings — infra/cloudflare/wrangler.toml"]
DB[("DB\nD1: subs-api-d1")]
CATEGORY_CACHE[("CATEGORY_CACHE\nKV namespace")]
CHANNEL_CACHE[("CHANNEL_CACHE\nKV namespace")]
EVENTS_QUEUE{{"EVENTS_QUEUE\nQueue: subs-events"}}
RATE_LIMITER[("RATE_LIMITER\nratelimit binding")]
end
Merchant -->|BC admin iframe| Admin
Subscriber -->|hosted portal| Portal
Subscriber -->|storefront widget / PDP| Catalyst
Admin -->|REST, signed JWT| API
Portal -->|service binding SUBS_API| API
Catalyst -->|REST| API
API --> DB
API --> CATEGORY_CACHE
API --> CHANNEL_CACHE
API -->|produces| EVENTS_QUEUE
API --> RATE_LIMITER
EVENTS_QUEUE -->|consumes| EmailConsumer
| Container | Service | Source config |
|---|---|---|
| Admin UI | Cloudflare Pages | apps/admin/ (Vite SPA) |
| API + Webhooks | Cloudflare Workers (subs-api) |
infra/cloudflare/wrangler.toml |
| Subscriber Portal | Cloudflare Pages assets + Workers routing (subs-storefront-svelte) |
apps/storefront-svelte/wrangler.toml |
| Catalyst Storefront Integration | Cloudflare Pages | apps/storefront-catalyst/ |
| Docs Site | Cloudflare Pages | apps/docs-site/mkdocs.yml |
| Email Consumer | Cloudflare Workers (subs-email-consumer) |
apps/email-consumer/wrangler.toml |
| DB (D1) | Cloudflare D1 | infra/cloudflare/wrangler.toml |
| CATEGORY_CACHE (KV) | Cloudflare KV | infra/cloudflare/wrangler.toml |
| CHANNEL_CACHE (KV) | Cloudflare KV | infra/cloudflare/wrangler.toml |
| EVENTS_QUEUE (Queue: subs-events) | Cloudflare Queues | infra/cloudflare/wrangler.toml |
| RATE_LIMITER (ratelimit) | Cloudflare rate-limit binding | infra/cloudflare/wrangler.toml |
Env binding cross-check (apps/api/src/types.ts)¶
The Env interface declares 18 fields (5 required,
13 optional). Bindings above (DB, EVENTS_QUEUE,
RATE_LIMITER, CATEGORY_CACHE, CHANNEL_CACHE) must have a matching field here; the
remainder are secrets (wrangler secret put, not declared in wrangler.toml) or runtime
config vars.
DB
BC_CLIENT_ID
BC_CLIENT_SECRET
BC_API_TOKEN
CREDENTIAL_ENCRYPTION_KEY
CREDENTIAL_ENCRYPTION_KEY_PREV?
CREDENTIAL_KEY_EPOCH?
EVENTS_QUEUE?
RATE_LIMITER?
CATEGORY_CACHE?
CUSTOM_FIELD_CACHE?
CHANNEL_CACHE?
PORTAL_ORIGIN?
SSO_HANDOFF_SECRET?
BC_WEBHOOK_SIGNING_SECRET?
BC_STOREFRONT_TOKEN?
STRIPE_WEBHOOK_SECRET?
NETWORK_UPDATER_WEBHOOK_SECRET?