Created comprehensive launch materials and monetization foundation. Marketing Materials Created: 1. DEMO_VIDEO_SCRIPT.md (90-second demo script) - Complete shot-by-shot breakdown - Voiceover script with timing - B-roll suggestions - Social media cut variations (30s, 60s) - Publishing checklist - Music recommendations - Target: 10K+ views in first week 2. PRODUCT_HUNT_LAUNCH.md (Complete PH strategy) - Optimized product listing copy - Founder's first comment (1000+ words) - 6-8 gallery images specifications - Hour-by-hour launch day plan - Comment response templates - Success metrics and goals - Community outreach strategy - Email campaign templates - Target: Top 5 product of the day 3. AUTHENTICATION_SETUP.md (Clerk + Stripe guide) - Step-by-step Clerk integration - Subscription tier definitions (Free/Studio/Pro/Enterprise) - Feature gating implementation - Stripe payment integration - Webhook handling - Usage tracking system - Implementation checklist - Target: Monetization-ready in 4 weeks Strategic Impact: Launch Readiness: ✅ Demo video script ready to record ✅ Product Hunt listing optimized ✅ Social media strategy planned ✅ Authentication roadmap defined ✅ Monetization path clear Revenue Model: - Free: 5 templates, no translation - Studio ($15/mo): All templates, desktop app - Pro ($45/mo): AI translation + collaboration - Enterprise: Custom pricing Time to Launch: - Record demo: 2-3 hours - Product Hunt submission: 30 minutes - Clerk auth implementation: 1 week - Stripe integration: 1 week - Total: 2-3 weeks to full monetization Next Actions: 1. Record demo video using provided script 2. Schedule Product Hunt launch (Tuesday-Thursday) 3. Implement Clerk authentication 4. Add Stripe payments 5. Deploy to production 6. Launch and scale!
661 lines
15 KiB
Markdown
661 lines
15 KiB
Markdown
# 🔐 Authentication Setup Guide (Clerk Integration)
|
|
|
|
Complete guide to adding authentication to AeThex Studio for monetization and user management.
|
|
|
|
---
|
|
|
|
## 🎯 Why Authentication?
|
|
|
|
**Required for**:
|
|
- User accounts and profiles
|
|
- Feature gating by tier (Free/Studio/Pro)
|
|
- Billing and subscriptions
|
|
- Team collaboration
|
|
- Usage tracking and analytics
|
|
- API key management
|
|
|
|
---
|
|
|
|
## 🚀 Quick Start (30 minutes)
|
|
|
|
### Step 1: Create Clerk Account
|
|
|
|
1. Visit: https://clerk.com
|
|
2. Sign up (free tier: 10,000 MAU)
|
|
3. Create new application: "AeThex Studio"
|
|
4. Select authentication methods:
|
|
- ✅ Email + Password
|
|
- ✅ Google OAuth
|
|
- ✅ GitHub OAuth
|
|
- ⚠️ Magic Links (optional)
|
|
|
|
### Step 2: Install Dependencies
|
|
|
|
```bash
|
|
npm install @clerk/nextjs
|
|
```
|
|
|
|
### Step 3: Add Environment Variables
|
|
|
|
```bash
|
|
# .env.local
|
|
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
|
|
CLERK_SECRET_KEY=sk_test_...
|
|
|
|
# Optional: Customize URLs
|
|
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
|
|
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
|
|
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/
|
|
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/
|
|
```
|
|
|
|
Get keys from: https://dashboard.clerk.com/apps → API Keys
|
|
|
|
---
|
|
|
|
## 📁 File Structure
|
|
|
|
```
|
|
src/
|
|
├── app/
|
|
│ ├── sign-in/
|
|
│ │ └── [[...sign-in]]/
|
|
│ │ └── page.tsx
|
|
│ ├── sign-up/
|
|
│ │ └── [[...sign-up]]/
|
|
│ │ └── page.tsx
|
|
│ └── layout.tsx (wrap with ClerkProvider)
|
|
├── middleware.ts (protect routes)
|
|
└── components/
|
|
└── UserButton.tsx (user menu)
|
|
```
|
|
|
|
---
|
|
|
|
## 🛠️ Implementation
|
|
|
|
### 1. Update Next.js Layout
|
|
|
|
**File**: `src/app/layout.tsx`
|
|
|
|
```typescript
|
|
import { ClerkProvider } from '@clerk/nextjs';
|
|
|
|
export default function RootLayout({
|
|
children,
|
|
}: {
|
|
children: React.ReactNode;
|
|
}) {
|
|
return (
|
|
<ClerkProvider>
|
|
<html lang="en">
|
|
<body>{children}</body>
|
|
</html>
|
|
</ClerkProvider>
|
|
);
|
|
}
|
|
```
|
|
|
|
### 2. Create Sign-In Page
|
|
|
|
**File**: `src/app/sign-in/[[...sign-in]]/page.tsx`
|
|
|
|
```typescript
|
|
import { SignIn } from '@clerk/nextjs';
|
|
|
|
export default function Page() {
|
|
return (
|
|
<div className="flex items-center justify-center min-h-screen">
|
|
<SignIn />
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
### 3. Create Sign-Up Page
|
|
|
|
**File**: `src/app/sign-up/[[...sign-up]]/page.tsx`
|
|
|
|
```typescript
|
|
import { SignUp } from '@clerk/nextjs';
|
|
|
|
export default function Page() {
|
|
return (
|
|
<div className="flex items-center justify-center min-h-screen">
|
|
<SignUp />
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
### 4. Add Middleware (Route Protection)
|
|
|
|
**File**: `src/middleware.ts`
|
|
|
|
```typescript
|
|
import { authMiddleware } from '@clerk/nextjs';
|
|
|
|
// Protect all routes except public ones
|
|
export default authMiddleware({
|
|
publicRoutes: [
|
|
'/',
|
|
'/sign-in(.*)',
|
|
'/sign-up(.*)',
|
|
'/api/public(.*)',
|
|
],
|
|
});
|
|
|
|
export const config = {
|
|
matcher: ['/((?!.+\\.[\\w]+$|_next).*)', '/', '/(api|trpc)(.*)'],
|
|
};
|
|
```
|
|
|
|
### 5. Add User Button to Toolbar
|
|
|
|
**File**: `src/components/Toolbar.tsx`
|
|
|
|
```typescript
|
|
import { UserButton, SignInButton, useUser } from '@clerk/nextjs';
|
|
|
|
export function Toolbar({ ... }: ToolbarProps) {
|
|
const { isSignedIn, user } = useUser();
|
|
|
|
return (
|
|
<div className="flex items-center gap-2">
|
|
{/* Existing toolbar items */}
|
|
|
|
{/* Add authentication */}
|
|
{isSignedIn ? (
|
|
<div className="flex items-center gap-2">
|
|
<span className="text-sm text-muted-foreground">
|
|
{user.fullName || user.emailAddress}
|
|
</span>
|
|
<UserButton afterSignOutUrl="/" />
|
|
</div>
|
|
) : (
|
|
<SignInButton mode="modal">
|
|
<button className="px-4 py-2 bg-accent text-white rounded">
|
|
Sign In
|
|
</button>
|
|
</SignInButton>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🎫 Feature Gating (Subscription Tiers)
|
|
|
|
### 1. Define User Tiers
|
|
|
|
**File**: `src/lib/subscription-tiers.ts`
|
|
|
|
```typescript
|
|
export type SubscriptionTier = 'free' | 'studio' | 'pro' | 'enterprise';
|
|
|
|
export interface TierFeatures {
|
|
name: string;
|
|
price: number;
|
|
features: {
|
|
translation: boolean;
|
|
desktopApp: boolean;
|
|
maxTemplates: number;
|
|
teamCollaboration: boolean;
|
|
prioritySupport: boolean;
|
|
};
|
|
}
|
|
|
|
export const tiers: Record<SubscriptionTier, TierFeatures> = {
|
|
free: {
|
|
name: 'Foundation',
|
|
price: 0,
|
|
features: {
|
|
translation: false,
|
|
desktopApp: false,
|
|
maxTemplates: 5,
|
|
teamCollaboration: false,
|
|
prioritySupport: false,
|
|
},
|
|
},
|
|
studio: {
|
|
name: 'Studio',
|
|
price: 15,
|
|
features: {
|
|
translation: false,
|
|
desktopApp: true,
|
|
maxTemplates: -1, // unlimited
|
|
teamCollaboration: false,
|
|
prioritySupport: true,
|
|
},
|
|
},
|
|
pro: {
|
|
name: 'Pro',
|
|
price: 45,
|
|
features: {
|
|
translation: true, // 🔥 KILLER FEATURE
|
|
desktopApp: true,
|
|
maxTemplates: -1,
|
|
teamCollaboration: true,
|
|
prioritySupport: true,
|
|
},
|
|
},
|
|
enterprise: {
|
|
name: 'Enterprise',
|
|
price: 0, // Custom pricing
|
|
features: {
|
|
translation: true,
|
|
desktopApp: true,
|
|
maxTemplates: -1,
|
|
teamCollaboration: true,
|
|
prioritySupport: true,
|
|
},
|
|
},
|
|
};
|
|
```
|
|
|
|
### 2. Add Tier to User Metadata
|
|
|
|
In Clerk Dashboard:
|
|
1. Go to "Users" → "Metadata"
|
|
2. Add public metadata field: `subscriptionTier`
|
|
3. Default value: `"free"`
|
|
|
|
### 3. Check User Tier
|
|
|
|
**File**: `src/lib/use-subscription.ts`
|
|
|
|
```typescript
|
|
import { useUser } from '@clerk/nextjs';
|
|
import { tiers, SubscriptionTier } from './subscription-tiers';
|
|
|
|
export function useSubscription() {
|
|
const { user } = useUser();
|
|
|
|
const tier: SubscriptionTier =
|
|
(user?.publicMetadata?.subscriptionTier as SubscriptionTier) || 'free';
|
|
|
|
const features = tiers[tier].features;
|
|
|
|
const hasFeature = (feature: keyof typeof features): boolean => {
|
|
return features[feature] as boolean;
|
|
};
|
|
|
|
const canUseTemplates = (count: number): boolean => {
|
|
if (features.maxTemplates === -1) return true;
|
|
return count <= features.maxTemplates;
|
|
};
|
|
|
|
return {
|
|
tier,
|
|
features,
|
|
hasFeature,
|
|
canUseTemplates,
|
|
isProOrHigher: tier === 'pro' || tier === 'enterprise',
|
|
};
|
|
}
|
|
```
|
|
|
|
### 4. Gate Translation Feature
|
|
|
|
**File**: `src/components/Toolbar.tsx`
|
|
|
|
```typescript
|
|
import { useSubscription } from '@/lib/use-subscription';
|
|
|
|
export function Toolbar({ ... }: ToolbarProps) {
|
|
const { hasFeature, tier } = useSubscription();
|
|
|
|
const handleTranslateClick = () => {
|
|
if (!hasFeature('translation')) {
|
|
toast.error('Translation requires Pro plan. Upgrade to unlock!');
|
|
// Redirect to pricing page
|
|
window.location.href = '/pricing';
|
|
return;
|
|
}
|
|
|
|
setShowTranslation(true);
|
|
};
|
|
|
|
return (
|
|
<Button onClick={handleTranslateClick}>
|
|
Translate
|
|
{!hasFeature('translation') && (
|
|
<Badge className="ml-2">PRO</Badge>
|
|
)}
|
|
</Button>
|
|
);
|
|
}
|
|
```
|
|
|
|
### 5. Gate Templates
|
|
|
|
**File**: `src/components/TemplatesDrawer.tsx`
|
|
|
|
```typescript
|
|
import { useSubscription } from '@/lib/use-subscription';
|
|
|
|
export function TemplatesDrawer({ ... }: TemplatesDrawerProps) {
|
|
const { canUseTemplates, features, tier } = useSubscription();
|
|
|
|
const handleTemplateClick = (template: ScriptTemplate, index: number) => {
|
|
// Check if user can access this template
|
|
if (!canUseTemplates(index + 1)) {
|
|
toast.error(
|
|
`Template ${index + 1} requires ${features.maxTemplates < index + 1 ? 'Studio' : 'Free'} plan or higher`
|
|
);
|
|
return;
|
|
}
|
|
|
|
onSelectTemplate(template.code);
|
|
onClose();
|
|
};
|
|
|
|
return (
|
|
{/* ... */}
|
|
{platformTemplates.map((template, index) => (
|
|
<Card
|
|
key={template.id}
|
|
className={`
|
|
p-4 cursor-pointer
|
|
${!canUseTemplates(index + 1) && 'opacity-50 cursor-not-allowed'}
|
|
`}
|
|
onClick={() => handleTemplateClick(template, index)}
|
|
>
|
|
<div className="flex items-start justify-between">
|
|
<h3>{template.name}</h3>
|
|
{!canUseTemplates(index + 1) && (
|
|
<Badge>
|
|
{tier === 'free' ? 'STUDIO' : 'PRO'}
|
|
</Badge>
|
|
)}
|
|
</div>
|
|
{/* ... */}
|
|
</Card>
|
|
))}
|
|
);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 💳 Stripe Integration (Payments)
|
|
|
|
### 1. Install Stripe
|
|
|
|
```bash
|
|
npm install @stripe/stripe-js stripe
|
|
```
|
|
|
|
### 2. Add Environment Variables
|
|
|
|
```bash
|
|
# .env.local
|
|
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
|
|
STRIPE_SECRET_KEY=sk_test_...
|
|
STRIPE_WEBHOOK_SECRET=whsec_...
|
|
```
|
|
|
|
### 3. Create Pricing Page
|
|
|
|
**File**: `src/app/pricing/page.tsx`
|
|
|
|
```typescript
|
|
import { tiers } from '@/lib/subscription-tiers';
|
|
|
|
export default function PricingPage() {
|
|
return (
|
|
<div className="container mx-auto py-12">
|
|
<h1 className="text-4xl font-bold text-center mb-12">
|
|
Choose Your Plan
|
|
</h1>
|
|
|
|
<div className="grid md:grid-cols-4 gap-6">
|
|
{Object.entries(tiers).map(([key, tier]) => (
|
|
<div key={key} className="border rounded-lg p-6">
|
|
<h2 className="text-2xl font-bold">{tier.name}</h2>
|
|
<p className="text-4xl font-bold my-4">
|
|
${tier.price}
|
|
{tier.price > 0 && <span className="text-lg">/mo</span>}
|
|
</p>
|
|
|
|
<ul className="space-y-2 mb-6">
|
|
<li>✓ {tier.features.maxTemplates === -1 ? 'Unlimited' : tier.features.maxTemplates} Templates</li>
|
|
<li>{tier.features.translation ? '✓' : '✗'} AI Translation</li>
|
|
<li>{tier.features.desktopApp ? '✓' : '✗'} Desktop App</li>
|
|
<li>{tier.features.teamCollaboration ? '✓' : '✗'} Team Collaboration</li>
|
|
<li>{tier.features.prioritySupport ? '✓' : '✗'} Priority Support</li>
|
|
</ul>
|
|
|
|
<button className="w-full bg-accent text-white py-2 rounded">
|
|
{tier.price === 0 ? 'Current Plan' : 'Upgrade'}
|
|
</button>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
### 4. Create Checkout API Route
|
|
|
|
**File**: `src/app/api/create-checkout-session/route.ts`
|
|
|
|
```typescript
|
|
import { NextResponse } from 'next/server';
|
|
import Stripe from 'stripe';
|
|
import { auth } from '@clerk/nextjs';
|
|
|
|
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
|
|
apiVersion: '2023-10-16',
|
|
});
|
|
|
|
export async function POST(req: Request) {
|
|
const { userId } = auth();
|
|
|
|
if (!userId) {
|
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
}
|
|
|
|
const { tier } = await req.json();
|
|
|
|
// Price IDs from Stripe Dashboard
|
|
const priceIds = {
|
|
studio: 'price_studio_monthly',
|
|
pro: 'price_pro_monthly',
|
|
};
|
|
|
|
const session = await stripe.checkout.sessions.create({
|
|
customer_email: userId, // Or get from Clerk
|
|
line_items: [
|
|
{
|
|
price: priceIds[tier as keyof typeof priceIds],
|
|
quantity: 1,
|
|
},
|
|
],
|
|
mode: 'subscription',
|
|
success_url: `${process.env.NEXT_PUBLIC_APP_URL}/dashboard?success=true`,
|
|
cancel_url: `${process.env.NEXT_PUBLIC_APP_URL}/pricing?canceled=true`,
|
|
metadata: {
|
|
userId,
|
|
tier,
|
|
},
|
|
});
|
|
|
|
return NextResponse.json({ url: session.url });
|
|
}
|
|
```
|
|
|
|
### 5. Handle Webhooks
|
|
|
|
**File**: `src/app/api/webhooks/stripe/route.ts`
|
|
|
|
```typescript
|
|
import { NextResponse } from 'next/server';
|
|
import Stripe from 'stripe';
|
|
import { clerkClient } from '@clerk/nextjs';
|
|
|
|
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
|
|
apiVersion: '2023-10-16',
|
|
});
|
|
|
|
export async function POST(req: Request) {
|
|
const body = await req.text();
|
|
const sig = req.headers.get('stripe-signature')!;
|
|
|
|
let event: Stripe.Event;
|
|
|
|
try {
|
|
event = stripe.webhooks.constructEvent(
|
|
body,
|
|
sig,
|
|
process.env.STRIPE_WEBHOOK_SECRET!
|
|
);
|
|
} catch (err) {
|
|
return NextResponse.json({ error: 'Webhook error' }, { status: 400 });
|
|
}
|
|
|
|
// Handle successful payment
|
|
if (event.type === 'checkout.session.completed') {
|
|
const session = event.data.object as Stripe.Checkout.Session;
|
|
const userId = session.metadata?.userId;
|
|
const tier = session.metadata?.tier;
|
|
|
|
if (userId && tier) {
|
|
// Update user's tier in Clerk
|
|
await clerkClient.users.updateUserMetadata(userId, {
|
|
publicMetadata: {
|
|
subscriptionTier: tier,
|
|
stripeCustomerId: session.customer,
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
// Handle subscription cancellation
|
|
if (event.type === 'customer.subscription.deleted') {
|
|
const subscription = event.data.object as Stripe.Subscription;
|
|
// Downgrade user to free tier
|
|
}
|
|
|
|
return NextResponse.json({ received: true });
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 Usage Tracking (Optional)
|
|
|
|
### Track API Usage Per User
|
|
|
|
**File**: `src/lib/usage-tracking.ts`
|
|
|
|
```typescript
|
|
import { auth } from '@clerk/nextjs';
|
|
import { createClient } from '@supabase/supabase-js';
|
|
|
|
const supabase = createClient(
|
|
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
|
process.env.SUPABASE_SERVICE_KEY!
|
|
);
|
|
|
|
export async function trackTranslation(
|
|
sourcePlatform: string,
|
|
targetPlatform: string
|
|
) {
|
|
const { userId } = auth();
|
|
|
|
if (!userId) return;
|
|
|
|
await supabase.from('usage').insert({
|
|
user_id: userId,
|
|
action: 'translation',
|
|
source_platform: sourcePlatform,
|
|
target_platform: targetPlatform,
|
|
timestamp: new Date().toISOString(),
|
|
});
|
|
}
|
|
|
|
export async function getUserUsage(userId: string, month: string) {
|
|
const { data } = await supabase
|
|
.from('usage')
|
|
.select('*')
|
|
.eq('user_id', userId)
|
|
.gte('timestamp', `${month}-01`)
|
|
.lte('timestamp', `${month}-31`);
|
|
|
|
return {
|
|
translationCount: data?.filter(u => u.action === 'translation').length || 0,
|
|
};
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## ✅ Implementation Checklist
|
|
|
|
### Phase 1: Basic Auth (Week 1)
|
|
- [ ] Install Clerk
|
|
- [ ] Add environment variables
|
|
- [ ] Create sign-in/sign-up pages
|
|
- [ ] Add middleware
|
|
- [ ] Add UserButton to Toolbar
|
|
- [ ] Test authentication flow
|
|
|
|
### Phase 2: Feature Gating (Week 2)
|
|
- [ ] Define subscription tiers
|
|
- [ ] Create `use-subscription` hook
|
|
- [ ] Gate translation feature
|
|
- [ ] Gate templates (5 free, rest require Studio+)
|
|
- [ ] Add upgrade prompts
|
|
- [ ] Create pricing page
|
|
|
|
### Phase 3: Payments (Week 3)
|
|
- [ ] Install Stripe
|
|
- [ ] Create products in Stripe Dashboard
|
|
- [ ] Implement checkout API
|
|
- [ ] Add webhook handler
|
|
- [ ] Test payment flow
|
|
- [ ] Handle subscription management
|
|
|
|
### Phase 4: Polish (Week 4)
|
|
- [ ] Add usage tracking
|
|
- [ ] Create user dashboard
|
|
- [ ] Implement billing portal
|
|
- [ ] Add team features (Pro tier)
|
|
- [ ] Test edge cases
|
|
- [ ] Deploy to production
|
|
|
|
---
|
|
|
|
## 🎯 Quick Win: Free vs Pro
|
|
|
|
**Easiest monetization path**:
|
|
|
|
1. **Free Tier**:
|
|
- 5 templates (1 per category)
|
|
- No translation (show "Upgrade to Pro" message)
|
|
- Web IDE only
|
|
|
|
2. **Pro Tier ($45/mo)**:
|
|
- ✅ **AI Translation** (killer feature)
|
|
- ✅ All 43 templates
|
|
- ✅ Desktop app access
|
|
- ✅ Priority support
|
|
|
|
**Implementation**: Just gate translation feature. That alone justifies $45/mo for studios.
|
|
|
|
---
|
|
|
|
## 📚 Resources
|
|
|
|
- **Clerk Docs**: https://clerk.com/docs
|
|
- **Stripe Docs**: https://stripe.com/docs
|
|
- **Next.js Auth**: https://clerk.com/docs/quickstarts/nextjs
|
|
- **Webhooks**: https://stripe.com/docs/webhooks
|
|
|
|
---
|
|
|
|
**Ready to monetize? Start with Clerk auth, then add Stripe payments!** 💰
|