Skip to main content
ClypAI uses a combination of PostgreSQL for structured data and Supabase for cloud storage to provide a robust and scalable storage solution.

Storage Architecture

ClypAI’s storage system consists of two main components:

PostgreSQL Database

Stores user accounts, organizations, authentication, connections, and metadata

Supabase Storage

Handles video files, thumbnails, and other binary assets

PostgreSQL Database

Overview

ClypAI uses PostgreSQL as the primary relational database, managed through Better Auth’s database hooks and connection pooling. Key Features:
  • Connection pooling with pg library
  • Automatic schema management via Better Auth
  • Support for organizations and multi-tenancy
  • Encrypted connections via SSL

Database Configuration

1

Set Up PostgreSQL Instance

You can use any PostgreSQL provider:Minimum version: PostgreSQL 12 or higher
2

Configure Connection String

Add your database connection string to .env:
DATABASE_URL="postgresql://user:password@host:5432/database?sslmode=require"
The connection string format:
postgresql://[user]:[password]@[host]:[port]/[database]?[parameters]
3

Initialize Database

Better Auth will automatically create required tables on first run:
  • user - User accounts and profiles
  • session - Active user sessions
  • account - OAuth provider connections
  • verification - Email verification tokens
  • organization - Organization/workspace data
  • member - Organization members and roles
  • invitation - Pending invitations
  • waitlist - Waitlist entries (if enabled)
No manual migration is required.
4

Verify Connection

Start your development server to verify the database connection:
npm run dev
Check the console for any connection errors.

Database Schema

Better Auth manages the core authentication and organization tables. ClypAI extends this schema with additional tables for:
  • Projects: Video editing projects and clips
  • Connections: Social media platform connections
  • Brand Kits: Saved brand assets and templates
  • Workers: Background job processing status
  • Metrics: Usage tracking and analytics
Database hooks in Better Auth automatically create an organization for each new user with a unique slug generated using ULID.

Connection Pooling

ClypAI uses the pg library’s connection pooling:
import { Pool } from "pg";

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});
Connection Pool Benefits:
  • Reuses database connections for better performance
  • Handles connection lifecycle automatically
  • Supports high concurrent request loads
  • Automatic reconnection on failures

Database Backups

Always configure automated backups for your production database:
  • Supabase: Daily backups included, point-in-time recovery on Pro plan
  • Neon: Automatic branching and backups
  • Vercel Postgres: Automated daily backups
  • Self-hosted: Configure pg_dump scheduled backups

Supabase Storage

Overview

Supabase Storage provides S3-compatible object storage for video files and assets. While the database connection is configured, Supabase Storage integration is available for file management. Storage Use Cases:
  • Source video files uploaded by users
  • Rendered/processed video clips
  • Thumbnail images and preview frames
  • Brand kit assets (logos, fonts, overlays)
  • Temporary files during processing

Supabase Setup

1

Create Supabase Project

  1. Go to supabase.com
  2. Create a new project
  3. Note your project URL and anon key
2

Configure Environment Variables

Add Supabase credentials to your .env file:
NEXT_PUBLIC_SUPABASE_URL="https://your-project.supabase.co"
NEXT_PUBLIC_SUPABASE_ANON_KEY="your-anon-key"
SUPABASE_SERVICE_ROLE_KEY="your-service-role-key"
3

Initialize Supabase Client

The Supabase client can be initialized in your application:
import { createClient } from '@supabase/supabase-js'

const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
4

Create Storage Buckets

Create buckets for different file types:
  • videos - Source and processed video files
  • thumbnails - Video thumbnails and previews
  • brand-kits - Brand assets and templates
  • temp - Temporary processing files

Storage Buckets Configuration

Recommended bucket settings:
Bucket Name: videosSettings:
  • Public: No (private)
  • File size limit: 500 MB
  • Allowed MIME types: video/*
Policies:
-- Users can upload to their organization folder
CREATE POLICY "Users can upload videos"
ON storage.objects FOR INSERT
WITH CHECK (
  bucket_id = 'videos' AND
  auth.uid()::text = (storage.foldername(name))[1]
);

-- Users can read their organization's videos
CREATE POLICY "Users can view their videos"
ON storage.objects FOR SELECT
USING (
  bucket_id = 'videos' AND
  auth.uid()::text = (storage.foldername(name))[1]
);
Bucket Name: thumbnailsSettings:
  • Public: Yes (with CDN)
  • File size limit: 5 MB
  • Allowed MIME types: image/jpeg, image/png, image/webp
Policies:
-- Public read access for thumbnails
CREATE POLICY "Thumbnails are publicly accessible"
ON storage.objects FOR SELECT
USING (bucket_id = 'thumbnails');

-- Authenticated users can upload thumbnails
CREATE POLICY "Users can upload thumbnails"
ON storage.objects FOR INSERT
WITH CHECK (
  bucket_id = 'thumbnails' AND
  auth.role() = 'authenticated'
);
Bucket Name: brand-kitsSettings:
  • Public: No (private)
  • File size limit: 10 MB
  • Allowed MIME types: image/*, font/*, application/json
Policies:
-- Organization members can manage brand kits
CREATE POLICY "Organization access to brand kits"
ON storage.objects
USING (
  bucket_id = 'brand-kits' AND
  auth.uid() IN (
    SELECT user_id FROM organization_members
    WHERE organization_id = (storage.foldername(name))[1]
  )
);

File Upload Implementation

Typical file upload flow:
// Upload a video file
const uploadVideo = async (file: File, organizationId: string) => {
  const filePath = `${organizationId}/${Date.now()}_${file.name}`
  
  const { data, error } = await supabase.storage
    .from('videos')
    .upload(filePath, file, {
      cacheControl: '3600',
      upsert: false
    })
  
  if (error) throw error
  return data.path
}

// Get signed URL for private file
const getVideoUrl = async (filePath: string) => {
  const { data } = await supabase.storage
    .from('videos')
    .createSignedUrl(filePath, 3600) // 1 hour expiry
  
  return data?.signedUrl
}

// Delete a file
const deleteVideo = async (filePath: string) => {
  const { error } = await supabase.storage
    .from('videos')
    .remove([filePath])
  
  if (error) throw error
}

Storage Optimization

Optimize storage usage and costs:
  1. Compress videos before upload using FFmpeg
  2. Generate thumbnails at lower resolution
  3. Set lifecycle policies to delete temporary files
  4. Use CDN for public assets (thumbnails, brand kits)
  5. Implement chunked uploads for large files

File Naming Conventions

Recommended file path structure:
videos/
  {organizationId}/
    {projectId}/
      source/
        {timestamp}_{filename}.mp4
      processed/
        {clipId}_{variant}.mp4

thumbnails/
  {organizationId}/
    {projectId}/
      {clipId}_thumb.jpg

brand-kits/
  {organizationId}/
    logos/
      {assetId}.png
    fonts/
      {fontName}.ttf
    templates/
      {templateId}.json

Edge Config (Feature Flags)

Overview

ClypAI uses Vercel Edge Config for feature flags and runtime configuration:
  • whitelist - Enable/disable whitelist mode
  • maintenance - Put app in maintenance mode
  • coming-soon - Show coming soon page

Configuration

1

Create Edge Config

Create an Edge Config in your Vercel project dashboard.
2

Add Edge Config URL

Add to .env:
EDGE_CONFIG="https://edge-config.vercel.com/..."
3

Set Feature Flags

In the Vercel dashboard, set your flags:
{
  "whitelist": false,
  "maintenance": false,
  "coming-soon": false
}

Using Feature Flags

Flags are defined in src/lib/flags.ts:
import { flag } from "flags/next";
import { get } from "@vercel/edge-config";

export const whitelistFlag = flag<boolean>({
  key: "whitelist-flag",
  description: "enable/disable the whitelist mode.",
  defaultValue: false,
  async decide() {
    return (await get("whitelist")) ?? false;
  },
});
Use in components:
import { whitelistFlag } from "@/lib/flags";

const isWhitelisted = await whitelistFlag();

Storage Monitoring

Metrics to Track

Database Metrics

  • Active connections
  • Query performance
  • Database size
  • Table growth rate

Storage Metrics

  • Total storage used
  • Bandwidth consumption
  • File count per bucket
  • Average file size

Setting Up Alerts

Configure alerts for:
  • Database connection pool exhaustion
  • Storage quota approaching limit (>80%)
  • Slow query performance (>1s)
  • Failed backup jobs

Troubleshooting

Database Connection Issues

Error: “Connection refused” or “Timeout” Solutions:
  • Verify DATABASE_URL is correct
  • Check database firewall allows your IP
  • Ensure SSL mode is configured correctly
  • Verify database is running and accessible

Storage Upload Failures

Error: Upload fails or times out Solutions:
  • Check file size is within bucket limits
  • Verify MIME type is allowed
  • Ensure user has proper RLS policies
  • Check network connection and Supabase status

RLS Policy Errors

Error: “Row level security policy violation” Solutions:
  • Verify user is authenticated
  • Check policy matches user’s organization
  • Use service role key for admin operations
  • Review and update RLS policies

Best Practices

  • Always use environment variables for credentials
  • Enable Row Level Security (RLS) on all Supabase tables
  • Use signed URLs for private files
  • Rotate service role keys regularly
  • Enable SSL for database connections
  • Use connection pooling for database
  • Implement CDN for public assets
  • Compress files before storage
  • Set appropriate cache headers
  • Use database indexes on frequently queried columns
  • Delete temporary files after processing
  • Implement storage lifecycle policies
  • Compress videos to reduce storage size
  • Use thumbnail generation instead of storing full images
  • Monitor and set storage quotas per organization
  • Enable automated database backups
  • Test restore procedures regularly
  • Keep separate backups of critical data
  • Document recovery procedures
  • Set backup retention policies

Next Steps

Back to Integrations

Return to the integrations overview

Build docs developers (and LLMs) love