mirror of
http://88.130.71.182:3000/BlitTech/deals24togo_be.git
synced 2026-06-12 23:33:21 +00:00
Initial commit
This commit is contained in:
180
migrations/001_initial_schema.sql
Normal file
180
migrations/001_initial_schema.sql
Normal file
@@ -0,0 +1,180 @@
|
||||
-- ============================================================
|
||||
-- Deals24Togo — Supabase Database Schema
|
||||
-- Run this in Supabase SQL Editor to create all tables
|
||||
-- ============================================================
|
||||
|
||||
-- Enable UUID generation
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
|
||||
-- ── USERS ────────────────────────────────────────────────
|
||||
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
email TEXT UNIQUE NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
role TEXT NOT NULL DEFAULT 'visitor'
|
||||
CHECK (role IN ('admin', 'agency', 'visitor')),
|
||||
verified BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
phone TEXT,
|
||||
avatar_url TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_users_email ON users (email);
|
||||
CREATE INDEX idx_users_role ON users (role);
|
||||
|
||||
-- ── AGENCIES ─────────────────────────────────────────────
|
||||
|
||||
CREATE TABLE IF NOT EXISTS agencies (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT NOT NULL DEFAULT '',
|
||||
logo TEXT,
|
||||
address TEXT NOT NULL DEFAULT '',
|
||||
phone TEXT NOT NULL DEFAULT '',
|
||||
email TEXT NOT NULL DEFAULT '',
|
||||
website TEXT,
|
||||
verified BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_agencies_user_id ON agencies (user_id);
|
||||
CREATE INDEX idx_agencies_verified ON agencies (verified);
|
||||
|
||||
-- ── CATEGORIES ───────────────────────────────────────────
|
||||
|
||||
CREATE TABLE IF NOT EXISTS categories (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
name TEXT NOT NULL,
|
||||
description TEXT NOT NULL DEFAULT '',
|
||||
icon TEXT NOT NULL DEFAULT 'tag',
|
||||
slug TEXT UNIQUE NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_categories_slug ON categories (slug);
|
||||
|
||||
-- ── LISTINGS ─────────────────────────────────────────────
|
||||
|
||||
CREATE TABLE IF NOT EXISTS listings (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
title TEXT NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
price NUMERIC(12, 2) NOT NULL DEFAULT 0,
|
||||
images JSONB NOT NULL DEFAULT '[]'::JSONB,
|
||||
status TEXT NOT NULL DEFAULT 'pending'
|
||||
CHECK (status IN ('pending', 'approved', 'rejected')),
|
||||
agency_id UUID NOT NULL REFERENCES agencies(id) ON DELETE CASCADE,
|
||||
category_id UUID NOT NULL REFERENCES categories(id) ON DELETE RESTRICT,
|
||||
location TEXT NOT NULL DEFAULT '',
|
||||
listing_type TEXT NOT NULL DEFAULT 'sale'
|
||||
CHECK (listing_type IN ('sale', 'rent')),
|
||||
condition TEXT CHECK (condition IN ('new', 'used', 'refurbished')),
|
||||
negotiable BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
views_count INTEGER NOT NULL DEFAULT 0,
|
||||
rejection_reason TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_listings_status ON listings (status);
|
||||
CREATE INDEX idx_listings_agency_id ON listings (agency_id);
|
||||
CREATE INDEX idx_listings_category_id ON listings (category_id);
|
||||
CREATE INDEX idx_listings_price ON listings (price);
|
||||
CREATE INDEX idx_listings_created_at ON listings (created_at DESC);
|
||||
CREATE INDEX idx_listings_views_count ON listings (views_count DESC);
|
||||
CREATE INDEX idx_listings_location ON listings USING gin (to_tsvector('english', location));
|
||||
|
||||
-- Full-text search index on title + description
|
||||
CREATE INDEX idx_listings_fts ON listings USING gin (
|
||||
to_tsvector('english', title || ' ' || description)
|
||||
);
|
||||
|
||||
-- ── MESSAGES ─────────────────────────────────────────────
|
||||
|
||||
CREATE TABLE IF NOT EXISTS messages (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
listing_id UUID NOT NULL REFERENCES listings(id) ON DELETE CASCADE,
|
||||
agency_id UUID NOT NULL REFERENCES agencies(id) ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
email TEXT NOT NULL,
|
||||
phone TEXT,
|
||||
message TEXT NOT NULL,
|
||||
read BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_messages_agency_id ON messages (agency_id);
|
||||
CREATE INDEX idx_messages_listing_id ON messages (listing_id);
|
||||
CREATE INDEX idx_messages_read ON messages (read);
|
||||
|
||||
-- ── FAVORITES ────────────────────────────────────────────
|
||||
|
||||
CREATE TABLE IF NOT EXISTS favorites (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
listing_id UUID NOT NULL REFERENCES listings(id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
UNIQUE (user_id, listing_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_favorites_user_id ON favorites (user_id);
|
||||
CREATE INDEX idx_favorites_listing_id ON favorites (listing_id);
|
||||
|
||||
-- ── ROW LEVEL SECURITY (RLS) ────────────────────────────
|
||||
-- NOTE: The backend uses the service_role key which bypasses RLS.
|
||||
-- These policies are for any direct Supabase client access.
|
||||
|
||||
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE agencies ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE categories ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE listings ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE messages ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE favorites ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Public read for approved listings
|
||||
CREATE POLICY "Public can view approved listings"
|
||||
ON listings FOR SELECT
|
||||
USING (status = 'approved');
|
||||
|
||||
-- Public read for categories
|
||||
CREATE POLICY "Public can view categories"
|
||||
ON categories FOR SELECT
|
||||
TO anon, authenticated
|
||||
USING (true);
|
||||
|
||||
-- Public read for verified agencies
|
||||
CREATE POLICY "Public can view agencies"
|
||||
ON agencies FOR SELECT
|
||||
USING (true);
|
||||
|
||||
-- Users can read their own data
|
||||
CREATE POLICY "Users can view own data"
|
||||
ON users FOR SELECT
|
||||
USING (auth.uid()::text = id::text);
|
||||
|
||||
-- Users can manage their own favorites
|
||||
CREATE POLICY "Users manage own favorites"
|
||||
ON favorites FOR ALL
|
||||
USING (auth.uid()::text = user_id::text);
|
||||
|
||||
-- ── SEED DATA ────────────────────────────────────────────
|
||||
|
||||
-- Default categories
|
||||
INSERT INTO categories (name, description, icon, slug) VALUES
|
||||
('Real Estate', 'Homes, apartments, land, and commercial properties', 'home', 'real-estate'),
|
||||
('Vehicles', 'Cars, motorcycles, boats, and other vehicles', 'car', 'vehicles'),
|
||||
('Electronics', 'Computers, phones, TVs, and other electronic devices', 'smartphone', 'electronics'),
|
||||
('Furniture', 'Home and office furniture, decor, and appliances', 'sofa', 'furniture'),
|
||||
('Jobs', 'Job listings and career opportunities', 'briefcase', 'jobs'),
|
||||
('Services', 'Professional services and skilled trades', 'wrench', 'services')
|
||||
ON CONFLICT (slug) DO NOTHING;
|
||||
|
||||
-- ── STORAGE BUCKET ───────────────────────────────────────
|
||||
-- Run this separately in Supabase Dashboard > Storage or via API:
|
||||
-- CREATE BUCKET 'listings' with public access enabled
|
||||
5
migrations/002_supabase_auth.sql
Normal file
5
migrations/002_supabase_auth.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
-- Migration 002: Supabase Auth integration
|
||||
-- Supabase Auth manages passwords; password_hash is no longer required.
|
||||
|
||||
ALTER TABLE users ALTER COLUMN password_hash DROP NOT NULL;
|
||||
ALTER TABLE users ALTER COLUMN password_hash SET DEFAULT NULL;
|
||||
55
migrations/003_payments.sql
Normal file
55
migrations/003_payments.sql
Normal file
@@ -0,0 +1,55 @@
|
||||
-- Migration 003: Payments, Subscriptions, Purchases
|
||||
-- Run in Supabase SQL editor
|
||||
|
||||
-- Extend listings status to include 'sold'
|
||||
ALTER TABLE listings
|
||||
DROP CONSTRAINT IF EXISTS listings_status_check;
|
||||
ALTER TABLE listings
|
||||
ADD CONSTRAINT listings_status_check
|
||||
CHECK (status IN ('pending', 'approved', 'rejected', 'sold'));
|
||||
|
||||
-- payments: one row per CinetPay transaction
|
||||
CREATE TABLE payments (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
transaction_id TEXT UNIQUE NOT NULL,
|
||||
type TEXT NOT NULL
|
||||
CHECK (type IN ('subscription', 'purchase')),
|
||||
payer_id UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||
amount NUMERIC(12,2) NOT NULL,
|
||||
currency TEXT NOT NULL DEFAULT 'XOF',
|
||||
status TEXT NOT NULL DEFAULT 'pending'
|
||||
CHECK (status IN ('pending', 'completed', 'failed', 'cancelled')),
|
||||
payment_method TEXT,
|
||||
operator_id TEXT,
|
||||
metadata JSONB DEFAULT '{}'::JSONB,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
paid_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
-- subscriptions: active plan per agency
|
||||
CREATE TABLE subscriptions (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
agency_id UUID NOT NULL REFERENCES agencies(id) ON DELETE CASCADE,
|
||||
plan TEXT NOT NULL CHECK (plan IN ('monthly', 'yearly')),
|
||||
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'expired')),
|
||||
starts_at TIMESTAMPTZ NOT NULL,
|
||||
ends_at TIMESTAMPTZ NOT NULL,
|
||||
payment_id UUID REFERENCES payments(id),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- purchases: visitor buys a listing
|
||||
CREATE TABLE purchases (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
listing_id UUID NOT NULL REFERENCES listings(id) ON DELETE CASCADE,
|
||||
buyer_id UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||
amount NUMERIC(12,2) NOT NULL,
|
||||
payment_id UUID REFERENCES payments(id),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_payments_transaction_id ON payments(transaction_id);
|
||||
CREATE INDEX idx_payments_payer_id ON payments(payer_id);
|
||||
CREATE INDEX idx_subscriptions_agency_id ON subscriptions(agency_id);
|
||||
CREATE INDEX idx_subscriptions_ends_at ON subscriptions(ends_at);
|
||||
CREATE INDEX idx_purchases_listing_id ON purchases(listing_id);
|
||||
Reference in New Issue
Block a user