Skip to content

tot/clipper

Repository files navigation

Clipper

A multi-tenant campaign and payouts platform for short-form creators. Built with Next.js App Router, Supabase (Postgres + Auth + Edge Functions), Shadcn UI, Tailwind, and Stripe. Includes a metrics ingestion pipeline using Bright Data and Supabase Edge Functions.

  • Admins, Content Managers, and Creators collaborate in organizations (tenants)
  • Managers define campaign payout rules; Admins approve them
  • Creators upload creatives with multiple URLs (TikTok, Instagram, YouTube, Facebook)
  • Metrics are periodically scraped and aggregated for payouts
  • Statements are generated and payouts executed (test mode) via Stripe

Contents

Features

  • Works across the Next.js stack (App Router, Middleware, Server Actions, Route Handlers)
  • Supabase SSR client using cookies (server and client helpers)
  • Multi-tenant RBAC: tenant_admin, manager, creator plus platform admins
  • Campaign rules with approval gates
  • Creatives with multiple platform URLs and URL invalidation
  • Metrics ingestion (views, likes, comments) and timeseries storage
  • Payout previews and statement generation; Stripe Connect onboarding and webhook sync
  • UI built with Shadcn UI, Radix UI, Tailwind, and TanStack Table

Architecture

  • Frontend: Next.js 14 (App Router), TypeScript (strict), Shadcn UI, Tailwind
  • Auth: Supabase Auth (SSR cookies via @supabase/ssr)
  • Data: Supabase Postgres with strict RLS and RPCs encapsulating logic
  • Payments: Stripe (Connect Express for creators) in test mode
  • Metrics: Supabase Edge Functions (Deno) for scheduler/worker and Bright Data client

Key helpers:

  • lib/supabase/server.ts – server-side Supabase client and active tenant helpers (requireActiveTenant, getActiveTenantIdOrNull)
  • lib/supabase/client.ts – browser Supabase client
  • lib/supabase/middleware.ts – auth cookie refresh and guarded routing, wired via middleware.ts
  • app/api/** – server endpoints (e.g., Stripe webhook, onboard, login-link)
  • sql/rbac.sql – database schema, RLS, triggers, and RPCs (includes files under sql/rbac/)

Getting Started

Prerequisites

  • Node 18+ and npm
  • Supabase project (cloud or local)
  • Stripe account (test mode)
  • Bright Data account for metrics datasets

Environment Variables

Create .env.local and set:

# Supabase (client)
NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY=your_supabase_anon_key

# Supabase (server/admin)
SUPABASE_SERVICE_KEY=your_service_role_key

# Stripe
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...

# App URL (used for Stripe return/login links)
NEXT_PUBLIC_APP_URL=http://localhost:3000
# or when on Vercel
# NEXT_PUBLIC_VERCEL_URL=your-app.vercel.app

Local Setup

  1. Install dependencies
npm install
  1. Prepare Supabase schema
  • Ensure your Supabase database has the schema and RPCs from sql/rbac.sql and the split files under sql/rbac/.
  • You can run sql/rbac.sql end-to-end in the Supabase SQL editor or via psql.
  • See sql/README.md for a compact overview and execution order.
  1. Start the dev server
npm run dev

App runs at http://localhost:3000.

  1. (Optional) Start Stripe CLI webhook forwarding for local testing
stripe listen --forward-to localhost:3000/api/stripe/webhook

Database & RBAC

See sql/README.md and sql/rbac.sql for full details. Highlights:

  • Roles: tenant_admin > manager > creator with union-of-roles per user per tenant
  • Platform admin: separate table granting global operator capabilities
  • Core tables: tenants, tenant_memberships, campaigns, campaign_creators, creatives, creative_urls, creative_url_metrics, payout_accounts, payout_statements, payout_line_items
  • RLS everywhere; helper functions enforce permissions (me_has_tenant_permission, is_my_creative, etc.)
  • RPCs for workflows: create_tenant, create_campaign, approve_campaign, campaign_invite_creator, creative_upload, creative_add_url, creative_invalidate_url, preview_creator_payout, create_payout_statement_from_preview, mark_payout_status, etc.

Tenant resolution pattern (server):

import { requireActiveTenant } from "@/lib/supabase/server";

const tenant = await requireActiveTenant();

Always scope queries with the active tenant on the server.

Stripe Integration

Endpoints:

  • POST /api/stripe/onboard – creates or retrieves a Stripe Connect Express account, returns onboarding link
  • POST /api/stripe/login-link – returns a Stripe dashboard login link for the connected account
  • POST /api/stripe/webhook – handles account.updated and transfer.* events; updates payout_accounts and payout_statements

Testing locally:

stripe listen --forward-to localhost:3000/api/stripe/webhook
# Examples
stripe trigger account.updated
# Or resend a specific event
stripe events resend evt_123

Metrics Pipeline

The metrics pipeline lives in the sibling repo clipper-functions/ (Supabase Edge Functions):

  • Scheduler: supabase/functions/metrics-scheduler/index.ts – periodically seeds/starts due jobs
  • Worker: supabase/functions/metrics-worker/index.ts – webhook endpoint to receive Bright Data results and write metrics
  • Scraper client: supabase/functions/scraper/clients/brightdata.ts
  • Platforms: supabase/functions/scraper/platforms/{tiktok,instagram,facebook,youtube}.ts

Job lifecycle:

  1. Ensure jobs exist for tracked URLs (ensure_metrics_jobs)
  2. Start due metrics_jobs in small batches; Bright Data posts back to the Worker
  3. Worker maps rows → { views, likes, comments }, inserts into creative_url_metrics, and schedules next run (complete_metrics_job)
  4. Failures call fail_metrics_job and can notify via webhook

Environment variables are required in the Edge Functions project; see above.

Project Structure

app/
  api/stripe/{onboard,login-link,webhook}/route.ts
  api/campaigns/*, api/tenants/* – server endpoints
  dashboard/* – UI routes
components/* – UI components (Shadcn/Radix), tables, forms
hooks/* – client and server hooks (role checks, dashboard store)
lib/
  supabase/{server.ts,client.ts,middleware.ts}
  stripe/server.ts
  api/* helpers
sql/
  rbac.sql (+ rbac/*)

Scripts:

  • npm run dev – start Next.js dev server
  • npm run build – production build
  • npm run start – start production server
  • npm run lint – run ESLint

Role Guides

Role capabilities are enforced via Supabase RLS and RPCs (see sql/rbac.sql). Users can hold multiple roles within the same tenant; permissions are the union of their roles. A separate platform admin table grants global operator powers.

Admin (Tenant Admin)

  • Approvals: approve/deny campaign rules (approve_campaign, deny_campaign)
  • Memberships: invite managers/creators, promote/demote roles (promote_user_in_tenant)
  • Creatives: read all, invalidate URLs (creative_invalidate_url)
  • Payouts: preview, create statements, and execute (preview_creator_payout, create_payout_statement_from_preview, mark_payout_status)
  • Tenants: create/manage, delete organization (secure RPC + confirmation)

Content Manager

  • Campaigns: create campaigns, configure payout rules; view approval status
  • Invites: invite creators to campaigns (campaign_invite_creator)
  • Creatives: approve/deny pending creatives; invalidate violating URLs
  • Payouts: preview and generate statements; execution may be admin-gated

Content Creator

  • Join: accept campaign invites (campaign_accept_invite)
  • Upload: create creatives and attach multiple URLs (creative_upload, creative_add_url)
  • Metrics: view timeseries and totals for own creatives
  • Payouts: view own statements; connect/update payout account (upsert_my_payout_account)

Notes:

  • Campaign uploads require campaign rules to be approved.
  • URL invalidation excludes that URL’s metrics from payout math.
  • Metrics ingestion is performed by background functions; delays are possible.

Development

  • Prefer Server Components; use Client Components for browser APIs, Zustand, forms
  • Use requireActiveTenant() for SSR tenant scoping; store cookie active_tenant
  • Forms: react-hook-form + Zod; validate on client and server actions
  • Avoid exposing service keys in browser; use RPCs with user session and RLS

Deployment

  • Vercel recommended. Set the environment variables listed above.
  • Configure Stripe webhook to https://your-domain/api/stripe/webhook with STRIPE_WEBHOOK_SECRET.
  • Deploy and configure the Supabase Edge Functions in clipper-functions/ (scheduler/worker) with required env vars and public Worker URL for Bright Data datasets.

Troubleshooting

  • Auth logout loops: ensure middleware.ts uses updateSession and env vars are set
  • Webhook 400: verify STRIPE_WEBHOOK_SECRET and that raw body is used (route handler already uses arrayBuffer)
  • Missing RPCs/tables: confirm sql/rbac.sql executed successfully
  • Metrics not updating: check Worker logs, dataset webhook URL, and service-role envs

Payments & Payouts Notes

Environment variables recap:

  • NEXT_PUBLIC_SUPABASE_URL
  • NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY
  • SUPABASE_SERVICE_KEY
  • STRIPE_SECRET_KEY
  • STRIPE_WEBHOOK_SECRET
  • NEXT_PUBLIC_APP_URL or NEXT_PUBLIC_VERCEL_URL

Local webhook testing:

stripe listen --forward-to localhost:3000/api/stripe/webhook

Open items (roadmap):

  • notifications for approval/denied creatives for user-side
  • notifications for payments for both creators and managers
  • notifications for campaign managers about new creatives
  • send email to user invited to org
  • show list of pending invitations when user visits orgs page
  • more robust search and filtering members
  • suspense and skeleton loaders for anything that is data fetched
  • allow adding/removing users within an org to a campaign (with autocomplete)
  • scope the date range of the analytics to start when the user added it

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors