Update skills: add website-creator, mql-developer, ecommerce-astro
Changes: - Add FAL_KEY and GEMINI_API_KEY to .env.example - Update picture-it to use ~/.config/opencode/.env (unified creds) - Remove shodh-memory skill (no longer used) - Remove alphaear-* skills (deprecated) - Remove thai-frontend-dev skill (replaced by website-creator) - Remove theme-factory skill - Add mql-developer skill (MQL5 trading) - Add ecommerce-astro skill (Astro e-commerce) - Add website-creator skill (Next.js + Payload CMS) - Update install script for new skills
This commit is contained in:
421
skills/ecommerce-astro/scripts/supabase_migration.sql
Normal file
421
skills/ecommerce-astro/scripts/supabase_migration.sql
Normal file
@@ -0,0 +1,421 @@
|
||||
-- =====================================================
|
||||
-- E-commerce Database Schema for Supabase
|
||||
-- Astro 6 + React + PaySo Multi-vendor Marketplace
|
||||
-- =====================================================
|
||||
|
||||
-- Enable UUID extension
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
|
||||
-- =====================================================
|
||||
-- USERS & AUTHENTICATION
|
||||
-- =====================================================
|
||||
|
||||
CREATE TABLE users (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
email TEXT UNIQUE NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
name TEXT,
|
||||
phone TEXT,
|
||||
role TEXT DEFAULT 'customer' CHECK (role IN ('customer', 'vendor', 'admin')),
|
||||
avatar_url TEXT,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- =====================================================
|
||||
-- VENDOR PROFILES (Multi-vendor support)
|
||||
-- =====================================================
|
||||
|
||||
CREATE TABLE vendor_profiles (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id UUID REFERENCES users(id) ON DELETE CASCADE UNIQUE,
|
||||
store_name TEXT NOT NULL,
|
||||
store_slug TEXT UNIQUE NOT NULL,
|
||||
store_description TEXT,
|
||||
store_logo TEXT,
|
||||
bank_account TEXT,
|
||||
bank_name TEXT,
|
||||
payout_status TEXT DEFAULT 'pending' CHECK (payout_status IN ('pending', 'approved', 'rejected')),
|
||||
total_earnings DECIMAL(12,2) DEFAULT 0,
|
||||
approved_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- =====================================================
|
||||
-- CATEGORIES (Hierarchical)
|
||||
-- =====================================================
|
||||
|
||||
CREATE TABLE categories (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
name TEXT NOT NULL,
|
||||
slug TEXT UNIQUE NOT NULL,
|
||||
description TEXT,
|
||||
image_url TEXT,
|
||||
parent_id UUID REFERENCES categories(id),
|
||||
sort_order INT DEFAULT 0,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- =====================================================
|
||||
-- PRODUCTS
|
||||
-- =====================================================
|
||||
|
||||
CREATE TABLE products (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
vendor_id UUID REFERENCES vendor_profiles(id) ON DELETE CASCADE,
|
||||
category_id UUID REFERENCES categories(id),
|
||||
name TEXT NOT NULL,
|
||||
slug TEXT UNIQUE NOT NULL,
|
||||
description TEXT,
|
||||
price DECIMAL(12,2) NOT NULL,
|
||||
compare_at_price DECIMAL(12,2),
|
||||
cost_price DECIMAL(12,2),
|
||||
sku TEXT UNIQUE,
|
||||
barcode TEXT,
|
||||
inventory INT DEFAULT 0,
|
||||
low_stock_threshold INT DEFAULT 5,
|
||||
track_inventory BOOLEAN DEFAULT TRUE,
|
||||
allow_backorder BOOLEAN DEFAULT FALSE,
|
||||
weight DECIMAL(8,2),
|
||||
images JSONB DEFAULT '[]',
|
||||
metadata JSONB DEFAULT '{}',
|
||||
status TEXT DEFAULT 'draft' CHECK (status IN ('draft', 'active', 'archived')),
|
||||
featured BOOLEAN DEFAULT FALSE,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- =====================================================
|
||||
-- PRODUCT VARIANTS
|
||||
-- =====================================================
|
||||
|
||||
CREATE TABLE product_variants (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
product_id UUID REFERENCES products(id) ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
sku TEXT UNIQUE,
|
||||
price DECIMAL(12,2),
|
||||
inventory INT DEFAULT 0,
|
||||
attributes JSONB DEFAULT '{}',
|
||||
image_url TEXT,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- =====================================================
|
||||
-- REVIEWS
|
||||
-- =====================================================
|
||||
|
||||
CREATE TABLE reviews (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
product_id UUID REFERENCES products(id) ON DELETE CASCADE,
|
||||
user_id UUID REFERENCES users(id),
|
||||
order_id UUID,
|
||||
rating INT CHECK (rating >= 1 AND rating <= 5),
|
||||
title TEXT,
|
||||
comment TEXT,
|
||||
images JSONB DEFAULT '[]',
|
||||
verified_purchase BOOLEAN DEFAULT FALSE,
|
||||
status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'approved', 'rejected')),
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- =====================================================
|
||||
-- ORDERS
|
||||
-- =====================================================
|
||||
|
||||
CREATE TABLE orders (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
order_number TEXT UNIQUE NOT NULL,
|
||||
user_id UUID REFERENCES users(id),
|
||||
vendor_id UUID REFERENCES vendor_profiles(id),
|
||||
status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'confirmed', 'processing', 'shipped', 'delivered', 'cancelled', 'refunded')),
|
||||
payment_status TEXT DEFAULT 'unpaid' CHECK (payment_status IN ('unpaid', 'paid', 'failed', 'refunded')),
|
||||
subtotal DECIMAL(12,2) NOT NULL,
|
||||
tax DECIMAL(12,2) DEFAULT 0,
|
||||
shipping_cost DECIMAL(12,2) DEFAULT 0,
|
||||
total DECIMAL(12,2) NOT NULL,
|
||||
currency TEXT DEFAULT 'THB',
|
||||
payment_method TEXT,
|
||||
payment_provider TEXT,
|
||||
payment_ref TEXT,
|
||||
shipping_name TEXT,
|
||||
shipping_phone TEXT,
|
||||
shipping_address TEXT,
|
||||
shipping_city TEXT,
|
||||
shipping_postal TEXT,
|
||||
shipping_country TEXT DEFAULT 'Thailand',
|
||||
notes TEXT,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- =====================================================
|
||||
-- ORDER ITEMS
|
||||
-- =====================================================
|
||||
|
||||
CREATE TABLE order_items (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
order_id UUID REFERENCES orders(id) ON DELETE CASCADE,
|
||||
product_id UUID REFERENCES products(id),
|
||||
variant_id UUID REFERENCES product_variants(id),
|
||||
vendor_id UUID REFERENCES vendor_profiles(id),
|
||||
quantity INT NOT NULL,
|
||||
unit_price DECIMAL(12,2) NOT NULL,
|
||||
total_price DECIMAL(12,2) NOT NULL,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- =====================================================
|
||||
-- PAYMENTS
|
||||
-- =====================================================
|
||||
|
||||
CREATE TABLE payments (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
order_id UUID REFERENCES orders(id),
|
||||
user_id UUID REFERENCES users(id),
|
||||
provider TEXT NOT NULL,
|
||||
provider_ref TEXT,
|
||||
amount DECIMAL(12,2) NOT NULL,
|
||||
currency TEXT DEFAULT 'THB',
|
||||
status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'completed', 'failed', 'refunded')),
|
||||
payment_data JSONB,
|
||||
paid_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- =====================================================
|
||||
-- VENDOR PAYOUTS
|
||||
-- =====================================================
|
||||
|
||||
CREATE TABLE vendor_payouts (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
vendor_id UUID REFERENCES vendor_profiles(id),
|
||||
amount DECIMAL(12,2) NOT NULL,
|
||||
status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'processing', 'completed', 'failed')),
|
||||
bank_account TEXT,
|
||||
bank_name TEXT,
|
||||
notes TEXT,
|
||||
processed_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- =====================================================
|
||||
-- SHOPPING CARTS
|
||||
-- =====================================================
|
||||
|
||||
CREATE TABLE carts (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id UUID REFERENCES users(id) ON DELETE CASCADE UNIQUE,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE cart_items (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
cart_id UUID REFERENCES carts(id) ON DELETE CASCADE,
|
||||
product_id UUID REFERENCES products(id),
|
||||
variant_id UUID REFERENCES product_variants(id),
|
||||
quantity INT DEFAULT 1,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
UNIQUE(cart_id, product_id, variant_id)
|
||||
);
|
||||
|
||||
-- =====================================================
|
||||
-- INDEXES FOR PERFORMANCE
|
||||
-- =====================================================
|
||||
|
||||
-- Products
|
||||
CREATE INDEX idx_products_vendor ON products(vendor_id);
|
||||
CREATE INDEX idx_products_category ON products(category_id);
|
||||
CREATE INDEX idx_products_slug ON products(slug);
|
||||
CREATE INDEX idx_products_status ON products(status);
|
||||
CREATE INDEX idx_products_featured ON products(featured) WHERE featured = TRUE;
|
||||
CREATE INDEX idx_products_inventory ON products(inventory);
|
||||
|
||||
-- Orders
|
||||
CREATE INDEX idx_orders_user ON orders(user_id);
|
||||
CREATE INDEX idx_orders_vendor ON orders(vendor_id);
|
||||
CREATE INDEX idx_orders_number ON orders(order_number);
|
||||
CREATE INDEX idx_orders_status ON orders(status);
|
||||
CREATE INDEX idx_orders_payment_status ON orders(payment_status);
|
||||
CREATE INDEX idx_orders_created ON orders(created_at DESC);
|
||||
|
||||
-- Order Items
|
||||
CREATE INDEX idx_order_items_order ON order_items(order_id);
|
||||
CREATE INDEX idx_order_items_product ON order_items(product_id);
|
||||
CREATE INDEX idx_order_items_vendor ON order_items(vendor_id);
|
||||
|
||||
-- Reviews
|
||||
CREATE INDEX idx_reviews_product ON reviews(product_id);
|
||||
CREATE INDEX idx_reviews_user ON reviews(user_id);
|
||||
CREATE INDEX idx_reviews_product_rating ON reviews(product_id, rating);
|
||||
|
||||
-- Cart
|
||||
CREATE INDEX idx_cart_items_cart ON cart_items(cart_id);
|
||||
|
||||
-- Payments
|
||||
CREATE INDEX idx_payments_order ON payments(order_id);
|
||||
CREATE INDEX idx_payments_status ON payments(status);
|
||||
|
||||
-- Vendor
|
||||
CREATE INDEX idx_vendor_profiles_user ON vendor_profiles(user_id);
|
||||
CREATE INDEX idx_vendor_profiles_slug ON vendor_profiles(store_slug);
|
||||
|
||||
-- Categories
|
||||
CREATE INDEX idx_categories_parent ON categories(parent_id);
|
||||
|
||||
-- =====================================================
|
||||
-- ROW LEVEL SECURITY (RLS)
|
||||
-- =====================================================
|
||||
|
||||
-- Enable RLS on all tables
|
||||
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE vendor_profiles ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE categories ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE products ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE product_variants ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE reviews ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE order_items ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE payments ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE vendor_payouts ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE carts ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE cart_items ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Users: Users can read their own profile
|
||||
CREATE POLICY "Users can view own profile" ON users
|
||||
FOR SELECT USING (auth.uid() = id);
|
||||
|
||||
CREATE POLICY "Users can update own profile" ON users
|
||||
FOR UPDATE USING (auth.uid() = id);
|
||||
|
||||
-- Products: Anyone can view active products
|
||||
CREATE POLICY "Anyone can view active products" ON products
|
||||
FOR SELECT USING (status = 'active');
|
||||
|
||||
CREATE POLICY "Vendors can manage own products" ON products
|
||||
FOR ALL USING (
|
||||
vendor_id IN (
|
||||
SELECT id FROM vendor_profiles WHERE user_id = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
-- Categories: Anyone can view categories
|
||||
CREATE POLICY "Anyone can view categories" ON categories
|
||||
FOR SELECT USING (true);
|
||||
|
||||
-- Reviews: Anyone can view approved reviews
|
||||
CREATE POLICY "Anyone can view approved reviews" ON reviews
|
||||
FOR SELECT USING (status = 'approved');
|
||||
|
||||
-- Orders: Users can view their own orders
|
||||
CREATE POLICY "Users can view own orders" ON orders
|
||||
FOR SELECT USING (auth.uid() = user_id);
|
||||
|
||||
CREATE POLICY "Vendors can view their orders" ON orders
|
||||
FOR SELECT USING (
|
||||
vendor_id IN (
|
||||
SELECT id FROM vendor_profiles WHERE user_id = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
-- Carts: Users can manage their own cart
|
||||
CREATE POLICY "Users can manage own cart" ON carts
|
||||
FOR ALL USING (user_id = auth.uid());
|
||||
|
||||
CREATE POLICY "Users can manage own cart items" ON cart_items
|
||||
FOR ALL USING (
|
||||
cart_id IN (SELECT id FROM carts WHERE user_id = auth.uid())
|
||||
);
|
||||
|
||||
-- =====================================================
|
||||
-- FUNCTIONS & TRIGGERS
|
||||
-- =====================================================
|
||||
|
||||
-- Auto-update updated_at timestamp
|
||||
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ language 'plpgsql';
|
||||
|
||||
-- Apply to tables with updated_at
|
||||
CREATE TRIGGER update_users_updated_at
|
||||
BEFORE UPDATE ON users
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
CREATE TRIGGER update_products_updated_at
|
||||
BEFORE UPDATE ON products
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
CREATE TRIGGER update_orders_updated_at
|
||||
BEFORE UPDATE ON orders
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
-- Function to generate order number
|
||||
CREATE OR REPLACE FUNCTION generate_order_number()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.order_number = 'ORD-' || TO_CHAR(NOW(), 'YYYYMMDD') || '-' || UPPER(SUBSTRING(NEW.id::text, 1, 8));
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ language 'plpgsql';
|
||||
|
||||
CREATE TRIGGER generate_order_number_trigger
|
||||
BEFORE INSERT ON orders
|
||||
FOR EACH ROW EXECUTE FUNCTION generate_order_number();
|
||||
|
||||
-- Function to update product inventory on order
|
||||
CREATE OR REPLACE FUNCTION update_inventory_on_order()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
UPDATE products
|
||||
SET inventory = inventory - NEW.quantity
|
||||
WHERE id = NEW.product_id AND track_inventory = TRUE;
|
||||
ELSIF TG_OP = 'DELETE' THEN
|
||||
UPDATE products
|
||||
SET inventory = inventory + OLD.quantity
|
||||
WHERE id = OLD.product_id AND track_inventory = TRUE;
|
||||
END IF;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ language 'plpgsql';
|
||||
|
||||
CREATE TRIGGER update_inventory_trigger
|
||||
AFTER INSERT OR DELETE ON order_items
|
||||
FOR EACH ROW EXECUTE FUNCTION update_inventory_on_order();
|
||||
|
||||
-- Function to update vendor earnings on payment
|
||||
CREATE OR REPLACE FUNCTION update_vendor_earnings()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
IF NEW.status = 'completed' THEN
|
||||
UPDATE vendor_profiles
|
||||
SET total_earnings = total_earnings + NEW.amount
|
||||
WHERE vendor_id IN (
|
||||
SELECT vendor_id FROM orders WHERE id = NEW.order_id
|
||||
);
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ language 'plpgsql';
|
||||
|
||||
CREATE TRIGGER update_vendor_earnings_trigger
|
||||
AFTER UPDATE OF status ON payments
|
||||
FOR EACH ROW EXECUTE FUNCTION update_vendor_earnings();
|
||||
|
||||
-- =====================================================
|
||||
-- SEED DATA (Optional sample categories)
|
||||
-- =====================================================
|
||||
|
||||
-- Uncomment to add sample categories
|
||||
/*
|
||||
INSERT INTO categories (name, slug, description, sort_order) VALUES
|
||||
('Electronics', 'electronics', 'Electronic devices and accessories', 1),
|
||||
('Clothing', 'clothing', 'Fashion and apparel', 2),
|
||||
('Home & Garden', 'home-garden', 'Home improvement and garden', 3),
|
||||
('Sports', 'sports', 'Sports and outdoor equipment', 4),
|
||||
('Books', 'books', 'Books and media', 5);
|
||||
*/
|
||||
Reference in New Issue
Block a user