Database Schema

ProductClank Arena uses Supabase (PostgreSQL) for data storage. This document outlines the key tables and relationships.

Core Tables

Products

products
├── id (uuid, primary key)
├── name (text)
├── description (text)
├── image_url (text)
├── website_url (text)
├── category (text)
├── tags (text[])
├── creator_id (uuid, foreign key → users)
├── believer_count (integer)
├── created_at (timestamp)
└── updated_at (timestamp)

Users

users
├── id (uuid, primary key)
├── farcaster_id (bigint, unique)
├── username (text)
├── display_name (text)
├── avatar_url (text)
├── wallet_address (text)
├── created_at (timestamp)
└── updated_at (timestamp)

Campaigns

campaigns
├── id (uuid, primary key)
├── product_id (uuid, foreign key → products)
├── creator_id (uuid, foreign key → users)
├── reward_amount (numeric)
├── reward_token (text)
├── start_date (timestamp)
├── end_date (timestamp)
├── status (text: 'draft' | 'active' | 'completed')
├── distribution_method (text)
├── created_at (timestamp)
└── updated_at (timestamp)

Auctions

auctions
├── id (uuid, primary key)
├── token_id (bigint, unique)
├── start_time (timestamp)
├── end_time (timestamp)
├── highest_bid (numeric)
├── highest_bidder (text)
├── is_settled (boolean)
├── winning_campaign_id (uuid, foreign key → campaigns)
├── tx_hash (text)
├── created_at (timestamp)
└── updated_at (timestamp)

Bids

bids
├── id (uuid, primary key)
├── auction_id (uuid, foreign key → auctions)
├── bidder_address (text)
├── bidder_id (uuid, foreign key → users)
├── amount (numeric)
├── campaign_id (uuid, foreign key → campaigns)
├── tx_hash (text)
├── created_at (timestamp)
└── is_refunded (boolean)

Believers (Product Votes)

product_believers
├── id (uuid, primary key)
├── product_id (uuid, foreign key → products)
├── user_id (uuid, foreign key → users)
├── created_at (timestamp)
└── UNIQUE(product_id, user_id)

Campaign Actions

campaign_actions
├── id (uuid, primary key)
├── campaign_id (uuid, foreign key → campaigns)
├── action_type (text)
├── action_data (jsonb)
├── reward_amount (numeric)
└── created_at (timestamp)

Action Submissions

action_submissions
├── id (uuid, primary key)
├── campaign_id (uuid, foreign key → campaigns)
├── action_id (uuid, foreign key → campaign_actions)
├── user_id (uuid, foreign key → users)
├── proof_data (jsonb)
├── status (text: 'pending' | 'approved' | 'rejected')
├── reviewed_at (timestamp)
├── created_at (timestamp)
└── updated_at (timestamp)

Leaderboard Tables

User Scores

user_scores
├── id (uuid, primary key)
├── user_id (uuid, foreign key → users)
├── builder_points (numeric)
├── believer_points (numeric)
├── combined_points (numeric)
├── last_updated (timestamp)
└── UNIQUE(user_id)

Leaderboard Snapshots

leaderboard_snapshots
├── id (uuid, primary key)
├── snapshot_date (date)
├── user_id (uuid, foreign key → users)
├── rank (integer)
├── builder_points (numeric)
├── believer_points (numeric)
├── combined_points (numeric)
└── created_at (timestamp)

Key Relationships

  • Products → Users: Many-to-one (creator)
  • Products → Believers: Many-to-many (users)
  • Campaigns → Products: Many-to-one
  • Campaigns → Users: Many-to-one (creator)
  • Auctions → Campaigns: One-to-one (winning campaign)
  • Bids → Auctions: Many-to-one
  • Bids → Users: Many-to-one (bidder)
  • Action Submissions → Campaigns: Many-to-one
  • Action Submissions → Users: Many-to-one

Indexes

Key indexes for performance:

  • Products: `creator_id`, `category`, `created_at`
  • Believers: `product_id`, `user_id` (composite unique)
  • Campaigns: `product_id`, `status`, `end_date`
  • Auctions: `token_id`, `is_settled`, `end_time`
  • Bids: `auction_id`, `bidder_address`, `created_at`
  • User Scores: `user_id`, `combined_points`

Database Functions

Upsert Auction

CREATE OR REPLACE FUNCTION upsert_auction(
  p_token_id BIGINT,
  p_start_time TIMESTAMP,
  p_end_time TIMESTAMP
) RETURNS uuid AS $$
-- Atomic auction upsert to prevent race conditions
$$ LANGUAGE plpgsql;

Get Auction Participants

CREATE OR REPLACE FUNCTION get_auction_participants(
  p_auction_id UUID
) RETURNS TABLE(...) AS $$
-- Returns all participants for an auction
$$ LANGUAGE plpgsql;