Home / Wiki
Knowledge Base

ContentFlow Wiki

The shared brain for building on ContentFlow, concepts, architecture, and the words we use. If the docs tell you how, the wiki tells you why.

Concepts

Blocks vs. instances

A block type is a UI shape defined in code (a hero, a card, a carousel). A block instance is that shape filled with content, a specific hero on your home screen. Types are shipped by developers with the CLI; instances are managed by anyone in the dashboard.

Channels

A channel is where a block is delivered: push, whatsapp, sms, popup, or in-app. Popup and in-app render as block-style image cards; SMS and WhatsApp run through configured Twilio channels.

Segments & targeting

A segment is an audience. Blocks and campaigns target a segment, a locale, or a single user. The special "All users" segment requires contacts to have phone + consent before SMS/WhatsApp can reach them.

Architecture

ContentFlow runs as a small set of services behind an API gateway. Your app only ever talks to the SDK, which talks to the gateway.

data flow
Your app
   │  @contentflow/sdk  (key → tenant)
   ▼
API Gateway  /api/v1
   ├──► auth-service     workspaces, members, keys
   ├──► content-service  blocks, instances, sync
   ├──► strings-service  extract, translate, deliver
   └──► campaign-service segments, dispatch
             │
             ▼
        MongoDB  (per-tenant data)
i Multi-tenantEvery request is scoped to the tenant behind your key. Data never crosses workspace boundaries.

Content lifecycle

  1. Define, a developer adds a block type in code and runs cf push.
  2. Fill, someone creates an instance in the dashboard (or seeds it via /cards/sync).
  3. Target, pick a segment, locale, and channel.
  4. Publish, the block goes live; content.published fires.
  5. Sync, apps pull it on next cf.sync(), no redeploy.
  6. Roll back, revert instantly if needed; content.rolledback fires.

Glossary

TermDefinition
KeyWorkspace credential (cf_live_ / cf_test_) that resolves to one tenant + env.
TenantA workspace. All data is scoped to it.
Block typeA UI shape defined in code and shipped with the CLI.
Block instanceA filled block, managed in the dashboard or seeded via API.
externalIdStable id you set so sync stays idempotent (no duplicates).
HandshakeA check that confirms key + tenant + env resolve before shipping.
ChannelDelivery surface: push, WhatsApp, SMS, popup, in-app.
SegmentAn audience a block or campaign targets.

FAQ

Do I need to redeploy my app to change content?

No. Publishing an instance makes it live on the next cf.sync(). That's the whole point.

Why is my block empty after conversion?

Almost always a failed handshake or a mismatched key/env. Run cf.handshake() and confirm the key prefix matches your environment.

Why didn't my SMS / WhatsApp campaign deliver?

The audience likely had zero contacts with phone + consent, or the tenant has no configured Twilio channel. See Campaigns.

Can non-developers manage content?

Yes. Developers define block types in code; anyone can create and edit instances in the dashboard.

← BACK TO DOCS HOME