A premium Generative Engine Optimization (GEO) consultant chatbot platform with subscription-based access ($59.99/month). Castor helps businesses optimize their content for AI search engines like ChatGPT, Perplexity, and Google AI Overviews.
π Live: trycastor.dev
Tech Stack:
- Frontend: Next.js 15 (App Router), React 18, TypeScript, Tailwind CSS, shadcn/ui
- State Management: TanStack React Query (server state + caching)
- Authentication: Clerk (Google OAuth, GitHub OAuth, email/password)
- Database: Supabase (PostgreSQL)
- Payments: Stripe (Subscriptions)
- AI Chatbot: Dify AI (API proxy with streaming SSE)
- Hosting: Vercel
- Styling: Tailwind CSS + shadcn/ui components
Key Features:
- β Multi-provider authentication via Clerk (Google, GitHub, email/password)
- β Subscription-based paywall ($59.99/month)
- β Stripe Checkout integration with webhook handling
- β AI chatbot with real-time streaming and conversation persistence
- β Rate limiting (30 requests/minute per user)
- β Payment grace period for failed recurring payments
- β Stripe Customer Portal for self-service billing
- β Fully responsive landing page with SEO optimization
- β Server-side payment verification
castor-1/
βββ frontend/ # Next.js application
β βββ app/ # Next.js App Router
β β βββ page.tsx # Landing page
β β βββ layout.tsx # Root layout with Clerk provider
β β βββ providers.tsx # TanStack Query provider
β β βββ loading.tsx # Global loading state
β β βββ sign-in/ # Clerk sign-in page
β β βββ sign-up/ # Clerk sign-up page
β β βββ dashboard/ # Protected dashboard (paywall + chatbot)
β β βββ api/ # API routes
β β βββ checkout/ # Stripe Checkout session creation
β β βββ customer-portal/ # Stripe Customer Portal session
β β βββ verify-checkout/ # Verify checkout completion
β β βββ dify/ # Dify AI proxy endpoints
β β β βββ chat/ # Stream chat messages
β β β βββ conversations/ # List conversations
β β β βββ messages/ # Get conversation messages
β β β βββ delete/ # Delete conversation
β β β βββ rename/ # Rename conversation
β β β βββ stop/ # Stop generation
β β β βββ generate-title/ # Generate conversation title
β β βββ generate-title/ # OpenRouter title generation
β β βββ webhook/stripe/ # Stripe webhook handler
β βββ components/ # React components
β β βββ ui/ # shadcn/ui components
β β βββ landing/ # Landing page sections
β β β βββ hero-section.tsx
β β β βββ value-proposition-section.tsx
β β β βββ services-section.tsx
β β β βββ testimonials-section.tsx
β β β βββ final-cta-section.tsx
β β β βββ chat-preview.tsx
β β βββ assistant-ui/ # Chat interface components
β β β βββ thread.tsx # Conversation view
β β β βββ threadlist-sidebar.tsx # Conversation list
β β β βββ sidebar/ # Sidebar subcomponents
β β βββ assistant-ui-dashboard.tsx # Main chat dashboard
β β βββ header.tsx # Site header with navigation
β β βββ footer.tsx # Site footer
β β βββ paywall-card.tsx # Subscription paywall
β β βββ grace-period-warning.tsx # Payment failure warning
β β βββ checkout-verifier.tsx # Verify checkout completion
β β βββ user-menu.tsx # User menu with billing link
β βββ lib/ # Utilities and helpers
β β βββ auth/
β β β βββ verify-subscription.ts # Subscription verification
β β βββ dify/
β β β βββ client.ts # Centralized Dify API client
β β β βββ errors.ts # Error handling utilities
β β βββ hooks/
β β β βββ use-dify-chat.ts # Chat state & streaming
β β β βββ use-conversations.ts # Conversation management
β β βββ middleware/
β β β βββ rate-limit.ts # In-memory rate limiting
β β βββ openrouter/
β β β βββ title-generator.ts # AI title generation
β β βββ supabase/
β β β βββ server.ts # Server-side Supabase client
β β β βββ admin.ts # Admin Supabase client
β β βββ content/
β β β βββ landing-page-content.ts # Landing page content
β β βββ types.ts # TypeScript type definitions
β β βββ utils.ts # Utility functions (cn, etc.)
β βββ middleware.ts # Clerk authentication middleware
β βββ .env.local # Local environment variables
β βββ .env.production # Production env reference
βββ CLAUDE.md # AI agent instructions
- Node.js 22.x
- npm or pnpm
- Clerk account
- Supabase project
- Stripe account
- Dify AI chatbot instance
-
Clone the repository:
git clone https://github.com/mchen04/castor.git cd castor-1/frontend -
Install dependencies:
npm install
-
Set up environment variables:
Copy
.env.exampleto.env.localand fill in your credentials:cp .env.example .env.local
Required variables:
# Supabase NEXT_PUBLIC_SUPABASE_URL=your-supabase-url NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key SUPABASE_SERVICE_ROLE_KEY=your-service-role-key # Stripe NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=your-stripe-publishable-key STRIPE_SECRET_KEY=your-stripe-secret-key STRIPE_WEBHOOK_SECRET=your-stripe-webhook-secret STRIPE_PRICE_ID=your-stripe-price-id # Clerk NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your-clerk-publishable-key CLERK_SECRET_KEY=your-clerk-secret-key NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL=/dashboard NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL=/dashboard # Dify AI DIFY_API_KEY=your-dify-api-key # OpenRouter (for title generation) OPENROUTER_API_KEY=your-openrouter-api-key # App NEXT_PUBLIC_SITE_URL=http://localhost:3000
-
Run development server:
npm run dev
Visit http://localhost:3000
Supabase Tables:
- id: uuid (primary key, generated)
- clerk_id: text (unique, NOT NULL - Clerk user identifier)
- email: text
- has_paid: boolean (default: false)
- stripe_customer_id: text (unique)
- stripe_subscription_id: text (unique)
- stripe_subscription_status: text (active, trialing, past_due, canceled, unpaid, etc.)
- stripe_subscription_current_period_end: timestamptz
- stripe_subscription_cancel_at_period_end: boolean
- in_grace_period: boolean (default: false)
- created_at: timestamptz
- updated_at: timestamptz (auto-updated)- id: uuid (primary key)
- event_id: text (unique, Stripe event ID)
- created_at: timestamp- User signs in with Clerk (Google/GitHub OAuth or email/password)
- Clerk redirects to Dashboard
- Dashboard checks payment status from Supabase
userstable (byclerk_id) - If not subscribed β PaywallCard component shows Stripe Checkout button
- User clicks "Subscribe" β
/api/checkoutcreates Stripe Checkout session - User completes payment on Stripe
- Stripe sends
checkout.session.completedwebhook β/api/webhook/stripe - Webhook handler:
- Verifies signature
- Checks idempotency (
processed_eventstable) - Updates
userstable with subscription metadata
- User returns to dashboard β sees chatbot
- Success:
invoice.payment_succeededwebhook clears grace period - Failure:
invoice.payment_failedwebhook sets grace period flag - Grace Period: User sees warning banner but maintains access during Stripe's retry window
- User clicks "Manage Billing" β Stripe Customer Portal
- Cancels subscription β
customer.subscription.deletedwebhook revokes access
The Dify AI chatbot is integrated via API proxy pattern using Vercel Serverless Functions:
Key Features:
- API Proxy: All Dify API calls routed through
/api/dify/*endpoints - Authentication: Clerk user verification + Supabase subscription check
- User Identification: Clerk user ID passed to Dify API for conversation persistence
- Rate Limiting: 30 requests/minute per user
- Streaming Chat: Real-time responses via Server-Sent Events (SSE)
- Error Handling: User-friendly error messages with retry logic
- Title Generation: AI-powered conversation titles via OpenRouter
Architecture:
Client β /api/dify/chat β Clerk Auth β Subscription Check β Dify API β SSE Stream β Client
API Endpoints:
POST /api/dify/chat- Send chat message (streaming)GET /api/dify/conversations- List conversationsGET /api/dify/messages- Get conversation messagesPOST /api/dify/delete- Delete conversationPOST /api/dify/rename- Rename conversationPOST /api/dify/stop- Stop generationPOST /api/generate-title- Generate conversation title
Authentication: Clerk handles all auth (Google OAuth, GitHub OAuth, email/password) Authorization: Middleware + server-side payment checks
- Protects routes except:
/,/sign-in,/sign-up,/api/webhook - Uses Clerk's
clerkMiddlewarefor session management - Automatic session refresh and CSRF protection
- Client-side: Dashboard reads user data from Supabase
- Server-side: API routes verify payment status before granting access
- Webhook: Stripe webhooks update payment status in real-time
POST /api/checkout
Creates Stripe Checkout session for new subscriptions.
POST /api/customer-portal
Creates Stripe Customer Portal session for billing management.
GET /api/verify-checkout
Verifies checkout session completion.
POST /api/webhook/stripe
Handles Stripe webhook events with signature verification and idempotency.
POST /api/dify/chat
Send chat message with streaming SSE response. Requires active subscription. Rate limited to 30 req/min.
GET /api/dify/conversations
List user's conversations with pagination.
GET /api/dify/messages
Get messages from specific conversation.
POST /api/dify/delete
Delete a conversation.
POST /api/dify/rename
Rename a conversation.
POST /api/dify/stop
Stop generating a streaming response.
POST /api/dify/generate-title
Auto-generate conversation title.
POST /api/generate-title
Generate conversation title using OpenRouter AI.
Built with shadcn/ui and custom components:
HeroSection- Hero with CTAValuePropositionSection- Value proposition with feature highlightsServicesSection- Feature cardsTestimonialsSection- Customer testimonialsFinalCTASection- Bottom CTAChatPreview- Interactive chat preview demo
PaywallCard- Subscription paywallAssistantUIDashboard- Main chat dashboard orchestratorThread- Conversation message viewThreadlistSidebar- Conversation list with sidebar navigationGracePeriodWarning- Payment failure alertUserMenu- User dropdown with billing linkCheckoutVerifier- Verify checkout completion
- Button, Card, Dialog, Dropdown, Input, Select, Tabs, Toast, etc.
Type Checking:
npm run type-checkLinting:
npm run lintUnused Code Detection:
npm run check:unused # Detect unused code and dependencies
npm run fix:unused # Auto-fix detected unused codeRun All Checks:
npm run check:all # Type + Lint + Unused detectionBuild:
npm run buildPlatform: Vercel
Add all variables from .env.production to Vercel:
- Settings β Environment Variables β Add each variable
-
Add webhook endpoint in Stripe Dashboard:
https://trycastor.dev/api/webhook/stripe -
Subscribe to events:
checkout.session.completedcustomer.subscription.updatedcustomer.subscription.deletedinvoice.payment_succeededinvoice.payment_failed
-
Copy webhook signing secret to
STRIPE_WEBHOOK_SECRETin Vercel
git push origin mainVercel auto-deploys on push to main branch.
- TypeScript: Strict mode, explicit types
- Components: PascalCase files, kebab-case for multi-word
- Functions: camelCase
- Constants: UPPER_SNAKE_CASE
- Files: Keep under 350 lines, split if needed
- Never commit secrets (use
.env.local) - Validate all webhook signatures
- Use Row Level Security (RLS) in Supabase
- Server-side payment verification only
mainbranch for production- Feature branches for development
- Vercel previews for pull requests
Issue: Clerk redirects to /login (404)
- Fix: Ensure
NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL=/dashboardis set in Vercel
Issue: Stripe webhook not working
- Fix: Check webhook signature secret, verify endpoint URL in Stripe Dashboard
Issue: Chatbot not loading
- Fix: Verify user has active subscription, check Dify URL and user_id encoding
Issue: Payment status not updating
- Fix: Check Supabase webhook logs, verify
processed_eventstable for duplicates
Proprietary - All rights reserved
Michael Chen
- GitHub: @mchen04
- Email: michaelluochen1@gmail.com