An innovative AI-powered fanfiction writing platform built with Next.js 16 and LangGraph.js.
Create amazing fanfiction with an AI assistant that understands your characters, respects canon, and helps bring your stories to life.
Featuring smart editing, creative wizard, fandom research, and Human-in-the-Loop approval workflows.
Live Demo · Report Bug · Request Feature
Share FanFic Lab
Pioneering the future of AI-assisted creative writing. Built for the fanfiction community.
Tech Stack
Important
FanFic Lab combines cutting-edge AI technology with a deep understanding of fanfiction culture. It features LangGraph.js for intelligent agent workflows with Human-in-the-Loop approval, Tavily for fandom research, and a beautiful "Literary Atelier" design system with Teal + Amber color palette.
Table of Contents
FanFic Lab is designed for the fanfiction community, providing:
- Smart Editor - AI-powered writing assistance with inline suggestions
- Creative Wizard - Conversational story setup with Human-in-the-Loop (HITL) forms
- Fandom Research - Tavily-powered research for characters, ships, and world-building
- Fandom Feed - Discover and filter stories by fandom, ships, and tags
- Character Management - Track characters and detect out-of-character moments
- Image Gallery - AI-generated character portraits and scene illustrations (coming soon)
graph TB
subgraph "User Interface"
A[Homepage] --> B[Creative Wizard]
A --> C[Smart Editor]
A --> D[Fandom Feed]
B --> C
end
subgraph "AI Layer"
E[CopilotKit Provider]
F[LangGraph Agent]
G[OpenAI GPT-4o]
H[Tavily Search]
end
subgraph "Backend"
I[Next.js API Routes]
J[Prisma ORM]
K[Neon PostgreSQL]
L[Redis Cache]
end
C --> E
B --> E
E --> I
I --> F
F --> G
F --> H
I --> J
J --> K
I --> L
Experience next-generation writing with AI-powered inline suggestions. The Smart Editor integrates CopilotKit for real-time assistance, helping you write better fanfiction faster.
| Feature | Description |
|---|---|
| CopilotTextarea | Inline AI suggestions while typing |
| Magic Continue | AI writes the next 200-300 words naturally |
| Expand Text | Enhance selected text with more dialogue/description/emotion |
| Polish Prose | Improve writing quality at light/medium/deep levels |
| Autosave | Automatic saving with debounce to localStorage |
| HITL Approval | Review and approve/edit AI-generated content |
Revolutionary story setup wizard that researches your fandom using Tavily API, understands your characters, and generates story outlines for your approval.
| Feature | Description |
|---|---|
| Fandom Selector | Browse popular fandoms or enter custom |
| Source Research | Tavily-powered research for characters, ships, world-building |
| Ship Builder | Define romantic pairings with AI suggestions |
| Character Setup | Add characters with AI-enhanced profiles |
| Outline Generation | AI creates story outline for HITL approval |
| Step Progress | Visual progress tracking through wizard |
Intelligent character management with out-of-character detection to keep your characters authentic.
| Feature | Description |
|---|---|
| Character Sidebar | Add/manage characters with personality traits |
| OOC Detection | AI checks for out-of-character moments |
| Character Profiles | Name, fandom, personality, speech patterns |
| Original Characters | Support for OCs with custom definitions |
| Dialogue Suggestions | In-character dialogue generation |
Discover and filter stories by fandom, ships, tags, rating, and status.
| Feature | Description |
|---|---|
| Story Cards | Display story info with cover images and metadata |
| Tag Filtering | Filter by relationship, setting, tone, content |
| Fandom Tabs | Quick navigation between fandoms |
| Rating/Status Filters | Filter by age rating and completion status |
| Sorting | Sort by recent, popular, comments, word count |
| Infinite Scroll | Load more stories seamlessly |
- 💨 Quick Setup: Auto-deploy via
git pushwith Coolify on DigitalOcean - 🌐 Responsive Design: Beautiful UI on desktop and mobile
- 🔒 Authentication: Stack Auth for secure user management
- 💎 Literary Atelier Design: Teal + Amber color palette with elegant typography
- 🗣️ Real-time AI: Live AI suggestions and generation
- 📊 Research Cache: Redis caching for Tavily search results (30-day TTL)
- 🔌 Extensible: Plugin-ready architecture for custom functionality
- ☁️ Cloud Storage: Cloudinary integration for image hosting
✨ More features are continuously being added as the project evolves.
| Layer | Technology | Deployment |
|---|---|---|
| Framework | Next.js 16 (App Router, Turbopack) | DigitalOcean + Coolify |
| UI | React 19, TailwindCSS 4, shadcn/ui | DigitalOcean + Coolify |
| AI Agent | LangGraph.js 1.0 | DigitalOcean + Coolify |
| Reverse Proxy | Traefik (via Coolify) | DigitalOcean |
| SSL / CDN | Cloudflare (proxy mode) | Cloudflare |
| LLM | OpenAI GPT-4o / GPT-4o-mini | OpenAI API |
| Search | Tavily API | Tavily |
| Database | Neon PostgreSQL + Prisma 7 | Neon |
| Cache | Redis (ioredis) | Upstash |
| Auth | Stack Auth | Stack Auth Cloud |
| Storage | Cloudinary | Cloudinary |
Tip
FanFic Lab runs on a DigitalOcean VPS with Coolify (self-hosted PaaS). Both the Next.js frontend and LangGraph agent are deployed as Docker Compose services, communicating via Docker internal networking. Cloudflare provides SSL and CDN.
graph TB
subgraph "Cloudflare"
CF[SSL + CDN + DNS]
end
subgraph "DigitalOcean VPS (Coolify)"
T[Traefik Reverse Proxy]
subgraph "Docker Compose"
A[Next.js 16 - Web] --> D[API Routes]
D --> E[Prisma 7]
F[LangGraph.js 1.0 - Agent] --> G[chat_node]
F --> H[research_node]
F --> I[outline_node]
F --> J[tool_node]
end
end
subgraph "External Services"
K[OpenAI API]
L[Tavily API]
M[LangSmith]
end
subgraph "Data Layer"
N[Neon PostgreSQL]
O[Redis Cache]
P[Cloudinary]
end
CF -->|HTTP| T
T --> A
D -->|Docker Network| F
G --> K
H --> L
F --> M
E --> N
D --> O
D --> P
The agent uses dedicated graph nodes for HITL operations instead of tools. This is a workaround for the CopilotKit/LangGraph.js ToolMessage format incompatibility.
graph TD
A[START] --> B{routeFromStart}
B -->|Research Request| C[research_node]
B -->|Outline Request| D[outline_node]
B -->|Default| E[chat_node]
C --> F[Tavily Search x4]
F --> G[LLM Aggregation]
G --> H[Emit State with researchData]
H --> I[Return AIMessage]
D --> J[Generate Outline]
J --> K[Set pendingContent]
K --> L[Emit State for HITL]
L --> I
E --> M{Has Tool Call?}
M -->|Yes| N[tool_node]
M -->|No| I
N --> O[Execute Tool]
O --> I
I --> P[END]
sequenceDiagram
participant U as User
participant FE as Frontend
participant CK as CopilotKit
participant Agent as LangGraph Agent
Agent->>CK: copilotkitEmitState(pendingContent)
CK->>FE: State Update
FE->>FE: useCoAgentStateRender detects pendingContent
FE->>U: Render Approval Card
U->>FE: Approve/Edit/Reject
FE->>CK: respond({ data })
CK->>Agent: Continue with user input
Important
Ensure you have the following installed:
- Node.js 20.9.0+ (required by Prisma 7.2.0)
- npm/yarn/pnpm package manager
- Git
- PostgreSQL database (Neon recommended)
- OpenAI API key
1. Clone Repository
git clone https://github.com/ChanMeng666/fanfic-lab.git
cd fanfic-lab2. Install Dependencies
npm install3. Environment Setup
cp .env.example .env.local
# Edit .env.local with your values4. Database Setup
# Generate Prisma client
npx prisma generate
# Run database migrations
npx prisma migrate dev5. Start Development
# Start both Next.js and LangGraph agent
npm run dev:all🎉 Success! Open http://localhost:3000 to view the application.
npm run dev # Start Next.js dev server only
npm run dev:agent # Start LangGraph agent only
npm run dev:all # Start both services (recommended)
npm run build # Build for production
npm run start # Start production server
npm run lint # Run ESLint# Database (Neon PostgreSQL)
DATABASE_URL=postgresql://user:pass@host.neon.tech/fanficlab?sslmode=require
# Stack Auth
STACK_SECRET_SERVER_KEY=ssk_...
NEXT_PUBLIC_STACK_PROJECT_ID=...
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=pck_...
# OpenAI (required for AI features)
OPENAI_API_KEY=sk-...
# LangGraph (local dev: localhost, production: http://agent:8123 via Docker Compose)
LANGGRAPH_URL=http://localhost:8123
# Redis (for research caching)
REDIS_URL=redis://localhost:6379
# Cloudinary (for image hosting)
CLOUDINARY_CLOUD_NAME=...
CLOUDINARY_API_KEY=...
CLOUDINARY_API_SECRET=...
# Optional: Together AI for image generation (currently disabled)
TOGETHER_API_KEY=...
# Optional: LangSmith for tracing
LANGSMITH_API_KEY=lsv2_...
# Optional: Admin endpoint protection
ADMIN_SECRET=...| Variable | Description | Required |
|---|---|---|
DATABASE_URL |
Neon PostgreSQL connection string | ✅ |
STACK_SECRET_SERVER_KEY |
Stack Auth server key | ✅ |
NEXT_PUBLIC_STACK_PROJECT_ID |
Stack Auth project ID | ✅ |
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY |
Stack Auth client key | ✅ |
LANGGRAPH_URL |
Agent URL (http://agent:8123 in Docker Compose) |
✅ |
OPENAI_API_KEY |
OpenAI API key | ✅ |
REDIS_URL |
Redis connection string | ✅ |
CLOUDINARY_* |
Cloudinary credentials | ✅ |
LANGSMITH_API_KEY |
LangSmith API key | 🔶 |
TAVILY_API_KEY |
Tavily API key (agent service) | ✅ |
ADMIN_SECRET |
Admin endpoint protection | 🔶 |
✅ Required, 🔶 Optional
erDiagram
User ||--o{ Story : writes
User ||--o{ Character : creates
User ||--o{ Draft : has
User ||--|| UserPreferences : configures
User ||--o{ Follow : follows
Story ||--o{ Chapter : contains
Story ||--o{ StoryCharacter : features
Story ||--o{ Like : receives
Story ||--o{ Comment : has
Character ||--o{ StoryCharacter : appears_in
Story ||--o{ Image : includes
User {
string id PK
string stackAuthId UK
string email UK
string username UK
string displayName
string avatarUrl
string bio
}
Story {
string id PK
string title
string summary
string fandom
string[] ships
string[] tags
enum rating
enum status
int wordCount
string coverImageUrl
}
Character {
string id PK
string name
string fandom
string[] personalityTraits
string speechPatterns
boolean isOriginal
string portraitUrl
}
SourceResearchCache {
string id PK
string sourceName
string sourceType
string normalizedName UK
json researchData
int searchCount
datetime lastAccessedAt
}
fanfic-lab/
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── api/ # API routes
│ │ │ ├── copilotkit/ # CopilotKit runtime
│ │ │ ├── research-cache/ # Redis caching
│ │ │ ├── health/ # Health check
│ │ │ ├── admin/cache-stats/ # Cache analytics
│ │ │ └── upload/cover/ # Cover upload
│ │ ├── (main)/ # Main routes
│ │ │ ├── (protected)/ # Auth required
│ │ │ │ ├── editor/ # Smart Editor
│ │ │ │ ├── wizard/ # Creative Wizard
│ │ │ │ └── profile/ # User Profile
│ │ │ └── feed/ # Fandom Feed (public)
│ │ └── handler/[...stack]/ # Stack Auth
│ │
│ ├── components/ # React components
│ │ ├── ui/ # shadcn/ui components
│ │ ├── editor/ # Editor components
│ │ ├── wizard/ # Wizard components
│ │ ├── feed/ # Feed components
│ │ ├── hitl/ # HITL approval cards
│ │ ├── layout/ # Layout components
│ │ └── providers/ # Context providers
│ │
│ ├── agent/ # LangGraph agent
│ │ ├── agent.ts # Workflow definition
│ │ ├── state.ts # State annotation
│ │ └── tools/ # Agent tools
│ │
│ └── lib/ # Utilities
│ ├── hooks/ # Custom hooks
│ ├── actions/ # Server actions
│ ├── types/ # TypeScript types
│ ├── db.ts # Database client
│ ├── redis.ts # Redis client
│ └── cloudinary.ts # Cloudinary client
│
├── prisma/
│ ├── schema.prisma # Database schema
│ └── migrations/ # Migrations
│
├── docs/
│ ├── COPILOTKIT_LANGGRAPH_HITL_GUIDE.md
│ └── MIGRATION_RAILWAY_TO_DIGITALOCEAN.md
│
└── public/ # Static assets
CopilotKit runtime endpoint that routes requests to the LangGraph agent.
const runtime = new CopilotRuntime({
agents: {
fanfic_agent: new LangGraphAgent({
deploymentUrl: process.env.LANGGRAPH_URL,
graphId: "fanfic_agent",
}),
},
});Research results caching endpoint (Redis).
| Method | Query/Body | Description |
|---|---|---|
| GET | ?sourceName=X&sourceType=Y |
Check if cached research exists |
| POST | { sourceName, sourceType, researchData } |
Save research results (30-day TTL) |
| DELETE | ?sourceName=X |
Clear cache (requires ADMIN_SECRET) |
Service health check endpoint.
{
"status": "healthy",
"services": {
"redis": { "status": "up", "latency": 5 },
"database": { "status": "up", "latency": 12 }
}
}Cover image upload endpoint.
- Validates user authentication and story ownership
- Accepts: jpeg, png, webp (max 5MB)
- Uploads to Cloudinary
- Returns: URL, publicId, dimensions
FanFic Lab runs on a DigitalOcean VPS with Coolify (self-hosted PaaS), using Docker Compose for both services. Cloudflare handles SSL and CDN.
Services:
| Service | Dockerfile | Port | Health Check |
|---|---|---|---|
| Web (Next.js) | Dockerfile.web |
3000 | /api/health |
| Agent (LangGraph) | Dockerfile.agent |
8123 | /info |
Deployment Compose: docker-compose.coolify.yml
| Service | URL |
|---|---|
| Frontend | https://fanfic-lab.tech |
| www (redirect) | https://www.fanfic-lab.tech → https://fanfic-lab.tech |
| Agent (Internal) | http://agent:8123 (Docker Compose network) |
| Coolify Dashboard | http://159.223.173.17:8000 |
| Method | Command |
|---|---|
| Auto-deploy | git push origin master (GitHub webhook → Coolify) |
| Manual (API) | curl -X POST http://159.223.173.17:8000/api/v1/applications/wea94e791gdrn59xv4tqnxdm/restart -H "Authorization: Bearer <token>" |
| Dashboard | Open Coolify → Deploy button |
┌──────────────┐
│ Cloudflare │
│ SSL + CDN │
└──────┬───────┘
│ HTTP
┌──────────────────────────┼────────────────────────┐
│ DigitalOcean VPS (Coolify) │
│ ┌───────┴───────┐ │
│ │ Traefik │ │
│ │ Reverse Proxy │ │
│ └───────┬───────┘ │
│ ┌───────────────────────┼───────────────────────┐│
│ │ Docker Compose Network ││
│ │ ┌─────────────────────┐ ┌──────────────────┐ ││
│ │ │ Web Service │ │ Agent Service │ ││
│ │ │ (Next.js 16) │ │ (LangGraph.js) │ ││
│ │ │ │ │ │ ││
│ │ │ • React 19 │ │ • chat_node │ ││
│ │ │ • Prisma 7 │ │ • research_node │ ││
│ │ │ • Stack Auth │ │ • outline_node │ ││
│ │ │ • Port 3000 │ │ • Port 8123 │ ││
│ │ └──────────┬──────────┘ └────────┬─────────┘ ││
│ │ │ http://agent:8123 │ ││
│ │ └─────────────────────┘ ││
│ └───────────────────────────────────────────────┘│
└──────────────────────────┼────────────────────────┘
│
┌─────────────────┼─────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Neon │ │ Upstash │ │Cloudinary│
│PostgreSQL│ │ Redis │ │ Images │
└──────────┘ └──────────┘ └──────────┘
For detailed migration history and Coolify setup guide, see docs/MIGRATION_RAILWAY_TO_DIGITALOCEAN.md.
We welcome contributions! Here's how you can help improve FanFic Lab:
1. Fork & Clone
git clone https://github.com/ChanMeng666/fanfic-lab.git
cd fanfic-lab2. Create Branch
git checkout -b feature/your-feature-name3. Make Changes
- Follow our coding standards in CLAUDE.md
- Add tests for new features
- Update documentation as needed
4. Submit PR
- Provide clear description
- Reference related issues
- Ensure CI passes
Chan Meng Creator & Lead Developer |
Chan Meng
LinkedIn: chanmeng666
GitHub: ChanMeng666
Email: chanmeng.dev@gmail.com
Website: chanmeng.org
This project is licensed under the MIT License - see the LICENSE file for details.
Open Source Benefits:
- ✅ Commercial use allowed
- ✅ Modification allowed
- ✅ Distribution allowed
- ✅ Private use allowed