aethex-studio/AUTHENTICATION_SETUP.md
Claude 05af047e19
Add marketing materials and authentication setup guide (B, C, D)
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!
2026-01-17 23:44:37 +00:00

15 KiB

🔐 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

npm install @clerk/nextjs

Step 3: Add Environment Variables

# .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

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

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

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

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

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

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

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

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

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

npm install @stripe/stripe-js stripe

2. Add Environment Variables

# .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

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

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

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

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


Ready to monetize? Start with Clerk auth, then add Stripe payments! 💰