Channel Communications
Publish once in PowersportOS, route to every subscribed dealer. One engine, four message kinds (blog post, product release, operational alert, safety recall), one shared subscription graph, an adapter pattern that ships a Shopify Admin blog target in v1 and leaves the door open for WordPress, intranet CMS, or generic webhooks without touching the core.
Why this exists
Manufacturer announcements arrive at dealers scattered across email, PDFs, distributor newsletters, and the occasional dealer-extranet login. New product release? Sales-stop on a SKU range? Safety recall? Each one is a separate motion, each one slow, each one easy to miss. From the manufacturer side it is worse: no way to reach the dealer network with one click, no visibility into whether the message landed, no way to force-deliver a recall to dealers who muted the rest.
Channel Communications solves both sides through the brand-subscription graph that already exists on the platform. Authors publish to PowersportOS once. Subscribed dealer tenants receive the content routed through subscription preferences (mode, category filter, schedule offset, rate cap) and either approve in their inbox or land it directly on their Shopify blog. Recalls bypass every mute and obligate an owner or admin to acknowledge within 48 hours, with the full forensic trail captured.
This is one of the few features that turns the multi-tenant network into active infrastructure rather than just shared catalog plumbing. The closest analogues elsewhere (Shopify's distribution apps, WooCommerce content syndication plugins) treat publishing as a per-shop concern with no upstream network. Channel Communications makes the upstream a first-class concept.
The four post kinds
- BLOG_POST
- Standard editorial content. Subscribers approve or decline at their discretion. Default landing on the configured Shopify blog with the author's canonical URL set as a metafield so search engines see one canonical.
- PRODUCT_RELEASE
- Low-drama announcement of new SKUs. Batchable into weekly digests on the subscriber side. Can be auto-generated from 'manufacturer added N parts in last 7 days' (planned).
- OPERATIONAL_ALERT
- Sales-stop on a SKU set, MSRP changes, supply disruption, similar non-safety operational news. Surfaces as a banner plus inbox row on the subscriber portal. Bypasses category filters.
- RECALL
- Safety recall. Force-delivered regardless of mute / category / queue / rate-cap. Owner or admin must acknowledge within 48 hours. Email sent to subscriber technical or billing contact via Resend in parallel to the portal banner.
Actor scope
Authoring is restricted to tenants of type MANUFACTURER, DISTRIBUTOR, or DATA_PROVIDER. Subscriber roles are RETAIL, RESELLER, HYBRID, and STANDARD. The gating sits in two middleware passes (requireAuthorTenant and requireSubscriberTenant) on top of the regular tenant-user authentication, plus a click-through terms gate for either kind that has to land before the first publish or subscription.
The same tenant can be both an author and a subscriber under different tenants in their group: for example, a HYBRID tenant who subscribes to upstream brands while also pushing their own house-brand catalogue to their own storefront. The two surfaces are distinct in the portal (Publisher vs Feeds + Inbox) and the API gates do not conflict.
The subscription graph
Each subscriber configures one row per (author, target) pair in TenantPostSubscription. The row carries the dealer's preferences:
- Mode
- QUEUE waits for explicit approval in the subscriber's inbox; AUTO_PUBLISH schedules straight to the target after the configured offset.
- Category filter
- Posts not tagged with any matching category are skipped. Empty filter means accept everything.
- Schedule offset
- Minimum delay between publish on the author side and landing on the storefront. Lets the subscriber review even in AUTO_PUBLISH mode.
- Rate cap
- Maximum number of non-recall posts per week from this author. Useful for managing a chatty source.
- Publish target
- Which configured destination receives the content. Subscribers can have several targets (one Shopify blog per source, for example) and pick which one each subscription routes to.
- Author-name override
- Optional display attribution for the rendered post. Defaults to the author tenant's display name.
Adapter pattern
The step that takes a publication and lands it on a third-party system goes through a ContentPublishAdapter interface with validate, publish, update, and optional unpublish methods. v1 ships one adapter (Shopify Admin GraphQL, using articleCreate / articleUpdate / articleDelete plus a canonical-URL metafield). Future adapters plug in without touching the core:
- Shopify Admin blog (live in v1)
- Articles posted to a chosen blog on the merchant's store. Requires write_content scope on the existing Dev Dashboard app the merchant set up for product push.
- WordPress (planned)
- Posts via the REST API. Merchant provides application-password credential per WordPress site.
- Intranet CMS (planned)
- Generic HTTP webhook posting a structured payload at a merchant-supplied URL.
- Headless content store (planned)
- Same shape as the webhook but with template substitution + retry logic suited to non-CMS consumers.
A subscriber's tenant.settings.publishTargets holds an array of configured targets. Each subscription references one target, so a tenant can route different sources to different destinations (technical-brand content to a B2B blog, marketing content to a retail blog) without per-post fiddling.
SKU markup and template placeholders
Inside the body HTML, authors can reference a specific part with [[sku:NNN]]. The queue worker resolves each marker to the matching part's title at delivery time per subscriber, so the same post can render different display strings if subscribers have their own naming conventions. Markers that do not resolve are left as plain text rather than erroring the post.
Three template placeholders are substituted in the body and title on delivery, regardless of edit scope:
{store_name}— subscriber's tenant display name.{store_url}— subscriber's primary domain.{publish_date}— actual landing date on that subscriber's storefront.
Edit scopes
Each post carries an allowConsumerEdit value chosen by the author that limits how much the subscriber can change before publishing:
- LOCKED
- No subscriber edits. Content is published verbatim. RECALL posts are always treated as LOCKED regardless of the author's selection.
- MINOR
- Subscriber can adjust template placeholders and small cosmetic details, intended for regional customisation rather than rewriting.
- FULL
- Subscriber can freely modify their local copy. The edited version exists only on the subscriber's storefront and is not synced back to the author; the author is not responsible for the edited content.
Safety recalls in detail
A post classified as RECALL goes through a different code path:
- Bypasses every subscription's category filter, rate cap, mute state, and queue mode.
- Force-schedules for immediate delivery without jitter (other kinds add a small randomisation to spread load).
- Forces
allowConsumerEdit = LOCKEDregardless of the author's selection. - Triggers a parallel email to each subscriber's technical or billing contact via Resend so the message reaches operators who do not live in the portal.
- Surfaces a persistent red
RecallBannerat the top of every subscriber portal page until acknowledged, with a one-click jump to the inbox detail drawer. - Cannot be Declined by the subscriber. The only subscriber action is Acknowledge, which is owner / admin role only.
Acknowledgement records the user, role-at-the-moment-of-ack, IP address, user agent, and timestamp on a RecallAcknowledgement row with a unique constraint on (postId, subscriberId) so repeat clicks are idempotent. The 48-hour SLA per the Channel Subscriber Terms starts at delivery; failure to acknowledge is a contractual breach that may suspend Channel Communications access for the offending tenant.
Legal positioning
Channel Communications moves PowersportOS from "platform hosting our customers' own data" into "platform intermediating third-party content between customers." This carries specific legal obligations under EU law that we address explicitly:
- DSA Article 6 hosting service classification. PowersportOS operates the module as a hosting service provider within the meaning of Article 6 of Regulation (EU) 2022/2065. The Provider stores and transmits content at the author's request and does not endorse, edit, rank, or curate content beyond technical processing required for delivery. Documented in the DSA transparency report.
- Click-through additional terms. Before authoring a first post or creating a first subscription, an owner or admin must accept the relevant module-specific terms (Channel Author Terms or Channel Subscriber Terms) at the current version. Acceptance captures user, IP, and user-agent for the audit trail.
- Notice and counter-notice. Any person can submit a notice of allegedly illegal content to abuse@powersportos.com; the procedure follows DSA Article 16. Counter-notices are accepted from authors whose content was taken down.
- No AI moderation. PowersportOS does not generate, summarise, or moderate content with AI or other automated decision-making systems. Sanitisation of body HTML uses a deterministic allow-list parser and is not content moderation within the meaning of the DSA.
What's deliberately not in v1
- Auto-generated product-release posts. Authors compose product releases by hand in v1. The "auto-generate from new SKUs added in the last 7 days" path is planned but not built.
- Weekly digest mode for subscribers. Schema supports it; UI defers until the second-cohort of users actually asks for it.
- Multi-language posts. Each post is single-language. Multi-region authors publish once per language for now.
- Editorial workflow (drafts, reviewers, approvals on the author side). Author tenants compose and publish directly. Internal approval workflows on the author side are out of scope.
- WordPress / intranet CMS / webhook adapters. The interface exists; the implementations land per real-customer request rather than speculatively.
- End-customer-facing surface. Posts land on the subscriber's storefront. PowersportOS does not host an end-customer-facing reading surface for content of any kind.
Related
- Brand subscriptions — the underlying subscription graph that the content fanout parallels.
- Shopify product push — the other place authors-to-storefront flow exists, with a different shape (operator-triggered batch).
- Channel Author Terms and Channel Subscriber Terms.
- Transparency Report (DSA Article 15-style, published voluntarily).