Back to Home

More Features

Email system, background jobs with Inngest, admin dashboard, and database schema.

Additional built-in features including transactional email, background jobs, admin dashboard, and the full database schema.

Email System

Transactional emails via Resend. All emails use dynamic brand configuration from brand.ts.

Available Templates

  • sendWelcomeEmail() — Triggered on user sign up (onboarding email)
  • sendInvoiceEmail() — Triggered on payment received (receipt with PDF attachment)
  • sendInviteEmail() — Triggered on team invitation (organization invite with token)
  • sendOrganizationWelcomeEmail() — Triggered on org created (confirmation to founder)
  • sendSubscriptionActivatedEmail() — Triggered on sub starts (plan details + next billing)
  • sendSubscriptionChargedEmail() — Triggered on recurring charge (receipt + next billing)
  • sendSubscriptionCancelledEmail() — Triggered on sub cancelled (end date + resubscribe link)
  • sendPlanChangedEmail() — Triggered on plan upgrade/downgrade (old plan → new plan details)

Email Configuration

Email sender addresses are configured in brand.email:

TypeScript
brand.email.fromSupport  // Support emails
brand.email.fromBilling  // Billing/payment emails
brand.email.fromNoReply  // Automated notifications
brand.email.replyTo      // Reply-to address

Background Jobs (Inngest)

Async job queue for event-driven tasks.

Event Types

TypeScript
'user.signed-up'              // New user registration
'license.purchased'           // License purchase
'organization.created'        // Org creation
'organization.member-invited' // Team invitation
'invoice.generated'           // Invoice ready
'subscription.charged'        // Recurring payment
'subscription.cancelled'      // Subscription ended
'credits.low-balance'         // Credits below threshold
'credits.purchased'           // Credit pack bought

Sending Events

TypeScript
import { inngest } from '@/lib/inngest';

await inngest.send({
  name: 'user.signed-up',
  data: { userId: user.id, email: user.email, name: 'John Doe' },
});

Job handlers are defined in src/lib/inngest/functions/ and automatically discovered.

Admin Dashboard

Superadmin control panel at /admin. Requires is_super_admin: true on the user's profile.

Admin Pages

  • /admin — Overview with key metrics
  • /admin/users — User management and browsing
  • /admin/subscriptions — Subscription management with filters
  • /admin/contacts — Support form submissions
  • /admin/analytics — Revenue and signup trends
  • /admin/waitlist — Waitlist management

Overview Metrics

  • Total users
  • Active subscriptions
  • Monthly revenue
  • Unread contact submissions
  • Waitlist pending
  • Organizations count (if multi-tenancy)
  • Credits granted this month (if credits)
  • Recent signups and subscriptions

Database Schema

Core Tables

  • profiles — User profiles (extends auth.users) — Always present
  • plans — Subscription plan definitions — Always present
  • subscriptions — Active subscriptions — Always present
  • licenses — License tracking — Always present
  • invoices — Invoice records — Always present
  • audit_logs — Audit trail — Always present
  • webhook_events — Webhook event log — Always present
  • admin_activity_log — Admin actions — Always present
  • contact_submissions — Contact form data — Always present
  • waitlist — Waitlist entries — Always present

Optional Tables

  • organizations — Feature: multiTenancy — Organization records
  • organization_members — Feature: multiTenancy — User-org membership with roles
  • organization_invites — Feature: multiTenancy — Pending invitations
  • credit_balances — Feature: credits — Current balance per tenant
  • credit_transactions — Feature: credits — Full audit log

Row Level Security

All tables have RLS enabled. Policies ensure:

  • Users can only access their own data
  • In multi-tenant mode, access is checked via organization_members
  • Admin operations use supabaseAdmin (service role) to bypass RLS

Migrations

Located in supabase/migrations/:

  • core/001 through core/019 — Core schema (profiles, plans, subscriptions, credits, admin, storage, payment abstraction)
  • optional/multi-tenancy/001-003 — Organization tables

Authentication

Built on Supabase Auth with Row Level Security.

Server-Side Auth

TypeScript
import { createClient } from '@/lib/supabase/supabase-server';

const supabase = await createClient();
const { data: { user } } = await supabase.auth.getUser();

Client-Side Auth

TypeScript
import { createClient } from '@/lib/supabase/supabase-browser';

const supabase = createClient();
const { data: { user } } = await supabase.auth.getUser();

Supported Auth Methods

  • Email/password
  • Magic link
  • OAuth providers (Google, GitHub, etc.)
  • Password reset flow

Protected Routes

All /dashboard/* routes require authentication. The auth middleware redirects unauthenticated users to /login.