Skip to content

Community Access — Internal

Access to a FluentCommunity course or space follows the licenses in license-server. Two things move people in and out: the payment and license events (immediately), and the daily check (repairs drift). A WordPress bridge plugin (littlebig-community-bridge, on community.littlebig.co) separately handles sign-in and the opt-in joining of spaces.

Paddle purchase / manual license in the Product Admin
│
▼
license-server (D1: products / tiers / paddle_price_map / licenses)
│ tiers.features.community_spaces: [slug, ...]
▼
grantCommunityAccess (src/lib/communityAccess.ts)
│ communityClient: WordPress REST + FluentCommunity REST (Application Password)
│ 1. find or create the WordPress user by email (random password, never used)
│ 2. enrol in the course, or join the space
│ 3. write the community_grants ledger row
▼
FluentCommunity course / space membership

A course or a space is just a slug in community_spaces. The client works out which it is.

Event Result
Paddle transaction.completed / subscription.created License issued, buyer enrolled. Plugin buyers get a key email; course buyers do not.
Manual license created in the Product Admin Customer enrolled, ledger row written.
License extended (reactivated) Customer enrolled again.
Admin revokes or expires a license Customer removed, unless another active, unexpired license of theirs grants the same slug.
Paddle subscription.canceled License canceled and the customer removed, with the same safeguard.
Daily check (“Reconcile”) Missing course buyers enrolled; members the system added who are no longer entitled removed. See Product Admin.

Removing someone from a course also deletes their progress (FluentCommunity does this; it cannot be undone).

community_grants records every membership the system granted (email, slug, kind, source, license, dates). The daily check only removes members who have an active ledger row, so people you added by hand are never touched. Existing members are recorded in the ledger the first time the check runs in apply mode.

The bridge only adds people to spaces (version 1.0.5 and later); it never removes anyone. Joining a space (for example the WP Luminary group) is the member’s own choice through the bridge (“Join the community”). The daily check therefore never enrols anyone into a space; it only records existing members and removes them when their license ends.

Setting Where Purpose
COMMUNITY_API_USER, COMMUNITY_API_PASSWORD Worker secrets (license server) WordPress user littlebig-license-server (administrator) and its Application Password
COMMUNITY_API_BASE optional variable Defaults to https://community.littlebig.co
COMMUNITY_COURSE_OWNER_ID variable WordPress user that owns new courses (1 = André)

The old FluentCommunity incoming webhooks are no longer used (removed October 2026); delete any that remain in FluentCommunity. Use the Product Admin: create the product with a community kind. The course is created as a private draft and assigned to its owner, the tier grants its slug, and the Paddle price is created from the same screen. Lessons and publishing stay in FluentCommunity. No migration, no curl.

If you must work by hand: tiers.features.community_spaces is a full replace when patched (PATCH /v1/admin/tiers/{id}), so send every existing key.

Section titled ““Paid newsletter” — which one do you mean?”
  • A gated feed inside FluentCommunity (posts only paying members see) works exactly like adding a course or space above: it is just another slug.
  • An actual email newsletter with paid tiers is a different system: littlebig-newsletter (separate Cloudflare Worker + D1, sends via tosend.com) has no concept of licenses today. Gating it would mean that Worker checking license-server’s /v1/admin/licenses for an active entitlement before sending — a real integration to build, not a data-seeding exercise like the rest of this page.

  • products.community_space_slug (old, product-level) still exists beside the newer community_slug / community_kind columns and tiers.features.community_spaces. It is still read as a fallback and not yet cleaned up.
  • The daily check is not scheduled yet (needs the Workers Paid plan). Until it is, a license that simply expires is only caught when someone clicks “Check now”.
  • The email-newsletter-with-paid-tiers integration described above does not exist yet.