Can CeylanVienna-based, globally curious.
Learn/Product Thinking

The distribution map pattern: one config that drives all publishing outputs

Multi-platform publishing workflows accumulate per-platform hacks over time. The distribution map pattern replaces them with a single declarative config: topic → platform list, which becomes the source of truth for what gets generated and where it goes.

2026-04-25·3 min read·intermediate

How multi-platform publishing goes wrong

Content publishing to multiple platforms starts simple: write an article, post it to one place. Then you add a second platform, and a third. Each addition gets its own if-statement, its own hardcoded platform name in the generation route, its own UI card in the admin dashboard.

Six months later, the code looks like this:

// scattered across multiple routes and components:
if (topic === "Tech & AI") {
  await generateLinkedInPost(article);
  await generateTwitterPost(article);
}
if (topic === "Finance") {
  await generateLinkedInPost(article);
  await generateMediumDraft(article);
}
// ... and so on

Every new platform requires changes in multiple places. Adding a platform to one category means auditing every file that checks topic names. Removing a platform leaves dead code. The system has no single source of truth for "which platforms does this category use?"

The distribution map

The fix is a declarative map stored in one place:

const DEFAULT_DISTRIBUTION_MAP: Record<string, string[]> = {
  "Tech & AI":          ["devto", "hashnode", "linkedin", "twitter", "reddit"],
  "Finance":            ["medium", "substack", "linkedin", "twitter"],
  "Health":             ["medium", "substack", "linkedin", "instagram"],
  "Politics & Society": ["medium", "substack", "linkedin", "twitter", "reddit"],
};

Every generation route, every UI component, and every publishing flow reads from this map — never from hardcoded platform lists.

export function getPlatformsForTopic(
  map: Record<string, string[]>,
  topic: string
): string[] {
  return map[topic] ?? [];
}

Adding a platform to a category is now a one-line change in the map. Nothing else in the codebase needs to change.

The map as the source of per-article workflow state

The distribution map does more than control generation. It becomes the input to a per-article workflow record that tracks what has been generated, what is ready, and what has been published.

function buildDistributionState(article, distributionMap, socialPosts) {
  const requiredPlatforms = getPlatformsForTopic(distributionMap, article.topic);

  return Object.fromEntries(
    requiredPlatforms.map((platform) => [
      platform,
      {
        required: true,
        textStatus: hasTextFor(platform, socialPosts) ? "ready" : "missing",
        assetStatus: hasAssetsFor(platform, socialPosts) ? "ready" : "not_needed",
        publishStatus: "not_ready",
      }
    ])
  );
}

The article now knows exactly which platforms it needs, what is done, and what is missing — derived from the map, not from scattered if-statements.

Category changes do not rewrite existing articles

One important rule: if the distribution map changes after an article is saved, the article's existing workflow state should not be silently rewritten.

The map is captured at article-creation time and stored per-article. Later map changes apply to new articles, not retroactively to old ones.

This prevents a frustrating class of bug: you change a category's platform list, and suddenly articles you already published are marked as missing platforms you never intended them to use.

Extending the map to drive UI

Because the map is the source of truth, the admin UI can be generated from it rather than hardcoded:

const platforms = getPlatformsForTopic(distributionMap, article.topic);

return platforms.map((platform) => (
  <PlatformCard
    key={platform}
    platform={platform}
    state={article.distributionState[platform]}
  />
));

No hardcoded platform list in the UI. Add a platform to the map, and it appears automatically in the dashboard for that category.

The broader principle

A distribution map is an instance of a general pattern: routing configuration as data, not code. Anywhere you find if-statements that check a category, type, or tag to decide what to do, ask whether those decisions could be captured in a lookup table instead.

The lookup table is easier to read, easier to change, and makes the system's behavior inspectable at a glance — without reading the code.

More like this, straight to your inbox.

I write about Product Thinking and a handful of other things I actually care about. No schedule, no filler — just when I have something worth saying.

More on Product Thinking

Two AI agents need one live memory file

If two AI coding agents share a repo but not a single mutable memory layer, the user becomes the message bus. Here is the failure mode, why it happens, and the operating model that fixes it.

Read the broader essay

Article

The Silence of Good People: Black Emancipation, European Assimilation, and Why Raising Your Voice Still Costs Something

Austria just cut funding to ZARA, one of the only organisations consistently documenting racism in the country — and the silence from good people is exactly the problem.

Article

The 'Foreigners and Crime' Argument Is Designed to Fail You

When a chancellor says 'little pashas' out loud, the debate isn't really about crime — it's about who gets to be seen as human first.

If this raised a question, I'd be happy to talk about it.

Find me →
← Back to Learn