figuro Svelte Themes

Figuro

Figma to Frontend SaaS platform — converts Figma designs to production-ready React, Vue, Angular, Svelte, and HTML

Figuro — Figma to Frontend SaaS Platform

Figuro is a full-stack SaaS platform that lets users instantly transform their Figma designs into production-ready frontend code (React, Vue, Angular, Svelte, or plain HTML). It includes a user-facing app with authentication, project management, and conversion history, plus a full admin panel with analytics.


Table of Contents

  1. Features
  2. Tech Stack
  3. Project Structure
  4. Getting Started
  5. Environment Variables
  6. Authentication
  7. Database
  8. API Reference
  9. Pages & Routes
  10. Admin Panel
  11. Development Workflow
  12. Deployment
  13. GitHub Integration
  14. Troubleshooting

Features

User-Facing

  • Figma-to-Code Conversion — Submit any Figma project URL and convert it to React, Vue, Angular, Svelte, or HTML in seconds.
  • Framework & Styling Options — Choose your target framework and styling approach (Tailwind CSS, CSS Modules, Styled Components, or plain CSS).
  • Project Management — Organize conversions into named projects, archive old ones, track conversion history.
  • Code Viewer — Syntax-highlighted output with one-click copy and download.
  • Regeneration — Re-run any conversion to get a fresh output.
  • Dashboard — Real-time stats (total projects, conversions, success rate) plus a recent-activity feed.
  • Authentication — Email/password, Google OAuth, and GitHub OAuth via Better Auth.

Admin Panel

  • Platform Analytics — Daily conversions chart (last 30 days), framework breakdown pie chart, live KPI cards.
  • User Management — View all users, change plans (Free/Pro/Enterprise), change roles (user/admin), ban or delete accounts.
  • Conversion Overview — Full table of all platform conversions with status filtering.

Tech Stack

Layer Technology
Frontend React 18 + Vite, TypeScript, Tailwind CSS v4, shadcn/ui, Wouter (routing), React Query
Backend Express 5, Node.js 24, TypeScript
Auth Better Auth (email/password + Google OAuth + GitHub OAuth)
Database PostgreSQL (Neon DB or any Postgres) via Drizzle ORM
Validation Zod (v4), drizzle-zod
API Contract OpenAPI 3.1 → Orval codegen (React Query hooks + Zod schemas)
Charts Recharts
Build esbuild (server), Vite (client)
Monorepo pnpm workspaces

Project Structure

figuro/
├── artifacts/
│   ├── api-server/          # Express 5 backend
│   │   └── src/
│   │       ├── app.ts       # Express app, CORS, Better Auth mount
│   │       ├── index.ts     # Server entry point
│   │       ├── lib/
│   │       │   ├── auth.ts      # Better Auth configuration
│   │       │   ├── session.ts   # Session helper
│   │       │   └── logger.ts    # Pino structured logger
│   │       └── routes/
│   │           ├── health.ts
│   │           ├── user.ts
│   │           ├── projects.ts
│   │           ├── conversions.ts
│   │           ├── dashboard.ts
│   │           └── admin.ts
│   └── figuro/              # React + Vite frontend
│       └── src/
│           ├── App.tsx          # Router setup
│           ├── index.css        # Theme variables + Tailwind
│           ├── contexts/
│           │   └── AuthContext.tsx
│           └── pages/
│               ├── landing.tsx
│               ├── login.tsx
│               ├── register.tsx
│               ├── dashboard.tsx
│               ├── projects.tsx
│               ├── project-detail.tsx
│               ├── convert.tsx
│               ├── conversion-result.tsx
│               ├── pricing.tsx
│               ├── settings.tsx
│               ├── admin/
│               │   ├── index.tsx
│               │   ├── users.tsx
│               │   └── conversions.tsx
│               └── not-found.tsx
├── lib/
│   ├── api-spec/
│   │   └── openapi.yaml     # API contract (source of truth)
│   ├── api-client-react/    # Generated React Query hooks
│   ├── api-zod/             # Generated Zod validation schemas
│   └── db/
│       └── src/
│           └── schema/
│               ├── users.ts
│               ├── projects.ts
│               ├── conversions.ts
│               └── activity.ts
└── scripts/                 # Utility scripts

Getting Started

Prerequisites

  • Node.js 20+ (22+ recommended)
  • pnpm 9+
  • PostgreSQL database (local or Neon DB for hosted)

1. Clone the repository

git clone https://github.com/your-username/figuro.git
cd figuro

2. Install dependencies

pnpm install

3. Set up environment variables

Copy the example env file and fill in your values:

cp .env.example .env

See Environment Variables for full details.

4. Set up the database

Push the schema to your PostgreSQL database:

pnpm --filter @workspace/db run push

5. Seed the database (optional)

pnpm --filter @workspace/scripts run seed

6. Start the development servers

In two separate terminals:

# Terminal 1 — API server (port 5000)
pnpm --filter @workspace/api-server run dev

# Terminal 2 — Frontend (port from .env)
pnpm --filter @workspace/figuro run dev

Open http://localhost:5173 (or whatever port Vite assigns).


Environment Variables

Create a .env file in the project root (or set these in your hosting environment):

# ─── Database ───────────────────────────────────────────────────────────────
# Full PostgreSQL connection string (Neon, Supabase, or local)
DATABASE_URL=postgresql://user:password@host:5432/figuro

# ─── Better Auth ─────────────────────────────────────────────────────────────
# Required: random 32+ character secret key
# Generate one: https://generate-secret.vercel.app/32
BETTER_AUTH_SECRET=your-super-secret-key-change-this-in-production

# The base URL where the auth callbacks are served (no trailing slash)
# In development: http://localhost:5000
# In production: https://your-domain.com
BETTER_AUTH_URL=http://localhost:5000

# ─── Google OAuth ────────────────────────────────────────────────────────────
# Create credentials at: https://console.cloud.google.com/apis/credentials
# Authorized redirect URI: {BETTER_AUTH_URL}/api/auth/callback/google
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret

# ─── GitHub OAuth ────────────────────────────────────────────────────────────
# Create an OAuth App at: https://github.com/settings/developers
# Callback URL: {BETTER_AUTH_URL}/api/auth/callback/github
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret

# ─── Server ──────────────────────────────────────────────────────────────────
# Port for the API server (set automatically in Replit)
PORT=5000

Setting up Google OAuth

  1. Go to Google Cloud Console
  2. Create a new project (or select an existing one)
  3. Enable the Google+ API or People API
  4. Click Create Credentials → OAuth client ID
  5. Choose Web application
  6. Add to Authorized redirect URIs:
    • Development: http://localhost:5000/api/auth/callback/google
    • Production: https://your-domain.com/api/auth/callback/google
  7. Copy the Client ID and Client Secret into your .env

Setting up GitHub OAuth

  1. Go to GitHub Developer Settings
  2. Click New OAuth App
  3. Fill in:
    • Homepage URL: http://localhost:5173 (or your production URL)
    • Authorization callback URL: http://localhost:5000/api/auth/callback/github
  4. Copy the Client ID and generate a Client Secret
  5. Add them to your .env

Authentication

Authentication is powered by Better Auth, a modern full-stack auth library.

Supported Methods

Method Description
Email + Password Standard registration and login
Google OAuth One-click sign-in with Google
GitHub OAuth One-click sign-in with GitHub

How it works

  1. The Better Auth handler is mounted at /api/auth/* in the Express app.
  2. The frontend AuthContext (src/contexts/AuthContext.tsx) wraps the entire app and exposes:
    • user — current user profile (or null)
    • isLoading — true while session is being fetched
    • isAuthenticated — convenience boolean
    • login(email, password) — email/password sign-in
    • register(name, email, password) — new account creation
    • loginWithGoogle() — redirect to Google OAuth flow
    • loginWithGithub() — redirect to GitHub OAuth flow
    • logout() — sign out and clear session
  3. Protected routes redirect unauthenticated users to /login.
  4. Admin routes additionally check user.role === 'admin'.

Making a user an admin

After creating your account, run this SQL to promote yourself:

UPDATE users SET role = 'admin' WHERE email = '[email protected]';

Or use the Replit database tool / any SQL client connected to your DATABASE_URL.


Database

The project uses Drizzle ORM with PostgreSQL.

Tables

Table Purpose
users User accounts (extended Better Auth schema with plan, role, banned)
sessions Active login sessions (managed by Better Auth)
accounts OAuth account links (managed by Better Auth)
verifications Email verification tokens (managed by Better Auth)
projects User Figma projects
conversions Individual conversion jobs
activity User activity feed events

Schema files

All schema lives in lib/db/src/schema/. Each table is a separate file, re-exported from index.ts.

Migrations

This project uses push-based schema management (Drizzle Kit push):

# Apply schema changes to the database
pnpm --filter @workspace/db run push

# Force push (resets conflicting columns — use carefully)
pnpm --filter @workspace/db run push-force

Production note: On Replit, the production database is automatically migrated when you publish. Drizzle diffs the dev schema against prod and applies changes through the Publish UI.


API Reference

The API is contract-first: all endpoints are defined in lib/api-spec/openapi.yaml and React Query hooks are auto-generated from it.

Re-generate hooks after spec changes

pnpm --filter @workspace/api-spec run codegen

Base URL

All endpoints are prefixed with /api.

Endpoint Summary

User

Method Path Description
GET /api/user/me Get current user profile
PATCH /api/user/me Update profile (name, avatar)

Projects

Method Path Description
GET /api/projects List user's projects
POST /api/projects Create a project
GET /api/projects/:id Get project by ID
PATCH /api/projects/:id Update project
DELETE /api/projects/:id Delete project

Conversions

Method Path Description
GET /api/conversions List user's conversions
POST /api/conversions Submit a new conversion
GET /api/conversions/:id Get conversion by ID
DELETE /api/conversions/:id Delete conversion
POST /api/conversions/:id/regenerate Re-run a conversion

Dashboard

Method Path Description
GET /api/dashboard/stats User stats (projects, conversions, success rate)
GET /api/dashboard/activity Recent activity feed (last 20 events)

Admin

Method Path Description
GET /api/admin/stats Platform-wide stats
GET /api/admin/users All users
PATCH /api/admin/users/:id Update user (plan, role, banned)
DELETE /api/admin/users/:id Delete user
GET /api/admin/conversions All conversions
GET /api/admin/analytics/daily Daily conversion chart data (30 days)
GET /api/admin/analytics/frameworks Framework usage breakdown

Auth (Better Auth)

Method Path Description
POST /api/auth/sign-in/email Email/password login
POST /api/auth/sign-up/email Register with email
GET /api/auth/sign-in/social?provider=google Start Google OAuth
GET /api/auth/sign-in/social?provider=github Start GitHub OAuth
POST /api/auth/sign-out Log out
GET /api/auth/session Get current session

Pages & Routes

Route Auth Required Description
/ No Marketing landing page
/login No Login (email/Google/GitHub)
/register No Register new account
/dashboard Yes User dashboard with stats
/projects Yes Projects list
/projects/:id Yes Project detail + conversions
/convert Yes New conversion form
/conversions/:id Yes Conversion result + code viewer
/pricing No Pricing plans
/settings Yes User settings
/admin Admin only Admin analytics dashboard
/admin/users Admin only User management table
/admin/conversions Admin only All conversions table

Admin Panel

The admin panel is accessible at /admin and requires role = 'admin'.

Promoting a user to admin

UPDATE users SET role = 'admin' WHERE email = '[email protected]';

Admin Features

  • Dashboard (/admin): KPI cards, daily conversions line chart, framework breakdown pie chart, recent signups
  • Users (/admin/users): Full searchable user table, inline plan/role editing, ban/unban, delete
  • Conversions (/admin/conversions): All platform conversions with status and framework filters

Development Workflow

Running all type checks

pnpm run typecheck

Building for production

pnpm run build

Adding a new API endpoint

  1. Add it to the spec: Edit lib/api-spec/openapi.yaml
  2. Re-run codegen: pnpm --filter @workspace/api-spec run codegen
  3. Implement the route: Add handler in artifacts/api-server/src/routes/
  4. Register the route: Import it in artifacts/api-server/src/routes/index.ts
  5. Use the hook: Import the generated hook from @workspace/api-client-react in your React component

Adding a new database table

  1. Create a new file in lib/db/src/schema/ (e.g. lib/db/src/schema/invoices.ts)
  2. Export it from lib/db/src/schema/index.ts
  3. Run pnpm --filter @workspace/db run push

Key commands

# Install all workspace dependencies
pnpm install

# Run the API server in development
pnpm --filter @workspace/api-server run dev

# Run the frontend in development
pnpm --filter @workspace/figuro run dev

# Full typecheck (all packages)
pnpm run typecheck

# Build everything
pnpm run build

# Push DB schema changes
pnpm --filter @workspace/db run push

# Re-generate API client hooks from OpenAPI spec
pnpm --filter @workspace/api-spec run codegen

Deployment

Deploying on Replit

  1. Click the Deploy button in the Replit UI
  2. Replit will automatically:
    • Build the frontend (vite build)
    • Build the API server (esbuild)
    • Diff and apply any schema changes to the production database
  3. The app will be live at your .replit.app domain (or a custom domain if configured)

Deploying elsewhere (VPS, Railway, Render, Fly.io, etc.)

  1. Set all environment variables listed in Environment Variables
  2. Build:
    pnpm install --frozen-lockfile
    pnpm run build
    
  3. Start the API server:
    node artifacts/api-server/dist/index.mjs
    
  4. Serve the frontend from artifacts/figuro/dist/public via a static file server (nginx, Caddy, etc.) or configure the Express server to serve it.
  5. Apply DB schema:
    pnpm --filter @workspace/db run push
    

Environment-specific OAuth callback URLs

When deploying to production, update your OAuth app callback URLs:

  • Google: Add https://your-domain.com/api/auth/callback/google
  • GitHub: Update callback URL to https://your-domain.com/api/auth/callback/github
  • BETTER_AUTH_URL: Set to https://your-domain.com

GitHub Integration

To push this project to GitHub:

First time setup

git init
git add .
git commit -m "Initial commit: Figuro SaaS platform"
git branch -M main
git remote add origin https://github.com/your-username/figuro.git
git push -u origin main

Subsequent pushes

git add .
git commit -m "Your commit message"
git push

Make sure your .gitignore includes:

.env
node_modules/
dist/
.DS_Store
*.tsbuildinfo

Never commit your .env file. Store secrets in your hosting platform's environment variable manager (Replit Secrets, Railway Variables, etc.).


Troubleshooting

DATABASE_URL must be set error

Ensure DATABASE_URL is in your environment. On Replit, it's auto-provisioned. Locally, add it to .env.

OAuth redirect mismatch

The callback URL registered in Google/GitHub must exactly match {BETTER_AUTH_URL}/api/auth/callback/{provider}. Double-check BETTER_AUTH_URL has no trailing slash and matches the URL your server is actually running on.

BETTER_AUTH_SECRET not set

Generate a strong secret: openssl rand -base64 32 or use https://generate-secret.vercel.app/32.

Schema push fails with "column already exists"

pnpm --filter @workspace/db run push-force

TypeScript errors after changing the OpenAPI spec

Always re-run codegen after spec changes:

pnpm --filter @workspace/api-spec run codegen

Port conflicts

The API server reads PORT from the environment. Make sure nothing else is running on the same port. Vite's port is separately configured in vite.config.ts.

Admin panel shows "Forbidden"

Your user account needs role = 'admin'. Run:

UPDATE users SET role = 'admin' WHERE email = '[email protected]';

License

MIT — feel free to use, modify, and distribute this project.

Top categories

Loading Svelte Themes