freightdesk/supabase/migrations/005_saas_marketplace.sql
FreightDesk 69d814c439
Some checks are pending
FreightDesk CI/CD / Lint & Test (push) Waiting to run
FreightDesk CI/CD / Build Docker Image (push) Blocked by required conditions
FreightDesk CI/CD / Deploy to Coolify (push) Blocked by required conditions
[OWL] SaaS Marketplace: registration, marketplace, bidding, notifications
Database:
- Migration 005: SaaS marketplace tables (enhanced shippers, vehicles, loads, bids, negotiations, ratings, notifications, load_views)

Public Registration:
- GET/POST /register/shipper — self-registration with validation
- GET/POST /register/driver — self-registration with vehicle details
- Public landing page with tricolor design
- Auto-login after registration

Marketplace:
- GET /marketplace — browse loads with filters (from, to, type, sort)
- GET /marketplace/load/:id — load detail with bid info
- GET/POST /marketplace/post — post a load (shipper)
- GET /marketplace/notifications — notification center with real-time badge
- GET /marketplace/notifications/count — unread count API

Bidding System:
- POST /marketplace/bid — place a bid (driver)
- POST /marketplace/bid/:id/accept — accept bid (shipper, auto-rejects others)
- POST /marketplace/bid/:id/negotiate — counter-offer
- POST /marketplace/rate — submit rating/review
- Automatic notifications on bid/accept/reject

Views:
- Marketplace index with load cards and bid status
- Load detail with bid form (driver) or bid management (shipper)
- Post load form with full details
- Notification center with mark-read
- Portal header/footer partials for portal layout

Architecture:
- Added portalUser to res.locals
- Wired /marketplace route into server.js
- Landing page at / (redirects to dashboard if logged in)
2026-06-08 01:35:24 +00:00

146 lines
7.6 KiB
SQL

-- ============================================================
-- FreightDesk — Migration 005: SaaS Marketplace Foundation
-- Adds shipper/driver self-registration, load marketplace, bidding
-- ============================================================
-- ============================================================
-- 1. ENHANCE SHIPPERS TABLE (self-registration support)
-- ============================================================
ALTER TABLE shippers ADD COLUMN IF NOT EXISTS user_id UUID REFERENCES auth.users(id);
ALTER TABLE shipppers ADD COLUMN IF NOT EXISTS is_verified BOOLEAN DEFAULT false;
ALTER TABLE shipppers ADD COLUMN IF NOT EXISTS verification_token TEXT;
ALTER TABLE shipppers ADD COLUMN IF NOT EXISTS company_name TEXT;
ALTER TABLE shipppers ADD COLUMN IF NOT EXISTS gst_number TEXT;
ALTER TABLE shipppers ADD COLUMN IF NOT EXISTS pan_number TEXT;
ALTER TABLE shipppers ADD COLUMN IF NOT EXISTS address TEXT;
ALTER TABLE shippers ADD COLUMN IF NOT EXISTS pincode TEXT;
ALTER TABLE shippers ADD COLUMN IF NOT EXISTS rating DECIMAL(3,2) DEFAULT 0;
ALTER TABLE shippers ADD COLUMN IF NOT EXISTS total_shipments INTEGER DEFAULT 0;
-- ============================================================
-- 2. ENHANCE VEHICLES/DRIVERS TABLE (self-registration support)
-- ============================================================
ALTER TABLE vehicles ADD COLUMN IF NOT EXISTS user_id UUID REFERENCES auth.users(id);
ALTER TABLE vehicles ADD COLUMN IF NOT EXISTS driver_name TEXT;
ALTER TABLE vehicles ADD COLUMN IF NOT EXISTS driver_phone TEXT;
ALTER TABLE vehicles ADD COLUMN IF NOT EXISTS driver_license TEXT;
ALTER TABLE vehicles ADD COLUMN IF NOT EXISTS is_verified BOOLEAN DEFAULT false;
ALTER TABLE vehicles ADD COLUMN IF NOT EXISTS verification_token TEXT;
ALTER TABLE vehicles ADD COLUMN IF NOT EXISTS vehicle_type TEXT; -- 'mini_truck', 'truck', 'trailer', 'container'
ALTER TABLE vehicles ADD COLUMN IF NOT EXISTS capacity_tons DECIMAL(6,2);
ALTER TABLE vehicles ADD COLUMN IF NOT EXISTS body_type TEXT; -- 'open', 'closed', 'container', 'tanker'
ALTER TABLE vehicles ADD COLUMN IF NOT EXISTS current_lat DECIMAL(10,8);
ALTER TABLE vehicles ADD COLUMN IF NOT EXISTS current_lng DECIMAL(11,8);
ALTER TABLE vehicles ADD COLUMN IF NOT EXISTS current_city TEXT;
ALTER TABLE vehicles ADD COLUMN IF NOT EXISTS is_available BOOLEAN DEFAULT true;
ALTER TABLE vehicles ADD COLUMN IF NOT EXISTS rating DECIMAL(3,2) DEFAULT 0;
ALTER TABLE vehicles ADD COLUMN IF NOT EXISTS total_trips INTEGER DEFAULT 0;
-- ============================================================
-- 3. ENHANCE LOADS TABLE (marketplace support)
-- ============================================================
ALTER TABLE loads ADD COLUMN IF NOT EXISTS posted_by UUID REFERENCES auth.users(id);
ALTER TABLE loads ADD COLUMN IF NOT EXISTS load_type TEXT; -- 'ftl', 'ptl', 'parcel'
ALTER TABLE loads ADD COLUMN IF NOT EXISTS weight_kg INTEGER;
ALTER TABLE loads ADD COLUMN IF NOT EXISTS material_type TEXT;
ALTER TABLE loads ADD COLUMN IF NOT EXISTS packaging_type TEXT;
ALTER TABLE loads ADD COLUMN IF NOT EXISTS pickup_address TEXT;
ALTER TABLE loads ADD COLUMN IF NOT EXISTS pickup_pincode TEXT;
ALTER TABLE loads ADD COLUMN IF NOT EXISTS pickup_lat DECIMAL(10,8);
ALTER TABLE loads ADD COLUMN IF NOT EXISTS pickup_lng DECIMAL(11,8);
ALTER TABLE loads ADD COLUMN IF NOT EXISTS delivery_address TEXT;
ALTER TABLE loads ADD COLUMN IF NOT EXISTS delivery_pincode TEXT;
ALTER TABLE loads ADD COLUMN IF NOT EXISTS delivery_lat DECIMAL(10,8);
ALTER TABLE loads ADD COLUMN IF NOT EXISTS delivery_lng DECIMAL(11,8);
ALTER TABLE loads ADD COLUMN IF NOT EXISTS pickup_date DATE;
ALTER TABLE loads ADD COLUMN IF NOT EXISTS delivery_date DATE;
ALTER TABLE loads ADD COLUMN IF NOT EXISTS budget_min INTEGER;
ALTER TABLE loads ADD COLUMN IF NOT EXISTS budget_max INTEGER;
ALTER TABLE loads ADD COLUMN IF NOT EXISTS is_open BOOLEAN DEFAULT true; -- open for bidding
ALTER TABLE loads ADD COLUMN IF NOT EXISTS expires_at TIMESTAMP WITH TIME ZONE;
ALTER TABLE loads ADD COLUMN IF NOT EXISTS accepted_bid_id UUID;
ALTER TABLE loads ADD COLUMN IF NOT EXISTS views INTEGER DEFAULT 0;
-- ============================================================
-- 4. BIDS TABLE
-- ============================================================
CREATE TABLE IF NOT EXISTS bids (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
load_id UUID NOT NULL REFERENCES loads(id) ON DELETE CASCADE,
driver_id UUID NOT NULL REFERENCES vehicles(id),
shipper_id UUID REFERENCES shippers(id),
amount INTEGER NOT NULL,
message TEXT,
status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'accepted', 'rejected', 'withdrawn', 'expired')),
valid_until TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(load_id, driver_id) -- one bid per driver per load
);
CREATE INDEX IF NOT EXISTS idx_bids_load ON bids(load_id);
CREATE INDEX IF NOT EXISTS idx_bids_driver ON bids(driver_id);
CREATE INDEX IF NOT EXISTS idx_bids_status ON bids(status);
-- ============================================================
-- 5. NEGOTIATION / COUNTER-OFFERS TABLE
-- ============================================================
CREATE TABLE IF NOT EXISTS negotiations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
bid_id UUID NOT NULL REFERENCES bids(id) ON DELETE CASCADE,
proposed_by UUID NOT NULL, -- user_id who proposed
proposed_amount INTEGER NOT NULL,
message TEXT,
status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'accepted', 'rejected', 'countered')),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_negotiations_bid ON negotiations(bid_id);
-- ============================================================
-- 6. RATINGS & REVIEWS TABLE
-- ============================================================
CREATE TABLE IF NOT EXISTS ratings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
from_user_id UUID NOT NULL,
to_user_id UUID NOT NULL,
load_id UUID REFERENCES loads(id),
driver_id UUID REFERENCES vehicles(id),
shipper_id UUID REFERENCES shippers(id),
rating INTEGER NOT NULL CHECK (rating >= 1 AND rating <= 5),
review TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_ratings_to_user ON ratings(to_user_id);
CREATE INDEX IF NOT EXISTS idx_ratings_driver ON ratings(driver_id);
CREATE INDEX IF NOT EXISTS idx_ratings_shipper ON ratings(shipper_id);
-- ============================================================
-- 7. NOTIFICATIONS TABLE
-- ============================================================
CREATE TABLE IF NOT EXISTS notifications (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
type TEXT NOT NULL CHECK (type IN ('bid_received', 'bid_accepted', 'bid_rejected', 'negotiation', 'load_assigned', 'delivery_update', 'payment', 'system')),
title TEXT NOT NULL,
message TEXT,
data JSONB DEFAULT '{}',
is_read BOOLEAN DEFAULT false,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_notifications_user ON notifications(user_id);
CREATE INDEX IF NOT EXISTS idx_notifications_unread ON notifications(user_id, is_read) WHERE is_read = false;
-- ============================================================
-- 8. LOAD VIEWS TABLE (analytics)
-- ============================================================
CREATE TABLE IF NOT EXISTS load_views (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
load_id UUID NOT NULL REFERENCES loads(id) ON DELETE CASCADE,
viewer_id UUID,
viewed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_load_views_load ON load_views(load_id);