Skip to content

Repository files navigation

Magnetic logo

Magnetic

Create, publish, and manage lead magnets that actually convert.

Next.js TypeScript Cloudflare Supabase

A full-stack SaaS for building interactive lead magnets, capturing leads through public share pages, and turning them into customers — with built-in CRM, analytics, and billing.


Features

  • Visual form builder — design lead magnets with a drag-and-drop form builder, custom fields, and validation.
  • Public share pages — every lead magnet gets a hosted page (/v/[slug]) with smart deduplication to avoid duplicate leads.
  • Built-in CRM — collect, search, filter, and qualify leads in a dedicated workspace.
  • Analytics — track views, submissions, and conversion over time.
  • Subscriptions & billing — Stripe-powered plans (Free / Pro) with usage limits and customer portals.
  • Email notifications — transactional emails (verification, password reset, OTP, welcome) via Resend.
  • Auth — email/password with verification, OTP, and Google OAuth (better-auth).
  • Asset storage — screenshots and uploads served from Cloudflare R2.

Screenshots

Landing & form Dashboard & CRM Analytics
Landing form CRM Stats
Landing Share page

Tech stack

Layer Technology
Framework Next.js 15 (App Router, React 19)
API tRPC + React Query
Database PostgreSQL via Drizzle ORM
Auth better-auth
Billing Stripe
Email Resend
Storage Cloudflare R2
Jobs Trigger.dev
Styling Tailwind CSS v4 + shadcn/ui
Deploy Cloudflare via OpenNext

Project structure

The codebase follows a feature-first, module-based architecture. Server logic is split into thin tRPC procedures, business services, and Drizzle repositories, with input validation centralized in Zod DTOs.

src/
├─ app/                 # Next.js routes: (public), (auth), (private), api
├─ components/          # Shared UI (shadcn-style) and marketing sections
├─ db/                  # Drizzle client and schema
├─ lib/                 # Auth client/server, shared utilities
├─ modules/             # Feature modules (auth, lead-magnets, viewer, analytics,
│                       #   subscription, email, settings)
│   └─ <feature>/
│       ├─ server/      # procedures.ts, service.ts, repository.ts, dto.ts
│       ├─ components/  # Feature UI
│       └─ types/       # Shared types
├─ trpc/                # tRPC client/server setup
└─ trigger/             # Background jobs

Getting started

Prerequisites

  • Node.js 20+
  • pnpm 10+
  • A PostgreSQL database (e.g. Supabase)
  • Accounts/keys for Stripe, Resend, Google OAuth, and Cloudflare R2 (see .env.example)

Installation

# Install dependencies
pnpm install

# Copy and fill in environment variables
cp .env.example .env.local

# Apply database migrations
pnpm dlx drizzle-kit push

# Run the development server
pnpm dev

Open http://localhost:3000.

Note

drizzle.config.ts reads .env.development (or .env.local) for DATABASE_URL. Adjust the path there if your local env file is named differently.

Environment variables

All configuration is provided through environment variables. See .env.example for the full list and descriptions. Never commit real secrets — only .env.example is tracked.

Available scripts

Script Description
pnpm dev Start the Next.js dev server
pnpm build Build the production app
pnpm lint Run ESLint
pnpm test Run the Jest test suite
pnpm preview Build and preview the Cloudflare deployment locally
pnpm deploy Build and deploy to Cloudflare

Deployment

This app is deployed to Cloudflare using OpenNext for Cloudflare. Bindings (D1/Postgres, R2, secrets) are configured in wrangler.jsonc.

pnpm deploy

Set the same environment variables from .env.example as Cloudflare secrets / vars before deploying.

Security

  • Secrets are loaded from environment variables only — none are hardcoded in the source.
  • Authentication and session management are handled by better-auth; all protected procedures verify the session server-side (protectedProcedure).
  • Data access is scoped per-user at the service/repository layer (ownership checks on every query).
  • Security headers (HSTS, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy) are set globally in next.config.ts.
  • Public share pages only expose lead magnets explicitly marked active, and never reveal other users' data.

Releases

Packages

Contributors

Languages