Ghostpost – multi-tenant blog-first content service
Open full-size image ↗
Category: Live SaaS (post-pivot)
Status: Live in production at ghostpost.fun; Phases 0–3 shipped (2026-07 → 2026-10); Phases 4–9 pending
Time window: Built spring 2026; pivoted July–October 2026
Live URL: https://ghostpost.fun
Purpose
Multi-tenant blog-first content service sold to external companies. Internal admins (Stratas) onboard client orgs sales-led, generate blog drafts end-to-end inside the app, publish to the customer's CMS, and send a LinkedIn companion post as a free side-effect.
The pivot: v1 was a single-user LinkedIn-post generator. V2 is a multi-tenant platform where blog is the primary artifact and LinkedIn rides along.
Who it is for
B2B content teams at mid-sized companies who want research-grounded blog posts without hiring a content agency. Sales-led onboarding; no public self-serve signup yet.
Stack
- Frontend: Next.js 14.2 App Router (TypeScript), hosted on Vercel
- Backend: Next.js API routes; generation pipeline inline via
@vercel/functions.waitUntil(Trigger.dev was removed in Phase 1C-2c) - Data: Supabase Postgres via Prisma 5, session-mode pooler, runtime switched to a constrained
ghostpost_approle for per-row RLS - LLM / AI: Multi-provider router under
src/lib/llm/– Anthropic Claude Sonnet 4.6 primary, OpenAI fallback; Perplexity Sonar-Pro for research - Email / billing: Resend (transactional), Stripe (subscriptions + webhook-driven quota)
- Observability: Langfuse (per-trace tag
ghostpost, projectstratas-products); LangSmith optional
My contribution
Shaped the product concept and generation workflow, built the blog structure, visualisations, integrations and publishing schedules, instrumented the product, and used early feedback to guide the pivot.
Notable capabilities
- Multi-tenant RLS via a constrained Postgres role – Prisma connects as
ghostpost_app, which can only see rows that match the current tenant context set viaset_config. No per-query tenant filter in application code; the database refuses to leak. - Atomic quota engine with Stripe webhook dedup – a
pg_advisory_xact_lockwraps the "consume one generation" write (PR #75) and a claim-before-work idempotency pattern on the Stripe webhook (PR #78) stops double-decrement on retried events. - Inline generation pipeline on Vercel – Trigger.dev was removed;
@vercel/functions.waitUntilruns the pipeline attached to the request, withwithLangfuseFlush+.finally(flushLangfuse)ensuring traces survive the lambda freeze that happens the moment the HTTP response is sent. - Multi-provider LLM fallback – a single router under
src/lib/llm/picks Anthropic → OpenAI by tier (e.g.tier: "drafting"→ Sonnet 4.6), carrying model name and token counts through to Langfuse for the per-provider cost split. - Trial-gated billing – Phase 3E re-targets Stripe trials so generation quota is live from signup, with trial expiry correctly bouncing the user to the plan selector.
Outcome
Live in production; 170 Post rows, 175 PostVersion rows, 20 BlogDraftRun rows on the founding Stratas org at Phase 2A backfill. Migrations applied to prod with verifiable timestamps (e.g. 20261002120000_phase_3c_generation_consumption on 2026-10-02). Not yet onboarding external customer orgs – pending Phase 5 (CMS connectors: WordPress + Webflow + webhook).
The pivot is tracked openly in the repo rather than as a hidden reset: GHOSTPOST_PIVOT_BUILD_PLAN.md dates to 2026-10-01, PRs #58–#78 carry the Phase 1–3 arc, and CHANGELOG.md section headers mark each deployed phase.
Evidence
- Live:
https://ghostpost.fun - Repo: private
- Docs in-repo:
GHOSTPOST_PIVOT_BUILD_PLAN.md,CHANGELOG.md,COST_INSTRUMENTATION_REQUIREMENTS.md - Langfuse:
stratas-productsproject, trace tagghostpost; surfaced on the Agent Fleet dashboard atstratas.space
Skills demonstrated
typescript, nextjs-14-app-router, prisma-5, supabase-postgres, multi-tenant-rls, constrained-postgres-role, atomic-quota-engine, pg-advisory-xact-lock, stripe-webhook-dedup, vercel-waituntil-pipeline, langfuse-cost-instrumentation, multi-provider-llm-fallback, anthropic-sdk, openai-sdk, perplexity-sonar, resend-transactional, product-pivot-in-git-history, cost-first-development
Want to discuss the decisions behind it?
Over fifteen years of consulting and growth, and hands-on AI delivery from discovery to daily operations. I can share my CV and talk through how I connect business outcomes with systems that run.
Available for a chat. In person in Stavanger, or remotely worldwide.