80 pages across 3 languages, Next.js 14 App Router with ISR, Supabase for auth + data, Stripe for subscriptions, and an LLM-powered AI interpretation backend. Designed, built, deployed, and marketed end-to-end.
| Feature | Route Pattern | Rendering | Notes |
|---|---|---|---|
| Dream Analysis | /[lang]/dream-analysis | Client + API | DeepSeek backend, 3 free/month, unlimited premium |
| Zodiac Signs | /[lang]/zodiac-signs/[sign] | Static (12 signs × 3 langs) | generateStaticParams — 36 pre-rendered pages |
| Compatibility | /[lang]/compatibility/[pair] | ISR 300s | Dynamic matching across all 12 signs |
| Dream Dictionary | /[lang]/dream-dictionary/[symbol] | ISR 3600s | 69 symbols pre-rendered + dynamic Supabase entries |
| Birth Chart | /[lang]/birth-chart | Client-rendered | Natal chart calculation, premium feature |
| Blog | /[lang]/blog/[slug] | ISR 300s | Trilingual articles from Supabase |
| Pricing / Checkout | /[lang]/pricing | Static + Stripe | Freemium → paid tier |
| Dashboard | /[lang]/dashboard | Server (auth) | Protected by Supabase middleware |
The platform is a single Next.js 14 App Router codebase. Every feature lives under src/app/[lang]/ where [lang] is one of en, es, pt. Static content pages are pre-rendered at build + revalidated with ISR. Authenticated pages are server components gated by Supabase middleware. There is no headless CMS, no separate API server, no client-state mess — just the framework.
| Route Group | Strategy | Revalidation | Why |
|---|---|---|---|
| Zodiac signs (12 × 3) | Static (SSG) | build time | Evergreen content, pure SEO plays |
| Dream dictionary (69+) | ISR | 3600s | Rarely changes, but Supabase-editable |
| Compatibility pairs | ISR | 300s | Personalized tone tuning per language |
| Blog | ISR | 300s | New content adds daily via GAEL |
| Dashboard / history | Server component | per-request | Personalized, auth-gated, no cache |
| Dream analysis result | Client + API | n/a | Streaming-like UX while DeepSeek runs |
| Table | Role |
|---|---|
profiles | Supabase user metadata — stripe_customer_id, tier, locale, birth data for chart |
dream_history | User dream submissions + AI interpretations, RLS-scoped per user |
symbol_content | Dream dictionary entries in 3 languages, editorial-controlled |
blog_posts | Multilingual blog with language alternates, drives GAEL distribution |
subscriptions | Stripe-synced state (status, tier, renewal date), updated by webhook |
Most Next.js i18n libraries are heavy or tied to legacy pages router. App Router has no built-in i18n.
[lang] dynamic segment + middleware for detection/redirects + language-keyed Supabase content. generateStaticParams walks the language list to pre-render every page per locale. Zero client-side i18n runtime.Free users get 3 AI interpretations/month. Enforcing that without trusting the client is tricky.
dream_history row count per calendar month, with Supabase RLS. Premium bypass keyed to the Stripe-synced subscription status — never touches client state.Too short and the CDN thrashes. Too long and editorial changes take a day to appear.
User completes checkout, returns to the app, sees their still-free dashboard because the webhook hasn't fired yet.
Google can easily treat 3 language versions as duplicate content without proper signals.
<link rel="alternate"> tags rendered via metadata API per page.Building a real SaaS alone means a thousand decisions: framework, database, payments, design system, SEO, content.
I build production Next.js SaaS applications solo — framework, database, auth, payments, SEO, AI backends. The platform is the reference. Your niche is the next one.
💬 Hire Me on Contra ← Back to portfolio