Integration modes

Integration modes

Cobuntu has one rule that decides who sees what. Everything else in this page — three named modes, two override layers, a custom-routes bypass — is configuration on top of that rule.

If you only remember one thing from this page, remember this:

Effective visibility = page.visibility ?? community.visibility. If the resolved value is PUBLIC, anyone sees the page. If MEMBERS_ONLY, only an ACCEPTED member of the community does.

Everything below is a consequence of that line.


The rule that runs them all

Two columns drive every decision:

  • visibility (community default) — the org-wide default. PUBLIC or MEMBERS_ONLY.
  • Per-page override — a specific page (feed, events, marketplace, members, …) can be set to PUBLIC or MEMBERS_ONLY independently, or left unset to fall through to the community default.

The resolver runs the same way on every request:

That's the whole gate. The three modes you'll see below are just names for the three useful shapes that resolver naturally produces when you set the two columns differently.


The three modes at a glance

PortalStorefrontHybrid
community.visibilityMEMBERS_ONLYPUBLICeither
Page overrides?nonenoneone or more rows
What anon seesgate page everywhereevery pagemixed, per-page
SEO / GEOnone (noindex)maximumpartial — public pages indexed
SDK complexityminimalminimalneeds usePageAccess
Typical use casepaid mastermind, private clubcontent-led brand, public marketplacecurated community with a members-only inner ring

The mode is derived from those two columns, not stored — flip either column in cobuntu-admin and the mode label changes on the next page-load.


Portal

A private members-only space. Like a Slack workspace or a Discord server — nobody outside sees anything.

Configuration. Community default visibility = MEMBERS_ONLY, no page-level overrides. Every canonical page (/feed, /events, /marketplace, /members, /atlas, /blog, /conversations, plus the viewer-scoped /hub, /profile, /settings) inherits MEMBERS_ONLY and gates accordingly.

What the visitor experiences.

Why pick it.

  • Privacy guarantee — no member data leaks through any surface.
  • Compliance-friendly: GDPR / DSA "private community" semantics are trivial to argue.
  • Simple SDK story: landing nav is either "go to /login" or "logged in, render everything."

Cost.

  • Zero SEO / GEO discoverability. Cobuntu pages emit X-Robots-Tag: noindex (opens in a new tab). Search engines see only your landing.
  • Funnel is fully customer-owned: the landing has to convert anon → signup → application, because Cobuntu won't show anything before that.

SDK implication. The landing only needs to know "is this visitor logged in?" The cobuntu_auth cookie is enough — no usePageAccess call needed.


Storefront

Everything is public. The community functions as a public-facing showroom — anyone can browse feed, marketplace, events, members — and they choose whether to sign in later.

Configuration. Community default visibility = PUBLIC, no page-level overrides. Every canonical page resolves to PUBLIC for an anonymous visitor — with one intrinsic exception: /conversations is always MEMBERS_ONLY, no matter the community shape, because chat is private user data by invariant.

What the visitor experiences.

Why pick it.

  • Maximum discoverability — feed posts, event pages, marketplace listings, member directory all crawled and indexed. Generative search engines can cite your event copy. Every member post is a fresh page in your site map.
  • Frictionless funnel: anon → reads → sees value → signs up. No "members-only" wall hiding the goods.
  • Inside Storefront you can still gate individual channels via the chapter's own visibility column — fine-grained without flipping the whole community.

Cost.

  • Member content is public by default. Deletes work, but third-party caches can linger.
  • The "members-only club" framing is gone. If exclusivity is the value prop, this isn't the right mode.

SDK implication. The landing doesn't need to gate any nav item — every Cobuntu route is clickable for anyone. The SDK is about layout, theming, and cross-domain auth, not page-access filtering.


Hybrid

Mixed-visibility. Some pages are open to the public, some require membership. The most flexible mode — and the most common for paid or curated communities.

Configuration. Any time at least one page has a visibility override set in admin → Settings → Pages. Each page resolves independently through the same rule from the top of this page (effective = page.visibility ?? community.visibility).

Because either column can be the default and either can be the override, Hybrid expresses two opposite shapes:

These are the same two patterns you'll recognise from firewalls, OAuth scopes, and CSP headers — default-allow with exceptions vs default-deny with exceptions. Pick whichever frames your community more naturally.

Flavour A — Blocklist (default-allow)

Community default visibility = PUBLIC + selectively gate the inner ring. The most common Hybrid shape today.

Sample shape:

Community default       = PUBLIC
Per-page overrides:
  FEED        = MEMBERS_ONLY  ← gated
  MEMBERS     = MEMBERS_ONLY  ← gated
  ATLAS       = MEMBERS_ONLY  ← gated
  EVENTS      = unset (inherits PUBLIC)
  MARKETPLACE = unset (inherits PUBLIC)
  BLOG        = disabled (yields to your landing — see note below)
  CHAT        = always MEMBERS_ONLY (intrinsic)

Use when your public surface is top-of-funnel and the gated pages are the value prop. Events and marketplace pull in traffic; joining unlocks the feed and member directory.

What happens when you disable a page (enabled: false). The Cobuntu reverse proxy yields the route to your landing host. That is, if you disable BLOG, a request to yourdomain.com/blog falls through to the landing host (Lovable, Webflow, Squarespace, your own Next.js, etc.) — same path Cobuntu uses for any Layer 3 custom route. This lets you author your own /blog on the landing without a route-collision with Cobuntu's. If your landing doesn't have that route either, the visitor gets whatever 404 / fallback the landing host serves. Cobuntu itself never renders a 404 for a disabled page.

Flavour B — Allowlist (default-deny)

Community default visibility = MEMBERS_ONLY + open up the specific pages that should leak outward — typically for marketing or recruiting.

Sample shape (closed network with a public face):

Community default       = MEMBERS_ONLY
Per-page overrides:
  EVENTS      = PUBLIC        ← published outward
  BLOG        = PUBLIC        ← published outward
  FEED        = unset (inherits MEMBERS_ONLY)
  MEMBERS     = unset (inherits MEMBERS_ONLY)
  ATLAS       = unset (inherits MEMBERS_ONLY)
  MARKETPLACE = unset (inherits MEMBERS_ONLY)
  CHAT        = always MEMBERS_ONLY (intrinsic)

Use when the community itself is the value prop — a closed mastermind, an invite-only network — and only specific surfaces should be visible to the outside world.

What changes between flavours

Nothing in the resolver. The runtime gate treats them identically; the only difference is which column you flip first. The usePageAccess hook returns the same shape either way, and SDK code that filters nav items by "can the viewer see this page?" works without modification.

SDK implication. The landing can't know upfront which routes to render in the nav — that depends on (a) what the leader configured per page and (b) whether the current viewer is a member. One usePageAccess(communityTag) call answers both, in one round-trip. See auth & page access for the wiring.


Layer 2 — Entity-level overrides

The three modes operate on pages. Layer 2 operates on individual entities within a page — events, feed posts, and (soon) more.

You'll see Layer 2 most often when:

  • You're in Storefront and want a single event to require member-only RSVP — without gating the whole /events listing.
  • You're in Allowlist Hybrid and want a single event to render publicly — without flipping the whole /events page.

Events have two axes

Events split visibility into two independent columns:

The two columns are independent, giving four combinations — three useful, one borderline:

viewabilityaccessibilityReading
PUBLICPUBLICAnyone sees the event, anyone registers. Pure top-of-funnel.
PUBLICMEMBERS_ONLYAnyone sees the event card; only members can RSVP. The classic "members-only perks, shown publicly" framing.
MEMBERS_ONLYMEMBERS_ONLYCard only renders for members; registration also gated. Default for internal events.
MEMBERS_ONLYPUBLICAllowed but usually a mistake — non-member viewer can't see the card, but if the URL is shared they can RSVP.

Sample shape — a Storefront community using accessibility: MEMBERS_ONLY to gate registration on member events while keeping the listings public:

Public Open Mixer       viewability=PUBLIC  accessibility=PUBLIC          ← fully public event
Members Monthly Brunch  viewability=PUBLIC  accessibility=MEMBERS_ONLY    ← public listing, member-only RSVP
Founders Workshop       viewability=PUBLIC  accessibility=MEMBERS_ONLY    ← same pattern
Annual Retreat          viewability=MEMBERS_ONLY  accessibility=MEMBERS_ONLY  ← fully internal

How Layer 2 interacts with Layer 1

The page gate (Layer 1) runs first on the listing URL. The detail URL bypasses the page gate and delegates to the entity:

This delegation is exactly what makes "fully-private community with a single fully-public event" work end-to-end: the event-detail URL respects its own columns, not the parent page's visibility.

Where Layer 2 exists today

EntityPer-row visibility?Notes
EventsYes — viewability + accessibilityFull 2-axis split, documented above.
Messages (feed posts)Yes — visibility, stamped at create-time from the channelInherited from the channel, then frozen on the post. Flipping a channel private → public only affects new posts; old ones keep their original visibility. Posts in chat channels are always MEMBERS_ONLY by invariant.
Products (marketplace listings)No — inherits from /marketplace pageNo per-product override yet.
Articles (blog posts)No — inherits from /blog pageNo per-article override yet.

When per-entity overrides ship on more entity types, this table grows. The Layer 1 + Layer 2 composition shape stays the same.


Layer 3 — Custom landing routes

Your landing has its own routes — /, /about, /pricing, /custom-route, anything you build. These are outside the visibility system entirely. Cobuntu's reverse proxy (Hosted apex pattern) leaves them untouched: a request to a path Cobuntu doesn't own falls through to your landing host, no gating, no rewriting, no SEO overrides.

Cobuntu's reserved paths

Anything matching these prefixes is owned by Cobuntu — the reverse proxy serves the Cobuntu page, not your landing:

SurfacePaths
Feed/feed, /feed/<channel-slug>, /feed/post/<id>
Events/events, /events/<slug>, /events/new
Marketplace/marketplace, /marketplace/<slug>
Members/members, /members/<usertag>
Atlas/atlas
Blog/blog, /blog/<slug>
Chat/conversations, /conversations/<id>
Cart + checkout/cart, /checkout
Personal hub/hub, /notifications, /library, /downloads, /my-events, /my-orders, /selling-here
Profile/profile, /profile/edit
Settings/settings, /settings/account, /settings/edit-profile, /settings/notifications, /settings/privacy
Membership/membership, /plans
Auth + onboarding/login, /join, /apply, /onboarding, /sso/*
Legal/privacy, /terms
API/api/*

Anything else routes to your landing. You keep full control over the routes you author.


Picking a mode

Quick-pick table:

If your community...Pick
Sells access to a private group, no public surface neededPortal
Is content-led, wants every event and article indexedStorefront
Has a public showroom and a members-only inner ringHybrid Blocklist
Is members-only at heart but wants a few outward-facing pagesHybrid Allowlist
Doesn't know yetStorefront — flip into Hybrid later by overriding one page

The default for new communities is PUBLIC + no overrides — i.e., Storefront. Customers move toward Hybrid by overriding individual pages in cobuntu-admin → Settings, or to Portal by flipping the community-level visibility.


Cheat sheet — admin settings reference

What you set, where you set it, what value it takes:

In cobuntu-admin → SettingsFieldValue
Community visibility togglevisibilityPUBLIC | MEMBERS_ONLY
How members get inaccessibilityOPEN | APPLICATION | INVITE_ONLY
Per-page Enabled switchpage overrideboolean
Per-page Visibility overridepage overridePUBLIC | MEMBERS_ONLY | unset
Per-event Viewability (manage page)event overridePUBLIC | MEMBERS_ONLY
Per-event Accessibility (manage page)event overridePUBLIC | MEMBERS_ONLY

Read these via the REST API:

GET /api/communities/<tag>             ← visibility, accessibility, pageSettings
GET /api/communities/<tag>/page-access ← composed verdict for the current viewer

The page-access endpoint runs the resolver server-side and returns one verdict per page key. SDK consumers wrap it with usePageAccess (React) or fetchPageAccess (vanilla).