zazzy
Features

Marketing pages

Public landing, pricing from plans, and an MDX blog + changelog.

Marketing adds the public-facing surface: a landing page, a pricing page derived straight from the plan config, and an MDX-backed blog and changelog. Content is files, not database rows — content-collections compiles src/content/** into typed collections at build time.

Optional feature

Marketing is optional (core: false, requires: ["billing"]). The pricing page renders billing's PlanPicker off config/plans.ts, so plans stay the single source of truth. It is a leaf — no feature depends on it.

What it does

  • Landing pageMarketingLanding inside MarketingShell renders at the core root / behind @feature:marketing markers (a pruned / falls back to redirect("/dashboard")).
  • Pricing page/pricing renders billing's PlanPicker off @/config/plans (PLANS). Marketing supplies only CTA derivation (pricingCtaHref / pricingCtaLabel): a free tier links to /sign-up, a priced plan to /sign-up?returnTo=/settings/billing. No pricing is duplicated marketing-side.
  • Blog/blog and /blog/[slug], thin server shells over BlogIndex / BlogPost reading listBlogPosts() / getBlogPost(slug) (lib/blog.ts). Posts are static (generateStaticParams over the build-time collection).
  • Changelog/changelog and /changelog/[slug], mirroring the blog via lib/changelog.ts.
  • SEO, sitemap, robots, OG imagesmarketingMetadata(...) and absoluteUrl(...) (lib/seo.ts), marketingSitemap() (lib/sitemap.ts), and ogImageElement(...) (one PNG per post via next/og, no fonts fetched so the build stays offline). The core-root sitemap.ts / robots.ts call these behind markers and fall back to an empty sitemap / disallow-all when pruned.

Models it adds

None. Marketing wraps nothing in prisma/schema.prisma — blog and changelog content are MDX files under src/content/**, compiled into typed collections (allPosts, allChangelogs) rather than stored in the database.

Env it needs

None. Adds four dependencies — @content-collections/core, /next, /mdx, and @tailwindcss/typography — wired via withContentCollections(...) in next.config.ts and the @plugin "@tailwindcss/typography" directive in globals.css. content-collections is the template's content stack for apps/web (the docs site in apps/docs uses a separate fumadocs stack).

Composition

  • requires: ["billing"] — the pricing page imports PLANS from @/config/plans and PlanPicker from @/features/billing; the boundary rule permits that deep import precisely because marketing declares billing. Billing owns the plan config and picker; marketing supplies only the crawlable acquisition CTAs (deep-links into sign-up rather than in-page mutations).
  • Dependents — none; marketing is a leaf.

What pruning removes

Leaving marketing out drops the whole (marketing) route group (pricing, blog, changelog, layout, OG-image routes), features/marketing, the src/content MDX, content-collections.ts and its vitest global setup, and the four content-collections / typography dependencies. The shared core-root files that carry marketing markers stay but revert to their fallbacks: / redirects to /dashboard, sitemap.ts returns empty, and robots.ts disallows all. Because marketing is a leaf, pruning it removes only its own surface — nothing else breaks.

On this page