🗝️

Ajijic Membership Platform Decision

Private. Enter the hub password to continue.

That's not right. Try again.

🗝️ Decision doc

Ajijic Membership Platform Decision

$399/yr membership: Ghost vs Stripe+Worker vs Outseta | 2026-07-12

← Back to Hub

The recommendation, up top

Go with Option C: Outseta ($39/mo Founder plan + 2% fee), dropped into the existing ajijic.org static site. It handles the $399/yr membership, the $297 one-time Digital Discovery, and future concierge tiers in one dashboard, with CRM and email built in, and it launches in 1-2 sessions with no content migration. Fallback if you want zero monthly cost: Option B (Stripe + our own Worker), slower and we own auth security forever. Ghost (Option A) is out: it forces member content into a second CMS on a second subdomain.

What's already cleared: the legal gate (attorney sign-off + Jalisco license, 2026-07-12). What still gates launch: the site's preview wall, membership can't go live until you call the public launch.

Companion: Ajijic Member Content Map (exactly what $399/yr buys).

Created: 2026-07-12 by Charlie (PLAN-membership-payments-prep) Status: DECISION DOC for Annette. One decision converts to execution from the runbooks below. Companion: Ajijic Member Content Map (what the membership gates)

Gates (read first)

  1. Legal gate: CLEARED 2026-07-12. Annette confirmed the attorney cleared the ToS and Privacy Policy, and her Jalisco license is reactivated. The legal/ docs can be promoted from DRAFT.
  2. Public-launch gate: STILL OPEN. The site is soft-launch gated (static-site/_worker.js preview cookie). Membership cannot go live behind a preview wall. Sequence: Annette calls public launch (remove preview gate, redeploy) → then membership goes live. This is the only remaining sequence gate.

The decision: three ways to run a $399/yr membership

Option A: Ghost(Pro) Option B: Stripe + our own Worker gating Option C: Outseta drop-in
Monthly cost $29/mo Publisher plan, billed annually ($35 monthly). Starter ($15) no longer allows paid subscriptions. Ghost takes 0% of member revenue $0 platform. Stripe fees only (2.9% + $0.30) $39/mo Founder plan + 2% transaction fee, plus Stripe fees
Cost on $399 sale ~$11.87 Stripe only ~$11.87 Stripe only ~$19.85 (Stripe + $7.98 Outseta)
What it is Hosted membership CMS at members.ajijic.org; content moves INTO Ghost Stripe Checkout links + a Cloudflare Worker that checks a session cookie against D1 (extends the existing worker/index.js stack) Auth, payments, CRM, and email widgets dropped into the existing static HTML pages
Annette effort to operate Low (Ghost dashboard) Medium (Charlie maintains; she has no dashboard beyond Stripe) Low (Outseta dashboard covers members, billing, email, CRM)
Time to launch 2-3 sessions (content migration into Ghost is the long pole) 3-5 sessions (build + security review of auth) 1-2 sessions (no content migration)
Migration risk Two stacks forever: static site + Ghost. Member content maintained in a second CMS None (one stack) but we own auth security forever Low; member data exportable, content never leaves our repo
$297 Digital Discovery fit Ghost tiers are subscriptions; one-time products are awkward (workaround: Stripe Payment Link on the side, so two systems anyway) Native: just another Checkout link Native: Outseta supports one-time charges alongside subscriptions
Content gating strength Strong (server-side) Strong (server-side, Worker-enforced) Widget gating is client-side by default (hide-in-browser); needs the hybrid hardening in the runbook to be real
Renewal dunning Built in We build it (Stripe Smart Retries + Resend emails) Built in

Pricing sources (verified 2026-07-12): Ghost(Pro) pricing and Ghost forum pricing announcement; Memberstack pricing (Basic $25/mo + 4% fee, Professional $39/mo + 2%, considered and rejected: 4% fee at entry tier and Webflow-first tooling); Outseta pricing (Founder $39/mo + 2%, Start-up $79/mo + 1%); Ghost custom-domain help.

Recommendation: Option C (Outseta), with Option B as the zero-monthly-cost fallback

The May "Ghost $29/mo" recommendation predates the site we actually built. We now have 50+ finished static pages on ajijic.org with locked branding, a live D1 + Resend worker, and a working funnel. Ghost's whole value is its CMS, which forces the member content into a second system on a second subdomain (members.ajijic.org), a permanent two-stack tax and a domain seam at the exact moment of purchase. Ghost also handles the $297 one-time product poorly. Outseta drops into the pages we already have, handles the $399/yr, the $297 one-time, and the future monthly concierge tiers in one dashboard, and throws in CRM and email (which trims the planned ConvertKit/Beehiiv spend from product-lineup-v1). The 2% fee costs about $8 per membership sale, roughly one sale per month pays the difference vs Ghost. The one real weakness, client-side gating, is fixed by the hybrid Worker check in Runbook C. Choose Option B only if zero monthly cost matters more than launch speed and than not owning an auth security surface.

Stripe object model (applies to A and B; Outseta creates equivalents in its own dashboard on top of Stripe)

Five products, five prices, USD:

# Product Price object Type
1 Ajijic Guide Membership $399/year Recurring, annual
2 Digital Discovery Package $297 One-time
3 Concierge Light $150/month Recurring, monthly (HOLD)
4 Concierge Regular $250/month Recurring, monthly (HOLD)
5 Concierge Absentee/Snowbird $400/month Recurring, monthly (HOLD)

HOLD note: strategy/monthly-concierge-tiers.md flags Regular and Absentee as margin-negative at $30/task Ava economics (-$10 and -$60 per client per month). Launch Membership + Digital Discovery first; do not open concierge checkout until the Ava pricing review closes.

Rules that apply to every option:

  • Sell Membership and Digital Discovery as separate checkout links; do not mix one-time and recurring in a single Checkout session (tax and receipt complications).
  • Test mode before live mode, always: create products in TEST, wire the webhook/receiver, fire Stripe CLI test events, complete a full test purchase and a test renewal-failure, and only then create the live products.
  • No keys in git, ever. Secret keys live only in wrangler secret put (Worker) or the platform's dashboard. Publishable keys (pk_) are the only class allowed in page HTML. .gitignore any .env.
  • Dunning or year-2 revenue halves silently: enable Stripe Smart Retries + a reminder email 7 days before renewal and on each failed charge (Resend for B, built-in for A and C).

Indexing and AI-crawler note

robots.txt and llms.txt were opened to SEO + AI crawlers on 2026-07-11, which is right for the free tier but wrong for member content. Whichever option wins: member-only URLs must be excluded from sitemap.xml, carry <meta name="robots" content="noindex">, and, decisively, be enforced server-side (Ghost and the Worker do this natively; Outseta needs the hybrid step in Runbook C). Client-side hiding alone means every AI crawler ingests the paid content and answers questions from it for free. Free teaser pages stay indexed on purpose; they are the funnel.


Runbook A: Ghost(Pro) at members.ajijic.org

  1. Gate check: Legal CLEARED 2026-07-12 (attorney sign-off received; Jalisco license reactivated). Confirm public launch has happened (preview gate removed from static-site/_worker.js and redeployed). If the site is still gated, STOP.
  2. ANNETTE + card required: Create Ghost(Pro) account, Publisher plan ($29/mo billed annually). Starter does not allow paid subscriptions.
  3. ANNETTE: Connect her Stripe account to Ghost (Ghost admin → Settings → Membership). If she has no Stripe account: ANNETTE + card/bank required to create one at stripe.com (identity + bank details, Charlie must not enter these).
  4. DNS: in Cloudflare, add CNAME members -> [target Ghost provides in admin], DNS-only (grey cloud) per Ghost's Cloudflare guidance. Never touch the apex record: ajijic.org's apex is Cloudflare Pages; pointing it at Ghost takes the site down. The membership lives at members.ajijic.org and visitors cross domains at signup (accept this UX seam or pick another option).
  5. Activate the custom domain in Ghost admin → Domain settings; wait for SSL.
  6. In Ghost TEST/Stripe test mode: create the Membership tier at $399/yr. Digital Discovery: create a separate Stripe Payment Link ($297 one-time) outside Ghost and link it from the site (Ghost does not do one-time products well).
  7. Migrate member content per the Member Content Map: 10 book chapters + 3 member relocation docs into Ghost posts tagged members-only. Apply brand fonts/colors to the Ghost theme (bright, light, no dark backgrounds, no sticky elements).
  8. Set Ghost posts to members-only visibility; verify logged-out access is refused server-side; confirm noindex on member posts; remove member URLs from any sitemap we control.
  9. Test-mode checklist: test signup, test $399 charge, member login, gated page access, cancel flow, failed-renewal email. All green before step 10.
  10. ANNETTE: flip Stripe to live mode in Ghost; do one real $399 purchase herself and refund it.
  11. Wire the static site: "Join" CTAs point to members.ajijic.org/#/portal/signup; add member callout blocks to the 13 category pages.
  12. Enable dunning: Ghost handles retries; verify the renewal-reminder email is on.

Runbook B: Stripe Checkout + Cloudflare Worker gating (own stack)

  1. Gate check: Legal CLEARED 2026-07-12 (attorney sign-off received; Jalisco license reactivated). Confirm public launch has happened (preview gate removed and redeployed). If still gated, STOP.
  2. ANNETTE + card/bank required: Create the Stripe account (identity + bank onboarding). Charlie never enters financial credentials.
  3. In Stripe TEST mode (Charlie, via dashboard access Annette grants or pair-session): create the 5 products/prices from the object model. Create Payment Links for Membership ($399/yr) and Digital Discovery ($297). Concierge products created but links NOT published (margin HOLD).
  4. Build the webhook receiver FIRST, before any checkout goes live: extend worker/index.js (or a sibling worker on the same account/D1) with POST /api/stripe-webhook handling checkout.session.completed, customer.subscription.updated, customer.subscription.deleted, invoice.payment_failed. Verify signatures with the webhook signing secret. Write member status to a new D1 members table (email, stripe_customer_id, status, current_period_end).
  5. Secrets: wrangler secret put STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET. Nothing key-shaped in git; publishable key only in HTML if Checkout is embedded (Payment Links need none).
  6. Build auth: magic-link email sessions at minimum. POST /api/member-login → look up active member in D1 → Resend a signed one-time link → set an HttpOnly signed session cookie (30 days). This is Charlie-built auth and a real security surface: HMAC-signed tokens, expiry, rate limiting on the login endpoint, constant-time comparison. Adversarial review (Gemini + Codex + Grok) REQUIRED before live.
  7. Gate the member paths: extend static-site/_worker.js so /members/* (chapters + member docs per the content map) requires a valid session cookie, else redirect to the join page. Server-side enforcement, plus noindex meta on member pages, and exclude /members/* from sitemap.xml.
  8. Test-mode checklist: Stripe CLI test events against the webhook; full test purchase; magic-link login; gated page access logged-in and logged-out; subscription-cancel removes access at period end; invoice.payment_failed triggers the Resend dunning email. All green before step 9.
  9. Dunning: enable Stripe Smart Retries in dashboard settings; Resend reminder 7 days pre-renewal (cron trigger on the worker) and on each failed charge.
  10. ANNETTE: switch keys to live mode (wrangler secret put with live keys), publish live Payment Links, make one real purchase and refund it.
  11. Wire the static site CTAs to the live Payment Links; add member callouts to category pages.

Runbook C: Outseta on the existing static site (RECOMMENDED)

  1. Gate check: Legal CLEARED 2026-07-12 (attorney sign-off received; Jalisco license reactivated). Confirm public launch has happened (preview gate removed and redeployed). If still gated, STOP.
  2. ANNETTE + card required: Create Outseta account, Founder plan ($39/mo, 2% transaction fee). During onboarding, ANNETTE + bank required: connect/create the Stripe account (Outseta bills through Stripe).
  3. In Outseta (test mode): create plans mirroring the object model: Membership $399/yr (recurring annual), Digital Discovery $297 (one-time), the 3 concierge plans created but hidden (margin HOLD).
  4. Drop the Outseta script + signup/login embeds into the static site: join page gets the $399 signup widget, a new login link in the nav (not sticky), and an account page. Keep all styling on-brand: bright, light, magenta CTAs only, no dark backgrounds, no sticky elements.
  5. Publish member content at /members/* paths (chapters + the 3 member relocation docs per the Member Content Map) using the existing page template.
  6. Hardening (required, do not skip): Outseta's default content protection is client-side. Add server-side enforcement in static-site/_worker.js: on /members/*, validate the Outseta JWT/access token (Outseta issues one at login) before serving; invalid or absent → redirect to join. Also add noindex meta to all /members/* pages and exclude them from sitemap.xml. Without this step the open robots.txt/llms.txt policy hands the paid content to every AI crawler.
  7. Configure Outseta email: welcome email on signup, renewal reminder, failed-payment dunning sequence (built in; turn them on and put them in Annette's voice, contractions, no em-dashes).
  8. Test-mode checklist: test signup + $399 test charge, login, gated page served with valid token, gated page refused without token (curl, not browser), cancel flow, failed-renewal email fires. All green before step 9.
  9. ANNETTE: flip Outseta/Stripe to live mode; make one real $399 purchase herself and refund it.
  10. Wire funnel: homepage and category-page CTAs to the join page; Digital Discovery checkout link on its sales page; import existing D1 subscriber emails into Outseta CRM (export from D1, import CSV; no credentials in git).
  11. Register the renewal/dunning emails in ~/memory/ROUTINES.md (what/when/where/how-to-disable) since they are recurring automation.

Legal footnote

Governing law is decided (Jalisco, Guadalajara arbitration, USD pricing) and the attorney packet covered the PROFECO / US-Canada consumer angle. Attorney review is complete as of 2026-07-12. Nothing here re-opens governing law.

🔒 Private · annettethompson.com/hub/ajijic-membership-platform-decision