feat: add use cases marketing product with AI-generated content

Transform qualifying scenarios into marketing-ready use cases with:
- AI-generated titles, descriptions, ROI estimates, business value
- Persona/industry/category taxonomy for targeting
- Browseable feed with filtering and ranking
- SEO-optimized case study pages
- Daily cron job for generation and ranking

Database:
- Add Persona, Industry, Category lookup tables
- Add UseCase model with marketing content fields
- Add junction tables for personas/industries/categories
- Add SocialProof model for cached metrics

API:
- GET /api/use-cases - Global directory with filtering
- GET /api/use-cases/[id] - Individual use case details
- GET /api/public/users/[username]/collections/[slug]/use-cases
- POST /api/cron/use-cases - Nightly generation job

Frontend:
- /use-cases - Global feed with persona dropdown
- /use-cases/[slug] - SEO case study page
- /[username]/collections/[slug]/use-cases - Collection feed
- UseCasesFeed component - Sortable table component
- UseCaseCaseStudy component - Full case study layout
This commit is contained in:
Ajax Davis 2026-01-20 16:17:35 +10:00
parent 5fafc90e3e
commit 48c41e8733
245 changed files with 4734 additions and 2075 deletions

View file

@ -1,5 +1,5 @@
import { AgentExampleSlideshow } from '@/components/AgentExampleSlideshow';
import type { Metadata } from 'next';
import { AgentExampleSlideshow } from '@/components/AgentExampleSlideshow';
export const metadata: Metadata = {
title: 'Real-World Agent Example | TPMJS Tutorials',

View file

@ -1,5 +1,5 @@
import { FirstToolSlideshow } from '@/components/FirstToolSlideshow';
import type { Metadata } from 'next';
import { FirstToolSlideshow } from '@/components/FirstToolSlideshow';
export const metadata: Metadata = {
title: 'Build Your First Tool | TPMJS Tutorials',

View file

@ -139,9 +139,9 @@
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
animation-duration: 0.01ms;
animation-iteration-count: 1;
transition-duration: 0.01ms;
}
}
}

View file

@ -1,5 +1,5 @@
import { OverviewSlideshow } from '@/components/OverviewSlideshow';
import type { Metadata } from 'next';
import { OverviewSlideshow } from '@/components/OverviewSlideshow';
export const metadata: Metadata = {
title: 'Overview | TPMJS Tutorials',

View file

@ -1,5 +1,5 @@
import { PlaygroundSlideshow } from '@/components/PlaygroundSlideshow';
import type { Metadata } from 'next';
import { PlaygroundSlideshow } from '@/components/PlaygroundSlideshow';
export const metadata: Metadata = {
title: 'Interactive Playground | TPMJS Tutorials',

View file

@ -1,17 +1,17 @@
'use client';
import { useSlideshow } from '@/hooks/useSlideshow';
import { AnimatePresence } from 'framer-motion';
import Link from 'next/link';
import { Slide } from './Slide';
import { SlideNavigation } from './SlideNavigation';
import { SlideProgress } from './SlideProgress';
import { useSlideshow } from '@/hooks/useSlideshow';
import { AgentCodeSlide } from './agent-example-slides/AgentCodeSlide';
import { AgentExampleNextStepsSlide } from './agent-example-slides/AgentExampleNextStepsSlide';
import { AgentExampleWelcomeSlide } from './agent-example-slides/AgentExampleWelcomeSlide';
import { ExecutionFlowSlide } from './agent-example-slides/ExecutionFlowSlide';
import { SetupCodeSlide } from './agent-example-slides/SetupCodeSlide';
import { TheGoalSlide } from './agent-example-slides/TheGoalSlide';
import { Slide } from './Slide';
import { SlideNavigation } from './SlideNavigation';
import { SlideProgress } from './SlideProgress';
const SLIDES = [
{ id: 'welcome', Component: AgentExampleWelcomeSlide },

View file

@ -1,8 +1,8 @@
'use client';
import { useSlideshow } from '@/hooks/useSlideshow';
import { AnimatePresence } from 'framer-motion';
import Link from 'next/link';
import { useSlideshow } from '@/hooks/useSlideshow';
import { Slide } from './Slide';
import { SlideNavigation } from './SlideNavigation';
import { SlideProgress } from './SlideProgress';

View file

@ -1,11 +1,8 @@
'use client';
import { useSlideshow } from '@/hooks/useSlideshow';
import { AnimatePresence } from 'framer-motion';
import Link from 'next/link';
import { Slide } from './Slide';
import { SlideNavigation } from './SlideNavigation';
import { SlideProgress } from './SlideProgress';
import { useSlideshow } from '@/hooks/useSlideshow';
import { AuthorNextStepsSlide } from './author-slides/AuthorNextStepsSlide';
import { AuthorWelcomeSlide } from './author-slides/AuthorWelcomeSlide';
import { GetDiscoveredSlide } from './author-slides/GetDiscoveredSlide';
@ -15,6 +12,9 @@ import { PackageSetupSlide } from './author-slides/PackageSetupSlide';
import { QualityScoringSlide } from './author-slides/QualityScoringSlide';
import { ToolDefinitionSlide } from './author-slides/ToolDefinitionSlide';
import { WhatIsRegistrySlide } from './author-slides/WhatIsRegistrySlide';
import { Slide } from './Slide';
import { SlideNavigation } from './SlideNavigation';
import { SlideProgress } from './SlideProgress';
const SLIDES = [
{ id: 'welcome', Component: AuthorWelcomeSlide },

View file

@ -1,17 +1,17 @@
'use client';
import { useSlideshow } from '@/hooks/useSlideshow';
import { AnimatePresence } from 'framer-motion';
import Link from 'next/link';
import { Slide } from './Slide';
import { SlideNavigation } from './SlideNavigation';
import { SlideProgress } from './SlideProgress';
import { useSlideshow } from '@/hooks/useSlideshow';
import { FirstToolNextStepsSlide } from './first-tool-slides/FirstToolNextStepsSlide';
import { FirstToolWelcomeSlide } from './first-tool-slides/FirstToolWelcomeSlide';
import { PackageJsonSlide } from './first-tool-slides/PackageJsonSlide';
import { ProjectSetupSlide } from './first-tool-slides/ProjectSetupSlide';
import { PublishSlide } from './first-tool-slides/PublishSlide';
import { WriteToolSlide } from './first-tool-slides/WriteToolSlide';
import { Slide } from './Slide';
import { SlideNavigation } from './SlideNavigation';
import { SlideProgress } from './SlideProgress';
const SLIDES = [
{ id: 'welcome', Component: FirstToolWelcomeSlide },

View file

@ -1,17 +1,17 @@
'use client';
import { useSlideshow } from '@/hooks/useSlideshow';
import { AnimatePresence } from 'framer-motion';
import Link from 'next/link';
import { Slide } from './Slide';
import { SlideNavigation } from './SlideNavigation';
import { SlideProgress } from './SlideProgress';
import { useSlideshow } from '@/hooks/useSlideshow';
import { ArchitectureSlide } from './overview-slides/ArchitectureSlide';
import { EcosystemSlide } from './overview-slides/EcosystemSlide';
import { ExploreSlide } from './overview-slides/ExploreSlide';
import { OverviewWelcomeSlide } from './overview-slides/OverviewWelcomeSlide';
import { UseCasesSlide } from './overview-slides/UseCasesSlide';
import { WhatIsTpmjsSlide } from './overview-slides/WhatIsTpmjsSlide';
import { Slide } from './Slide';
import { SlideNavigation } from './SlideNavigation';
import { SlideProgress } from './SlideProgress';
const SLIDES = [
{ id: 'welcome', Component: OverviewWelcomeSlide },

View file

@ -1,17 +1,17 @@
'use client';
import { useSlideshow } from '@/hooks/useSlideshow';
import { AnimatePresence } from 'framer-motion';
import Link from 'next/link';
import { Slide } from './Slide';
import { SlideNavigation } from './SlideNavigation';
import { SlideProgress } from './SlideProgress';
import { useSlideshow } from '@/hooks/useSlideshow';
import { FillParametersSlide } from './playground-slides/FillParametersSlide';
import { FindToolSlide } from './playground-slides/FindToolSlide';
import { OpenPlaygroundSlide } from './playground-slides/OpenPlaygroundSlide';
import { PlaygroundNextStepsSlide } from './playground-slides/PlaygroundNextStepsSlide';
import { PlaygroundWelcomeSlide } from './playground-slides/PlaygroundWelcomeSlide';
import { SeeResultsSlide } from './playground-slides/SeeResultsSlide';
import { Slide } from './Slide';
import { SlideNavigation } from './SlideNavigation';
import { SlideProgress } from './SlideProgress';
const SLIDES = [
{ id: 'welcome', Component: PlaygroundWelcomeSlide },

View file

@ -1,6 +1,6 @@
'use client';
import { type Variants, motion } from 'framer-motion';
import { motion, type Variants } from 'framer-motion';
import type { ReactNode } from 'react';
interface SlideProps {