marketing

Phase 0 launch checklist — first 5 user-action items

Why this doc exists. All the Phase 0 infrastructure shipped this session (PRs #102–#121). The work left is yours, not the code's. Each item below is a one-sitting task; together they unblock the first real signal from the audience — listens, engagement, subscribers — that should inform what we build next.

Recommended order. Apple/Spotify first (the crawl takes a week, so start that clock now). Then Bluesky + Stripe in parallel (both are quick + compounding). Then TikTok trailer. Then the Reddit launch as the headline moment when the other three are humming.

Estimated total: ~3 hours of focused work spread across 1–2 sittings.


1. Apple Podcasts + Spotify directory submission

Goal. Get every published show listed in the two podcast directories that drive 80%+ of audio-fiction discovery. One-time human-gated step per platform per show.

Why first. Apple's crawl-to-listing time is typically 5–7 business days. The Spotify pipeline is faster but still 1–3 days. Starting this clock today means listings are live by the time TikTok + Reddit traffic starts.

Time: 30 minutes for the first show (per platform), 10 minutes for each subsequent show after you've done the dance once.

Steps

  1. Open /dashboard/admin/podcast-feed (super-admin gated).
  2. Scroll past the feed validator to the Per-show submission tracker section.
  3. The chips at the top show how many shows are still pending per platform — should match your total published count for both Apple and Spotify on the first visit.
  4. Per show, for Apple Podcasts Connect:
    • Click 📋 Copy RSS URL on the show's row.
    • Click the Apple Podcasts portal ↗ chip at the top of the section (opens https://podcastsconnect.apple.com/ in a new tab).
    • Sign in with your Apple ID (use the one tied to the show's intended brand account; for Graphene network feeds this is the Graphene Apple ID).
    • Click + Add a show → choose Add a show with an RSS feed.
    • Paste the URL → click Add.
    • Apple validates the feed (takes 5–60 seconds) → if errors appear, return to /dashboard/admin/podcast-feed, click ↻ Re-run on the validator section, fix any flagged channel/item findings.
    • Submit for review.
    • Back on /dashboard/admin/podcast-feed, click the Apple toggle pill on that show's row → flips to ✓ submitted <today's date> in green.
  5. Per show, for Spotify for Podcasters:
    • Same 📋 Copy RSS URL (same URL works for both platforms).
    • Click the Spotify for Podcasters portal ↗ chip → https://podcasters.spotify.com/pod/dashboard/podcast/get-started.
    • Sign in with the show's brand Spotify account.
    • Choose I already have a podcast → paste the RSS URL.
    • Verify ownership (Spotify emails a code to the <itunes:owner><email> address in the feed — should be the brand email).
    • Submit.
    • Back on /dashboard/admin/podcast-feed, click the Spotify toggle pill → green ✓ stamp.
  6. Repeat 4–5 for every show. The page hides completed shows by default (Hide completed button at the top); click Show all to see the full list.

How to verify it worked

  • Apple Podcasts: search the show title in the Podcasts app on iOS / macOS. Listings typically appear within 5–7 business days. Watch your Apple Podcasts Connect inbox — Apple emails when the show goes live OR if it was rejected (rare; usually metadata field issues we'd have caught in the validator).
  • Spotify: search the show title in Spotify on mobile or web. Usually 1–3 days. The show owner gets an email confirmation when it lands.

What to watch for

  • If Apple rejects with Invalid feed errors, run the feed validator (/dashboard/admin/podcast-feed, click ↻ Re-run) — usually a missing <itunes:image> (poster_url not set), <itunes:owner> email mismatch, or an item with a zero-byte <enclosure length>.
  • Spotify's stricter on duration metadata — every episode needs a non-zero <itunes:duration>. The validator catches this.
  • Don't double-submit — if you accidentally try, the Apple portal will say "this feed is already submitted by <other user>" and you'll need to claim ownership via the in-portal flow.

2. Stripe Graphene+ price ID

Goal. Light up paid subscriptions for the $5/mo Graphene+ tier. All the backend wiring (checkout endpoint, webhook handlers, subscription state tracking, cancellation flow with retention coupon) is pre-wired — flipping this one env var on Railway turns it on.

Why now. Doesn't take effect on its own (no one's subscribing yet), but means the moment a TikTok or Reddit visitor decides to subscribe, the upgrade path works. Without this, the /graphene-plus upgrade button silently 4xx's.

Time: 10 minutes.

Steps

  1. Open the Stripe dashboard → Prices (you'll need to be in the correct Stripe account if you have multiple — top-right account switcher).
  2. Click + Add a price → choose Recurring → pricing model Standard pricing.
  3. Product: create a new product called Graphene+ (monthly) — description: Listener subscription. Ad-free, priority letter selection, early-access chapters. Statement descriptor: GRAPHENE+.
  4. Amount: $5.00 USD, billing period Monthly.
  5. Tax behavior: Inclusive (or Exclusive if you've set up Stripe Tax — Inclusive is fine for v1).
  6. Save → copy the price ID (looks like price_1ABCxyz...).
  7. Open the Railway dashboard → your backend service (hivejournal-backend or similar) → Variables.
  8. Add a new variable: STRIPE_PRICE_GRAPHENE_PLUS = the price ID you just copied.
  9. Save. Railway re-deploys automatically (~60s).
  10. (Optional, recommended) Repeat 2–6 for a yearly variant at $48/yr (= $4/mo, gives a discount nudge to switch from monthly), save as STRIPE_PRICE_GRAPHENE_PLUS_ANNUAL. The BillingIntervalToggle component self-hides if this isn't set, so it's safe to skip for v1.

How to verify it worked

  1. Open /dashboard/admin/launch-readiness → the STRIPE_PRICE_GRAPHENE_PLUS row should now be green ✓ instead of red ✗.
  2. As a non-super-admin (use the 👁 view-as picker → Viewer mode), visit /graphene-plus — the upgrade button should be active and not say "coming soon."
  3. Click the upgrade button → Stripe Checkout opens in a new tab showing the $5/mo Graphene+ product.
  4. Don't actually complete a test purchase on prod unless you want to be the first subscriber. Use a Stripe test mode key if you want to validate the full webhook flow without a real charge.

What to watch for

  • The launch-readiness page caches for a moment after Railway redeploys — give it 30s and refresh.
  • If you set the wrong price ID (e.g. a prod_ product ID instead of a price_ price ID), checkout fails with a 400. The error message in DevTools console will say No such price.
  • The retention-offer flow at /dashboard/subscription needs a separate STRIPE_COUPON_RETENTION env var — set up a 100%-off, repeating, 1-month duration coupon in Stripe and paste the coupon ID. Optional for v1.

3. Bluesky chapter-drop autopost

Goal. Wire up free, compounding distribution: every triggered chapter auto-posts to your Bluesky audience with the show poster + chapter link. Set it once per show, then chapter 2 / 3 / 4 / ... all post for free.

Why now. Costs $0 ongoing, takes 2 min per show, and produces signal you can read in 4h (engagement counts auto-refresh via the cron from PR #108). You're already posting to Bluesky from the cafe-bluesky pipeline so the credentials are set.

Time: 5 min per show to enable + first-post sanity check.

Steps

  1. Pick a show to start with — recommend The Last Reflection (Hotel Diaries universe) since it has good poster + premise text + you already mentioned it in the Reddit draft.
  2. Open /seasons/<id> for that show (super-admin only, so you'll see admin chrome).
  3. Scroll down to the 🌤 Bluesky panel (collapsed by default, between Paid traffic URLs and Trigger warnings).
  4. Click to expand → check the Auto-post new chapters to Bluesky checkbox.
  5. Status message confirms: ✓ Autopost on — next triggered chapter posts to Bluesky.
  6. Test post (recommended, for the first show you enable): before triggering a new chapter, do a one-off manual post for a recent chapter to sanity-check the format Bluesky will use.
    • Use a tool like Postman or curl to hit POST /api/story-seasons/<season-id>/episodes/<chapter-number>/post-to-bluesky with super-admin auth.
    • Watch bsky.app/profile/<your-handle> — the post should appear within 5 seconds.
    • If the format looks off (poster missing, caption clipped), iterate on the source data:
      • Poster missing → set story_seasons.poster_url.
      • Caption clipped → Bluesky caps at 300 graphemes; the post text is built from the show title + chapter label + URL + 4 hashtags. Cut the show title if it's very long.
  7. Trigger a NEW chapter via the existing trigger-episode flow. The auto-post fires in the background within 1–2s of the trigger.
  8. Verify on Bluesky → the post shows up. Check engagement counts back on /seasons/<id> panel within 4h (the cron sweep refreshes them).
  9. Repeat 2–4 for each other published show.

How to verify it worked

  • Open the show page → expand the 🌤 Bluesky panel → status says Autopost on.
  • After the next chapter trigger, refresh /seasons/<id> and expand the panel → Recent posts table shows the new chapter at the top with engagement counts (♥ ↻ 💬 initially 0, refreshes every 4h).
  • Bluesky-side: search your own posts on bsky.app or check your profile feed — the auto-post is there.

What to watch for

  • The post will refuse to fire if (a) the show isn't published to graphene (is_published_to_graphene = false → would post a 404 link), or (b) the episode isn't triggered yet. Both gates were added in PR #114 specifically to prevent broken-link posts. So enable autopost on a show you've already published.
  • Auto-post is idempotent on episode.bluesky_post_uri — re-triggering an already-posted chapter is a no-op. If you want to redo a post, hit the manual route with { force: true }.
  • Engagement counts are scraped by a 4h cron — they don't update in real time. The first time you check after enabling, expect 0s until the next sweep.
  • Bluesky's API rate limits are generous but not infinite. Don't enable autopost on 20+ shows and bulk-trigger 50 episodes simultaneously.

4. TikTok vertical trailer — first manual post

Goal. Get one show's vertical trailer in front of TikTok's algorithm. This is the manual test before considering whether to invest in regular TikTok cadence.

Why now. The trailer + caption are auto-generated (PR #102 / #103 / #104). The download + upload is the only manual step. One post tells you whether the format works on TikTok at all.

Time: 20–30 minutes for the first one (mostly figuring out TikTok's caption + cover-frame UI). 5–10 minutes for subsequent posts once you've done it.

Pre-flight

If the vertical trailer hasn't been rendered yet for your chosen show:

  1. Go to /dashboard/admin/seasons.
  2. The cyan banner at the top shows {N} published shows missing TikTok/Reels/Shorts trailer if any are pending.
  3. Click 🎬 Render next 5 — runs the bulk pipeline (~1 min wall time, ~$0.03 in Whisper costs for captions).
  4. When complete, the results section shows each rendered show with 📋 Copy (caption) + 📣 Share kit ↗ (link added in PR #115).

Steps to post

  1. Click 📣 Share kit ↗ on the show you want to post (or navigate directly to /dashboard/admin/share-kit/<season-id>).
  2. In the 📱 Vertical trailer (TikTok / Reels / Shorts) section:
    • Click 📥 Download MP4 → file downloads as <show-slug>-vertical.mp4.
    • Click 📋 Copy caption next to the auto-drafted caption text.
  3. Open TikTok upload (sign in to your account — use the brand TikTok if you have one, or your personal for v1).
  4. Drag the MP4 into the upload area.
  5. Caption field: paste the copied caption (⌘V).
  6. Cover frame: TikTok auto-picks one. The auto-pick is usually mid-motion and bad. Click the cover editor → scrub to the first frame (which shows the show poster + title in branded chrome — that's the deliberate cover).
  7. Settings:
    • Privacy: Everyone (you're posting publicly)
    • Comments: On (engagement = reach)
    • Duet / Stitch: On (more reach)
    • Schedule: post immediately (this is a one-off test)
  8. Hashtags in the caption are pre-included. TikTok's algorithm strongly favors comment engagement — be ready to reply to first-hour comments within 5 minutes each.
  9. Click Post.
  10. Stay on TikTok for 1 hour after posting. Reply to every comment in the first 30 minutes (even one-word replies; the algorithm reads them as comment activity → boosts reach). After the first hour, replies become less critical but still matter.

How to verify it worked

  • The post appears on your TikTok profile within 30 seconds of clicking Post.
  • The cover frame shows the show poster (branded chrome), NOT a mid-motion frame.
  • Within 1 hour: at minimum 100 views (TikTok seeds every new post with ~100–500 views from your followers + cold algorithm test).
  • Within 24 hours: views are still growing OR have plateaued at <500 (plateau = algorithm decided it wasn't a fit; iterate the caption + cover for the next attempt).

What to watch for

  • TikTok caps captions at 2,200 chars but engagement falls off after ~150. The auto-drafted caption is well under that.
  • Cover frame matters a LOT. A bad auto-pick can tank a post that would have done well. Always set it manually.
  • First hour metric to watch: views + view-through rate. If you see 1k+ views in the first hour, the algorithm is testing wider — engage every comment.
  • TikTok deprioritizes posts that drive users off-platform. The link in the caption (graphene.fm/seasons/...) is fine but don't add link in bio framing in v1 — let the caption stand on its own.
  • Don't post a second trailer on the same day from the same account. TikTok suppresses rapid-fire posts. One post / show / week is the right cadence.

5. Reddit r/audiodrama launch post

Goal. Single ungated post to the most demanding fiction-podcast audience on the internet. If Graphene lands here, it lands elsewhere. If it bounces, the feedback in the comments is gold.

Why last. Highest stakes (one chance per show — re-posting same show across subreddits gets you flagged for spam). Want the other items live first so people who land on graphene.fm from the post have a good experience: published shows in Apple/Spotify, real trailers on the season pages, Bluesky autopost running.

Time: 2 hours total — 30 min to post + 90 minutes engaging in the first window.

Pre-flight

  1. Open /dashboard/admin/marketing-todo.
  2. Find the 🚀 Week-1 kickoff section → Post the r/audiodrama launch draft item.
  3. Click Show ready-to-post text ▾ to expand the draft.
  4. Click 📋 Copy body → the full draft is on your clipboard.

Choose the show to feature

The draft mentions The Last Reflection as the feature show. If that's still the best pick:

  • Open /dashboard/admin/share-kit/<the-last-reflection-id> in another tab.
  • Copy the Organic permalink (graphene.fm/seasons/...) — this goes in the draft body where it says [paste the per-show landing URL from /dashboard/admin/share-kit/<id>].

If a different show has stronger Chapter 1 (you'd know better than I would), swap it in. Update the show title + premise sentence in the body to match.

Posting steps

  1. Open reddit.com/r/audiodrama/submit in a fresh tab.

  2. Choose post type: Text post (not link post — links are heavily suppressed in r/audiodrama).

  3. Title (paste from the draft):

    Built a fiction podcast network where AI writers each have their own MBTI, journal history, and continuity. Looking for honest feedback before I ship more.

  4. Body (paste from the draft, replace the [paste...] placeholder with the actual graphene.fm URL).

  5. Flair: Pick Show / Audio Drama if available, otherwise Discussion. Don't pick Self-promotion — even though it technically applies, that flair gets less visibility.

  6. Before submitting: re-read the body for typos. Make sure the URL is the organic permalink (graphene.fm/seasons/<id>), NOT the paid landing (/listen/<id>).

  7. Click Post.

  8. Pin the comment thread. Right after posting, leave one top comment that says something like:

    Author of the post here. I'll be hanging in this thread for the next 48 hours to reply to anything — questions about the writing pipeline, where to start, what's working / not working in the audio. Critical feedback especially welcome.

    Then click the ... on your own comment → Sticky comment (mods can override, but if the sub allows it, your comment sits at the top).

The first 48 hours

This is where the post lives or dies. r/audiodrama rewards engaged authors and dunks on ones who post-and-bail.

  • First 1 hour: reply to every comment within 5 minutes. Even one-line replies. Upvote constructive critiques.
  • First 6 hours: check every 30 minutes. Long-form replies to substantive critiques. Don't argue — even when commenter is wrong, thank them for the read and explain the design intent.
  • First 24 hours: check every 2 hours. Most engagement lands here.
  • First 48 hours: check every 6 hours. Tail engagement; convert listeners by replying with show-specific recommendations ("if you liked X, try Hotel Diaries").

How to verify it worked

  • Within 30 min: upvote ratio should stabilize. >50% is a healthy launch. <30% = the title or framing landed wrong; the post might still recover via comment engagement but the algorithm has already deprioritized it.
  • Within 24 hours: at least 50 upvotes + 10 comments is "this connected." Less than that = quiet but not failed. r/audiodrama posts that get 5+ critical-but-constructive comments are MORE valuable than ones that get 500 upvotes with no comments — the comments are the gold.
  • Within 48 hours: check graphene.fm referral traffic — should see a measurable bump from referrer=reddit.com in PostHog or your analytics dashboard. Per-show landings via /listen/<id> won't catch this (organic post → organic permalink → analytics filter on session source).

What to watch for

  • Don't immediately post a second show. Even to a different subreddit. The channel-execution kit's strategy is "one post, watch 48 hours, learn, then plan the next."
  • Mods may DM you. If r/audiodrama mods reach out with concerns (e.g. AI disclosure framing), reply same-day with a thoughtful response. The mod team is generally fair but doesn't love hidden AI content.
  • Negative critiques: if someone says "this sounds AI-generated and breaks immersion," DO NOT defend. Thank them, ask which moment specifically, and use the feedback for the next show. Public defensiveness on r/audiodrama is the fastest way to torch your account.
  • If it bombs: that's fine. The brief lays out a decision tree at the 14-day mark — if no traction here, try r/podcasts or r/serialfiction with a different show, never the same one. See docs/marketing/2026-05-19-graphene-week-1-channel-execution.md for the full decision tree.

Tracking progress

Each of these is an item on /dashboard/admin/marketing-todo. Tick them off as you complete them. State persists per-admin in your browser's localStorage — won't sync across devices, but survives reloads.

After all five land, the right next move is wait 1–2 weeks for signal, not "ship more code." Real engagement data (listen counts, Bluesky reach, Reddit comments, TikTok view-through rate) tells us what to invest in next. Without that signal, the next round of features would just be guessing.

When the signal starts coming in, the per-chapter listening table on /dashboard/seasons/[id]/analytics (shipped in PR #112) is the primary read — it shows which chapters listeners actually finish vs bounce, which tells you where to focus revision effort.

2026 05 24 Phase 0 Launch Checklist — Docs | HiveJournal