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)
146 lines
7.6 KiB
SQL
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);
|