Files
flatrender/PROJECT_MEMORY.md
Soroush.Asadi 36e264f3e3 feat: admin API integration, LogoMark, settings page, i18n, RTL font, docs
- Wire admin API into homepage + templates page (ISR 60s, null fallback)
- Add src/lib/admin-api.ts with safeFetch helper
- Add adminProjectToTemplateItem + adminProjectToCatalogTemplate mappers
- Add LogoMark SVG component, replace Sparkles icon in Navbar/Footer/Sidebar
- Add public/favicon.svg (SVG brand mark)
- Rewrite opengraph-image.tsx with FlatRender branding
- Add RTL/Persian font cascade: unlayered [dir=rtl] block forces Vazirmatn
- Dashboard Settings page: Profile, Security, Billing, Notifications sections
- Add src/lib/supabase/client.ts browser client
- Admin API: GET /me, PATCH /profile, POST /change-password endpoints
- Admin API DTOs: AdminUserDto, UpdateProfileRequest, ChangePasswordRequest
- Admin UI Settings page with TanStack Query + mutations
- Add CLAUDE.md + README.md to both repos for new-machine onboarding
- Update PROJECT_MEMORY.md with session log
- Add appsettings.Development.json.example template
2026-05-27 09:06:51 +03:30

25 KiB
Raw Permalink Blame History

FlatRender — Project Memory

Rule: Read this file before starting any task. Update it after every completed feature, bug fix, or architectural decision. Both Cursor AI and Claude Code use this as the project brain.


📌 Project Identity

Key Value
Project folder D:\Projects\flatrender
Brand name FlatRender (package: flatrender) — All UI updated to FlatRender
Products Video Maker · Image Maker
Stack Next.js 14 App Router · TypeScript · Tailwind CSS · shadcn/ui · Framer Motion
Canvas React-Konva (Konva.js) — both Video Studio and Image Editor
State Zustand (studio-store.ts, image-editor-store.ts)
Auth + DB Supabase (@supabase/ssr)
Payments Stripe
Video (browser) ffmpeg.wasm in Web Worker (src/workers/ffmpeg-trim.worker.ts)
Video (server) nexrender + Adobe After Effects (server/render-worker.ts)
Dev server npm run devhttp://localhost:3000
Render worker npm run render-workerhttp://localhost:3355

Completed Features

Landing Page (/)

  • Hero — gradient on “AI” (from-blue-600 via-violet-500 to-blue-500), dual CTA, preview cards, blobs
  • HeroPreviewCards — Mixkit MP4 loops, play overlay fades on hover, Framer Motion stagger
  • ProductsShowcase — Video Maker + Image Maker cards with glassmorphism style
  • TemplateGallery — filter tabs, 8-card grid, scroll-mt-20 for sticky nav anchor
  • TemplateCard — hover Mixkit video via previewVideoUrl, bottom "Use Template" CTA, AnimatePresence fade
  • template-gallery-data.tspreviewVideoUrl on video/social template entries
  • HowItWorks — 3-step process, alternating layout, scroll-triggered animations
  • Pricing — monthly/annual toggle, green “Save 20%” yearly badge, 3 tiers, Stripe checkout wired
  • PricingCompareTable — full feature comparison table, 5 sections, synced billing toggle, Pro column highlight
  • Testimonials — 6-card grid
  • FAQ — accordion, 2-column layout
  • Navbar — FlatRender logo, Video/Image Maker + Learn dropdowns (shadcn), Pricing link, Sign In / Try for Free; mobile sheet (navbar-menu-data.ts)
  • Footer — 4-column, dark background

Product Pages

  • /video-maker — Hero, Features, UseCases, TemplateCarousel, CTA
  • /image-maker — Hero, BeforeAfter, Gallery, Features, UseCases, CTA

Templates Page (/templates)

  • Renderforest layout: 260px category sidebar + carousel rows (VideoTemplatesCategorySidebar, VideoTemplatesCarouselRow)
  • Toolbar: search, Premium Only (Switch), All Sizes select (16:9 / 9:16 / 1:1 / 4:5), Sort by (local state)
  • Sidebar filters panel (collapsed): Premium + size; ?category= from navbar
  • VideoTemplatesPageContent — client-side filtering via video-templates-catalog.ts
  • Template detail /templates/[id]TemplateDetailContent (preview, styles, Create Now, examples row); generateStaticParams from catalog

Auth (/auth)

  • Sign In / Sign Up tabs
  • Email + password (react-hook-form + zod)
  • Google OAuth button
  • Supabase auth integration
  • OAuth callback route (/auth/callback)
  • Sign-out route (/auth/sign-out)
  • SupabaseSetupNotice — shown when env vars missing (dev-friendly)

Dashboard (/dashboard)

  • DashboardShell — layout wrapper
  • DashboardSidebar — logo, nav links, user avatar + plan badge
  • DashboardTopBar — search + "New Project" dropdown
  • NewProjectMenu — Video / Image / Trimmer options
  • DashboardProjectsSection — projects grid from Supabase; isLoading shows 6-card skeleton grid
  • DashboardProjectsContent — async Supabase fetch (Suspense on /dashboard)
  • SkeletonProjectCard — pulse placeholders matching ProjectCard layout
  • DashboardPlanBadge — async plan fetch; sidebar Suspense + DashboardPlanBadgeSkeleton
  • DashboardSidebarNav — client nav (pathname-aware)
  • DashboardEmptyState — illustration + CTA
  • ProjectCard — thumbnail, type badge, status, 3-dot menu
  • /dashboard/settings — settings page

Video Creation Studio (/studio/video/[projectId])

  • VideoStudioLayout — icon dock (56px) + fixed 220px tool panel + full-width canvas/timeline (no right PropertiesPanel); StudioMobileGate below 768px; useStudioProjectPersistence (3s debounced save; dev 404 → localStorage flatrender-project-{id})
  • StudioSidebarDock — Audio / TTS / Colors / Transitions / Font / Watermark + Guide + Keyboard (toasts); blue active bar; scenes via timeline strip only
  • WatermarkSidebarContent — upload placeholder, 3×3 position grid, opacity slider
  • Sidebar panels — AudioSidebarContent, ColorsSidebarContent, TransitionsSidebarContent (Random / No Transition tiles, apply all scenes), FontSidebarContent, WatermarkSidebarContent
  • scene-browser-data.ts, SceneBrowserCard, shadcn Tabs for media filter
  • /studio/video/new — Renderforest-style onboarding (Select Scenes / AI / presets) before editor
  • VideoProjectNewContent, TEMPLATE_GALLERY_ITEMS (picsum thumbnails); preset click → /templates/[id]; catalog includes onboarding preset ids
  • SceneBrowserModal — full-screen library (categories, Video/Photo tabs, search, 28 scenes); onboarding + studio “Browse Scenes”
  • StudioMobileGate + useIsMobile — desktop-only gate for video/image studio (matchMedia max-width 767px)
  • ResizableStudioPanel — drag-to-resize left/right panels
  • StudioTopBar — breadcrumb (My Projects → name), StudioTopBarSaveBadge (Local / Saved ✓ / dot), centered undo/redo + toolbar, StudioTopBarTextControls when text layer selected, Export dropdown → RenderModal presets
  • PropertiesPanel — still used by image editor; not mounted in video studio layout
  • dev-project-storage.ts — dev-only localStorage fallback when Supabase returns 404
  • render-presets.ts — full / 720p preview / GIF export presets for RenderModal
  • Scenes managed via timeline SceneThumbnailStrip only (no left sidebar scenes panel): 120×80px blocks, rename, browse (SceneBrowserModal), duplicate/delete on hover
  • SceneTransitionPicker — None / Fade / Slide / Zoom popover on outgoing scene
  • scene-transitions.ts — Framer Motion animate() playback (300ms fade, slide-left, zoom)
  • DraggableSceneItem + SceneItemActions — live Konva thumbnailUrl previews
  • AddSceneMenu — blank / from template
  • CanvasEditor — React-Konva Stage (1280×720), scaled to container
    • Text layers (draggable, resizable, rotatable)
    • Image layers
    • Video clip layers
    • Shape layers (rect, circle, line, arrow)
    • Transformer (resize handles, rotation, min 8px guard)
    • Click empty area → deselect
    • Circle drag fix (center-origin correction)
  • CanvasLayerNode router → TextLayerNode, ImageLayerNode, ShapeLayerNode, VideoLayerNode
  • PropertiesPanel — context-sensitive to selected layer type
    • TextLayerProperties — font, size, bold/italic, color, align, letter-spacing, line-height, animation style
    • ImageLayerProperties — opacity, flip H/V, replace, border-radius
    • ShapeLayerProperties — fill, stroke, stroke-width, border-radius
    • CommonLayerControls — X/Y/W/H, rotation, z-order, delete
    • PropertyControls + useLayerUpdater
  • Timeline — 180px Renderforest layout: TimelineControlBar, SceneThumbnailStrip / SceneThumbnailBlock, TimelineActionRow; playhead on strip (STRIP_PX_PER_SECOND 24); zoom slider 30120
    • TimeRuler — time markers, click to seek
    • SceneTrack + SceneBlock — color-coded, drag-right-edge to resize duration
    • AudioTrack — file picker, file name display
    • TimelinePlayhead — red playhead overlay on thumbnail strip during playback
    • Legacy SceneBlock / SceneTrack / TimeRuler / AudioTrack — unused by Timeline (kept for reference)
  • StudioToolbar — add Text / Image / Video / Shape buttons
  • RenderModal — resolution, FPS, progress bar, download link
  • useCanvasKeyboard — Delete, Ctrl+C/V/Z/Y
  • useCanvasPreviewPlayback — scene-by-scene playback with timing
  • useContainerSize — responsive canvas scaling
  • studio-store.ts — full Zustand store (scenes, layers, playback, zoom, audio, undo/redo)
  • studio-history.ts — past/future snapshot undo stack (limit 50)
  • studio-timeline.ts — duration helpers, zoom levels, scene-at-time
  • studio-types.ts — Scene, Layer, LayerType, SceneTransition, AddLayerInput interfaces
  • studio-snapshot.ts — Konva stage → PNG download
  • studio-canvas-stage.ts — global stage ref registry
  • studio-scene-thumbnail.tstoDataURL({ pixelRatio: 0.2 }) + deferred capture after layer edits
  • studio-scene-data.ts / image-scene-data.ts — parse + serialize scene_data for persistence
  • ProjectSaveIndicator — Saving… / Saved / Local save / Save failed (image editor); video studio uses StudioTopBarSaveBadge
  • canvas-transform.ts — node transform → layer coords
  • studio-layer-props.ts — typed prop accessors per layer type
  • dev-mock-project.ts — dev-only mock for testing without Supabase

Video Trimmer (/studio/trimmer)

  • TrimmerUploadZone — drag-drop + click, accepts video/*
  • TrimmerVideoPreview<video> + react-rnd crop overlay, aspect ratio buttons
  • TrimmerStrip — frame thumbnail strip, draggable trim handles
  • TrimmerExportSection — MP4/WebM toggle, export button, progress, download
  • ffmpeg-trim.worker.ts — full ffmpeg.wasm Web Worker (init, progress, process, complete)
  • ffmpeg-worker-client.ts — typed client to communicate with worker
  • trimmer-types.ts + trimmer-utils.ts — types and crop scaling math

Image Editor (/studio/image and /studio/image/[projectId])

  • ImageEditorLayout — full-viewport, dark theme; mobile gate; useImageProjectPersistence auto-save
  • ImageEditorTopBar — project name, export button
  • ImageEditorToolbar — Select, Crop, Text, Shape, Draw, AI tools
  • ImageEditorCanvas — dynamic import (SSR off), Konva stage
    • ImageBaseLayer — base image rendering with Konva filters
    • ImageEditorLayerNode — text/shape/draw layer nodes
    • ImageCropOverlayreact-rnd crop box on canvas (aspect lock)
    • VignetteOverlay — radial gradient vignette
  • ImageCropControls — aspect presets (Free, 1:1, 16:9, 4:3, 9:16), Apply/Cancel above canvas
  • image-editor-crop.ts — aspect math, canvas→source crop, cropImageDataUrl
  • ImageEditorRightPanel — tabbed: Adjust | Filters | Layers
    • AdjustPanel — brightness, contrast, saturation, hue, blur, sharpen, vignette sliders
    • FiltersPanel — 12 preset filter thumbnails
    • LayersPanel — reorder, hide, lock, delete
  • AiRemoveBgModal — calls /api/remove-bg, shows result
  • image-editor-store.ts — Zustand store for image editor
  • image-editor-filters.ts — Konva filter pipeline helpers
  • image-editor-konva.ts — Konva helpers
  • image-editor-types.ts — ImageLayer, ImageEditorState types
  • image-editor-export.ts — stage → PNG/JPG/WebP download
  • image-editor-stage-ref.ts — global stage ref
  • image-editor-transform.ts — transform helpers

API Routes

  • POST /api/checkout — creates Stripe Checkout session
  • POST /api/webhooks/stripe — updates user plan on checkout.session.completed
  • GET/POST /api/projects — fetch / create user projects
  • GET/PATCH /api/projects/[projectId] — load project + auto-save scene_data
  • POST /api/remove-bg — calls remove.bg or rembg service
  • POST /api/render — queues render job in Supabase
  • GET /api/render/[jobId]/status — poll render job status

Server (render worker process)

  • server/render-worker.ts — HTTP server on port 3355, /health + /process
  • server/render-job-processor.ts — fetches job from Supabase, runs nexrender, uploads result
  • server/nexrender-job-builder.ts — builds nexrender job JSON from scene data
  • server/nexrender.d.ts — type declarations for @nexrender/core

Infrastructure

  • supabase/migrations/001_profiles.sql — profiles table, RLS
  • supabase/migrations/002_render_jobs.sql — render_jobs table, RLS
  • supabase/migrations/003_projects.sql — projects table, RLS, updated_at trigger
  • .env.example — all required env vars documented (including ADMIN_API_URL)
  • next.config.mjs — webpack globalObject fix + COOP/COEP headers (required for ffmpeg.wasm)
  • .cursorrules — full project rules for Cursor AI
  • tailwind.config.ts — custom colors, font families (heading, body, vazirmatn)
  • components.json — shadcn/ui config
  • CLAUDE.md — Claude Code instructions (auto-read on session start)
  • public/favicon.svg — brand favicon (SVG, blue rounded square + play icon)

i18n

  • messages/fa.json + messages/en.json — full translations for all public pages
  • Namespaces: hero, nav, products, templates, pricing, testimonials, faq, footer, metadata, videoMaker, imageMaker
  • globals.css[dir="rtl"] block forces Vazirmatn on all elements in Persian locale
  • src/i18n/routing.tsfa default (no prefix), en at /en/
  • src/components/ui/LogoMark.tsx — inline SVG brand mark (play triangle + 3 layer bars in blue square)
  • Navbar, Footer, DashboardSidebar — all use <LogoMark> (removed old <Sparkles> icon)
  • app/opengraph-image.tsx — proper FlatRender OG image (1200×630, headline + feature pills)

Admin Panel integration

  • src/lib/admin-api.tsfetchCategories, fetchProjects, fetchProject, isAdminApiAvailable
  • app/[locale]/page.tsx — async, fetches 8 projects → <TemplateGallery adminItems={...}>
  • app/[locale]/templates/page.tsx — async, fetches 100 video projects → initialCatalog
  • TemplateGallery.tsx — accepts adminItems prop, maps AdminProjectTemplateItem
  • VideoTemplatesPageContent.tsx — accepts initialCatalog prop
  • video-templates-catalog.tsadminProjectToCatalogTemplate() mapper added

Dashboard Settings

  • /dashboard/settings — full settings page (Profile, Security, Billing, Notifications, Danger zone)
  • src/lib/supabase/client.ts — browser Supabase client (for client-side auth updates)
  • SettingsProfile.tsx — editable display name via supabase.auth.updateUser
  • SettingsSecurity.tsx — change password (re-authenticates first)
  • SettingsBilling.tsx — plan info + features + Stripe billing portal link
  • SettingsNotifications.tsx — 4 email toggle switches

🔄 In Progress

Nothing currently in progress.

Status as of 2026-05-27

  • npx tsc --noEmit — clean (zero TypeScript errors)
  • All public pages fully built and i18n'd (fa + en)
  • Admin panel fully built (backend + frontend) — needs real Postgres + MinIO credentials
  • Admin API integrated into Next.js with ISR fallback
  • Logo, favicon, OG image all done
  • Dashboard settings page fully functional
  • Next step: fill in .env.local credentials and test end-to-end

📋 Backlog (Next Tasks)

🔴 Must Do Before Launch

  • Create .env.local from .env.example and fill in Supabase + Stripe keys
  • Run Supabase migrations (001002003) in SQL Editor
  • Set up admin API: copy appsettings.Development.json.exampleappsettings.Development.json, fill Postgres + MinIO
  • Seed first admin: POST /api/auth/seed with email + password
  • Upload real template categories + projects via admin panel (auto-appears on website)
  • Add real logo image/video assets (currently using picsum + Mixkit placeholders)
  • Test full auth flow (sign up → dashboard → create project → open studio)
  • Test ffmpeg.wasm trimmer end-to-end in browser
  • Build settings page "Delete account" confirmation flow

🟡 UI Polish (Cursor screenshot-driven)

  • Navbar: Video/Image Maker + Learn dropdowns (Renderforest-style, no mega menu)
  • Landing polish pass: rf-blue / rf-blue-light tokens, Hero AI gradient, pricing Save 20% badge, #templates scroll-mt-20
  • Hero: animated video thumbnail preview cards (autoplay muted)
  • TemplateCard: video preview on hover (autoplay muted loop, AnimatePresence fade)
  • Studio: scene thumbnail auto-generated from Konva canvas (toDataURL)
  • Studio: transition picker between scenes (fade, slide, zoom)
  • Dashboard: skeleton loading states for project cards
  • Mobile: studio pages desktop gate (under 768px shows StudioMobileGate, not full editor)

🟢 Nice to Have

  • Template system: pre-built .aep templates for nexrender
  • Image editor: text curved/arc effect
  • Image editor: sticker/icon library (200+ SVGs)
  • Video studio: background color/gradient picker per scene
  • Onboarding flow for new users (first project wizard)
  • Usage limits per plan (enforced server-side)

🐛 Known Issues

# Issue File Priority
1 Brand name "CreatorStudio" in UI Fixed 2026-05-21 — all 4 files updated
2 next.config.mjs was missing COOP/COEP headers Fixed 2026-05-21
3 Scene thumbnails are placeholder gray boxes Fixed 2026-05-21 — thumbnailUrl via updateSceneThumbnail
4 No loading/error state in trimmer if ffmpeg CDN is slow TrimmerExportSection 🟡 Medium
5 Image editor crop tool not fully implemented Fixed 2026-05-21 — ImageCropControls, ImageCropOverlay, pixel crop in applyCrop

🏗️ Architecture Decisions

Decision Rationale
React-Konva for all canvas work Consistent layer model across Video Studio and Image Editor
ffmpeg.wasm in Web Worker only Never block main thread; SharedArrayBuffer requires COOP/COEP headers in next.config.mjs
Zustand for studio state (not React context) Avoids re-render cascade on every canvas update
nexrender + aerender for final render AE templates give highest quality output; RENDER_MOCK=true skips it in dev
Supabase RLS on all tables Row-level security — users can only access their own data
studio-canvas-stage.ts global stage ref Allows snapshot/export from any component without prop-drilling
Dynamic import for ImageEditorCanvas Konva cannot run on server — ssr: false prevents SSR crash
dev-mock-project.ts Dev POST mock; dev-project id skips load/save in studio editors

🚀 Production-Ready Checklist

Item Status
next.config.mjsoutput: 'standalone' (Docker)
app/sitemap.ts/, /video-maker, /image-maker, /templates, /pricing
app/robots.ts — allow public; disallow /dashboard, /studio, /api
Page metadata via createPageMetadata (public routes + studio layouts)
app/pricing/page.tsx — dedicated pricing route for SEO/sitemap
app/error.tsx — error boundary with reload
app/not-found.tsx — 404 with home CTA
npx tsc --noEmit clean (re-run before deploy)
.env.local + Supabase migrations Operator setup
NEXT_PUBLIC_SITE_URL set to production domain Required for sitemap/OG URLs

🔑 Environment Variables Checklist

Variable Status Where to get it
NEXT_PUBLIC_SUPABASE_URL Not set Supabase → Settings → API
NEXT_PUBLIC_SUPABASE_ANON_KEY Not set Supabase → Settings → API
SUPABASE_SERVICE_ROLE_KEY Not set Supabase → Settings → API
STRIPE_SECRET_KEY Not set Stripe Dashboard → API Keys
STRIPE_WEBHOOK_SECRET Not set Stripe → Webhooks → signing secret
STRIPE_PRICE_PRO_MONTHLY Not set Stripe → Products → price ID
STRIPE_PRICE_PRO_ANNUAL Not set Stripe → Products → price ID
STRIPE_PRICE_BUSINESS_MONTHLY Not set Stripe → Products → price ID
STRIPE_PRICE_BUSINESS_ANNUAL Not set Stripe → Products → price ID
REMOVE_BG_API_KEY Not set remove.bg → API
RENDER_WORKER_URL Default: http://localhost:3355
RENDER_MOCK Default: true Set to false when AE is configured
NEXRENDER_TEMPLATE_SRC Not set Path to your .aep template file
NEXRENDER_BINARY Not set Path to aerender executable

📁 Key File Map (Quick Reference)

src/
├── app/
│   ├── page.tsx                        ← Landing page
│   ├── video-maker/page.tsx            ← Video Maker product page
│   ├── image-maker/page.tsx            ← Image Maker product page
│   ├── templates/page.tsx              ← Templates gallery
│   ├── pricing/page.tsx                ← Pricing (public SEO route)
│   ├── sitemap.ts / robots.ts          ← SEO + crawler rules
│   ├── error.tsx / not-found.tsx       ← Global error UI
│   ├── auth/page.tsx                   ← Sign in / Sign up
│   ├── dashboard/page.tsx              ← User dashboard
│   ├── studio/
│   │   ├── video/new/page.tsx          ← New video project onboarding
│   │   ├── video/[projectId]/page.tsx  ← Video Creation Studio
│   │   ├── image/[projectId]/page.tsx  ← Image Editor
│   │   └── trimmer/page.tsx            ← Video Trimmer/Cropper
│   └── api/                            ← All API routes
├── components/
│   ├── layout/                         ← Navbar, Footer, SiteChrome
│   ├── sections/                       ← Landing page sections
│   ├── studio/                         ← Video Studio components
│   ├── image-editor/                   ← Image Editor components
│   ├── trimmer/                        ← Video Trimmer components
│   ├── dashboard/                      ← Dashboard components
│   └── ui/                             ← shadcn/ui (do not edit)
├── lib/
│   ├── studio-store.ts                 ← Video Studio Zustand store
│   ├── studio-types.ts                 ← Scene / Layer types
│   ├── image-editor-store.ts           ← Image Editor Zustand store
│   └── supabase/                       ← Supabase client helpers
├── hooks/                              ← useCanvasKeyboard, useContainerSize, useIsMobile, etc.
└── workers/
    └── ffmpeg-trim.worker.ts           ← ffmpeg.wasm Web Worker

server/
├── render-worker.ts                    ← HTTP server (port 3355)
├── render-job-processor.ts            ← nexrender job runner
└── nexrender-job-builder.ts           ← builds AE job from scene JSON

supabase/
└── migrations/                         ← SQL files, run in order in Supabase SQL Editor

📅 Session Log

Date What was done
2026-05-21 Full project scaffolded: all pages, studio modules, API routes, Supabase migrations, server render worker
2026-05-21 Fixed next.config.mjs — added COOP/COEP headers required for ffmpeg.wasm SharedArrayBuffer
2026-05-21 Created PROJECT_MEMORY.md — project brain for Cursor + Claude
2026-05-21 Fixed brand name in 4 files: metadata.ts, DashboardSidebar.tsx, ProductsMegaMenu.tsx, Navbar.tsx
2026-05-21 Discovered ProductsMegaMenu already fully built — moved from backlog to done
2026-05-21 Added PricingCompareTable with 5 feature sections matching Renderforest /subscription layout
2026-05-21 Scene thumbnails: thumbnailUrl on Scene, updateSceneThumbnail, DraggableSceneItem img preview
2026-05-27 Built admin panel at D:\Projects\flatrender-admin: .NET 10 API + React SPA. Categories/Projects/Media CRUD, JWT auth, MinIO storage, public endpoints
2026-05-27 i18n: added videoMaker + imageMaker namespaces (fa + en), wired useTranslations in all 8 components
2026-05-27 Wired admin API into Next.js: admin-api.ts, homepage + templates page async with ISR, TemplateGallery accepts adminItems
2026-05-27 RTL fix: globals.css [dir="rtl"] block forces Vazirmatn on every text element
2026-05-27 LogoMark SVG component — replaces Sparkles in Navbar, Footer, DashboardSidebar; public/favicon.svg added
2026-05-27 OG image rebranded FlatRender with logo, feature pills
2026-05-27 Dashboard settings page: Profile, Security (pw change), Billing (plan + Stripe link), Notifications toggles
2026-05-27 Admin API: added GET /api/auth/me, PATCH /api/auth/profile, POST /api/auth/change-password
2026-05-27 Admin UI: Settings page (profile edit + password change), Settings link in sidebar
2026-05-27 appsettings.Development.json.example created for admin API local setup
2026-05-27 CLAUDE.md created — Claude Code auto-reads on session start