# FlatRender — Claude Instructions > **Read this entire file before touching any code.** > This is the single source of truth for the AI assistant working on this project. --- ## 🗂 Project Layout (two repos, work together) ``` D:\Projects\flatrender\ ← Next.js marketing + studio app (THIS REPO) D:\Projects\flatrender-admin\ ← Admin panel (separate repo) admin-api\ ← .NET 10 ASP.NET Core Web API admin-ui\ ← Vite + React + TypeScript SPA ``` Both repos must be open together — the Next.js app consumes admin-api's public endpoints. --- ## 🚀 How to Run ### Next.js app ```bash cd D:\Projects\flatrender npm run dev # → http://localhost:3000 npm run render-worker # optional — video render worker on :3355 ``` ### Admin API (.NET 10) ```bash cd D:\Projects\flatrender-admin\admin-api # First time: copy appsettings.Development.json.example → appsettings.Development.json # Fill in Postgres + MinIO credentials, then: dotnet run # → http://localhost:5000 # Scalar API docs: http://localhost:5000 (root) ``` ### Admin UI (React SPA) ```bash cd D:\Projects\flatrender-admin\admin-ui npm run dev # → http://localhost:5173 ``` ### First-time admin seed ``` POST http://localhost:5000/api/auth/seed Body: { "email": "admin@example.com", "password": "YourPassword123" } Only works when zero admin users exist. ``` --- ## 🛠 Tech Stack | Layer | Technology | |---|---| | Framework | Next.js 15 App Router, TypeScript | | Styling | Tailwind CSS v3, shadcn/ui, Framer Motion | | Canvas | React-Konva (Video Studio + Image Editor) | | State | Zustand (`studio-store.ts`, `image-editor-store.ts`) | | Auth + DB | Supabase (`@supabase/ssr`) | | Payments | Stripe | | i18n | next-intl (`fa` = default/RTL, `en` = `/en/` prefix) | | Fonts | Vazirmatn (Persian RTL), Plus Jakarta Sans + Inter (English) | | Video (browser) | ffmpeg.wasm in Web Worker | | Video (server) | nexrender + After Effects | | Admin backend | .NET 10 ASP.NET Core, EF Core 9 + Npgsql (Supabase Postgres) | | Admin storage | MinIO (S3-compatible) | | Admin auth | JWT Bearer, BCrypt | | Admin UI | Vite + React + TypeScript + Tailwind + TanStack Query | --- ## 🌐 i18n / Locale Routing - **Persian (`fa`)** — default, no URL prefix, RTL, Vazirmatn font - **English (`en`)** — at `/en/` prefix, LTR, Plus Jakarta Sans + Inter Config: `src/i18n/routing.ts` Messages: `messages/fa.json` and `messages/en.json` Both files must have identical keys — add to both when adding new strings. Components use `useTranslations("namespace")` hook. **RTL font rule**: `globals.css` has a `[dir="rtl"]` block that forces Vazirmatn on all elements — do not fight it with utility classes. --- ## 🔑 Environment Variables Copy `.env.example` → `.env.local` and fill in: ```env # Admin API (optional — hardcoded fallback when not set) ADMIN_API_URL=http://localhost:5000 # Supabase — REQUIRED for auth/dashboard/studio NEXT_PUBLIC_SUPABASE_URL= NEXT_PUBLIC_SUPABASE_ANON_KEY= SUPABASE_SERVICE_ROLE_KEY= # Stripe — required for payments STRIPE_SECRET_KEY= STRIPE_WEBHOOK_SECRET= STRIPE_PRICE_PRO_MONTHLY= STRIPE_PRICE_PRO_ANNUAL= STRIPE_PRICE_BUSINESS_MONTHLY= STRIPE_PRICE_BUSINESS_ANNUAL= # Image background removal REMOVE_BG_API_KEY= # Video rendering (RENDER_MOCK=true → skip real rendering in dev) RENDER_MOCK=true RENDER_WORKER_URL=http://localhost:3355 NEXRENDER_BINARY= NEXRENDER_TEMPLATE_SRC= ``` --- ## 📁 Key File Map ``` src/ ├── app/[locale]/ │ ├── page.tsx ← Homepage (async, fetches admin projects) │ ├── video-maker/page.tsx ← Video Maker landing │ ├── image-maker/page.tsx ← Image Maker landing │ ├── templates/page.tsx ← Templates browser (async, fetches admin projects) │ ├── pricing/page.tsx ← Pricing page │ ├── auth/page.tsx ← Sign in / Sign up (Supabase) │ ├── dashboard/ │ │ ├── layout.tsx ← Auth guard, DashboardShell │ │ ├── page.tsx ← Projects grid │ │ └── settings/page.tsx ← Settings (Profile, Security, Billing, Notifications) │ └── studio/ │ ├── video/new/page.tsx ← New project onboarding │ ├── video/[projectId]/page.tsx ← Video Creation Studio │ ├── image/[projectId]/page.tsx ← Image Editor │ └── trimmer/page.tsx ← Video Trimmer │ ├── components/ │ ├── layout/ │ │ ├── Navbar.tsx ← Sticky nav, dropdowns, mobile sheet │ │ ├── Footer.tsx ← 4-column dark footer │ │ └── SiteChrome.tsx ← Wraps pages in Navbar+Footer (skips dashboard/studio) │ ├── ui/ │ │ └── LogoMark.tsx ← Inline SVG brand icon (used everywhere) │ ├── sections/ ← Landing page sections │ │ ├── TemplateGallery.tsx ← Accepts adminItems prop from server │ │ └── template-gallery-data.ts ← Hardcoded fallback + TemplateItem type │ ├── dashboard/ │ │ └── settings/ ← Settings sub-components │ │ ├── SettingsProfile.tsx │ │ ├── SettingsSecurity.tsx │ │ ├── SettingsBilling.tsx │ │ └── SettingsNotifications.tsx │ ├── studio/ ← Video Studio (Konva canvas) │ ├── image-editor/ ← Image Editor (Konva canvas) │ └── templates/ ← Templates page components │ ├── lib/ │ ├── admin-api.ts ← fetchCategories, fetchProjects, fetchProject │ ├── supabase/ │ │ ├── server.ts ← Server-side Supabase client │ │ ├── client.ts ← Browser-side Supabase client │ │ └── middleware.ts ← Session refresh │ ├── studio-store.ts ← Video Studio Zustand store │ ├── image-editor-store.ts ← Image Editor Zustand store │ ├── video-templates-catalog.ts ← Hardcoded + admin-to-catalog mapper │ ├── plans.ts ← PlanId type, Stripe price helpers │ └── profiles.ts ← getUserProfile (reads Supabase profiles table) │ ├── i18n/ │ ├── routing.ts ← locales: ["fa","en"], defaultLocale: "fa" │ └── request.ts ← getRequestConfig (loads messages JSON) │ └── middleware.ts ← next-intl + Supabase session messages/ ├── fa.json ← Persian translations (default locale) └── en.json ← English translations public/ └── favicon.svg ← SVG favicon (blue rounded square + play icon) supabase/migrations/ ├── 001_profiles.sql ├── 002_render_jobs.sql └── 003_projects.sql server/ ├── render-worker.ts ← HTTP server port 3355 ├── render-job-processor.ts └── nexrender-job-builder.ts ``` --- ## 🔗 Admin API Integration The Next.js app fetches from the admin API server-side with ISR (60-second revalidation). **`src/lib/admin-api.ts`** exports: - `fetchCategories(type?)` → `AdminCategory[]` - `fetchProjects(opts?)` → `AdminProjectsResponse` - `fetchProject(slug)` → `AdminProject | null` - `isAdminApiAvailable()` → `boolean` **Fallback behaviour**: If `ADMIN_API_URL` is not set or the service is unreachable, all functions return empty arrays / null — the app works standalone with hardcoded data. **Wired pages**: - `app/[locale]/page.tsx` → fetches 8 projects → passes `adminItems` to `` - `app/[locale]/templates/page.tsx` → fetches 100 video projects → converts to `VideoCatalogTemplate[]` → passes `initialCatalog` to `` --- ## 🗄 Database (Supabase) Run migrations in order in Supabase SQL Editor: 1. `supabase/migrations/001_profiles.sql` — profiles (plan, billing_period, stripe IDs) 2. `supabase/migrations/002_render_jobs.sql` — render_jobs 3. `supabase/migrations/003_projects.sql` — projects + scene_data --- ## ✅ What Is Complete - All marketing pages (Home, Video Maker, Image Maker, Pricing, Templates) - Full Video Creation Studio (Konva canvas, timeline, layers, transitions, undo/redo) - Full Image Editor (Konva canvas, filters, crop, adjustments, layers) - Video Trimmer (ffmpeg.wasm, frame strip, export) - Auth (Supabase, email/password, Google OAuth) - Dashboard (project grid, plan badge, settings page) - Stripe checkout + webhook for plan upgrades - Admin API backend (full CRUD for categories, projects, media + public endpoints) - Admin UI (dashboard, projects, categories, media library, settings) - i18n for all public pages (fa + en) - Logo brand mark (inline SVG `LogoMark` component) - RTL font (Vazirmatn forced via `[dir="rtl"]` CSS) --- ## ⏳ What Still Needs Setup (credentials required) | Item | Action needed | |---|---| | Supabase | Create project → get URL + anon key + service key → add to `.env.local` → run 3 SQL migrations | | Stripe | Create products with 4 prices → add price IDs to `.env.local` | | Admin API DB | Fill `appsettings.Development.json` with real Postgres connection string | | MinIO | Run MinIO locally or use S3 → update admin `appsettings.Development.json` | | Real template assets | Upload via admin panel → auto-appears on website | | Video rendering | Set `RENDER_MOCK=false` + `NEXRENDER_BINARY` path | --- ## 📝 Coding Conventions - **Server components** for data fetching; **`"use client"`** for interactivity - All new translation strings go in **both** `messages/fa.json` AND `messages/en.json` - Never hardcode English strings in components — use `useTranslations()` - Logo: always use `` — never the old `` icon - Admin API calls in page.tsx only (server-side), never in client components - TypeScript strict — run `npx tsc --noEmit` before committing - Tailwind only — no inline styles except Framer Motion animations