Spaces:
Paused
Paused
File size: 12,981 Bytes
21d2ae0 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
-- ================================================
-- SUPABASE DATABASE SCHEMA FOR SSG WHATSAPP AI
-- ================================================
-- Enable UUID extension
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- ================================================
-- TABLE: categories
-- Purpose: Store business categories
-- ================================================
CREATE TABLE categories (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL UNIQUE,
description TEXT,
icon VARCHAR(50),
display_order INTEGER DEFAULT 0,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_categories_name ON categories(name);
CREATE INDEX idx_categories_active ON categories(is_active);
-- ================================================
-- TABLE: locations
-- Purpose: Store geographical locations
-- ================================================
CREATE TABLE locations (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL UNIQUE,
country VARCHAR(100),
region VARCHAR(100),
latitude DECIMAL(10, 8),
longitude DECIMAL(11, 8),
display_order INTEGER DEFAULT 0,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_locations_name ON locations(name);
CREATE INDEX idx_locations_country ON locations(country);
CREATE INDEX idx_locations_active ON locations(is_active);
-- ================================================
-- TABLE: companies
-- Purpose: Store company listings
-- ================================================
CREATE TABLE companies (
id SERIAL PRIMARY KEY,
company_name VARCHAR(255) NOT NULL,
description TEXT,
website_link VARCHAR(500),
advertising_tier VARCHAR(20) DEFAULT 'Free' CHECK (advertising_tier IN ('Premium', 'Enhanced', 'Logo', 'Free')),
category_id INTEGER NOT NULL REFERENCES categories(id) ON DELETE CASCADE,
location_id INTEGER NOT NULL REFERENCES locations(id) ON DELETE CASCADE,
keywords TEXT[],
contact_email VARCHAR(255),
contact_phone VARCHAR(50),
address TEXT,
logo_url VARCHAR(500),
is_active BOOLEAN DEFAULT TRUE,
featured BOOLEAN DEFAULT FALSE,
views_count INTEGER DEFAULT 0,
clicks_count INTEGER DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_companies_category ON companies(category_id);
CREATE INDEX idx_companies_location ON companies(location_id);
CREATE INDEX idx_companies_tier ON companies(advertising_tier);
CREATE INDEX idx_companies_active ON companies(is_active);
CREATE INDEX idx_companies_keywords ON companies USING GIN(keywords);
-- ================================================
-- TABLE: users
-- Purpose: Store user profiles and subscription info
-- ================================================
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
phone_number VARCHAR(20) UNIQUE NOT NULL,
full_name VARCHAR(255),
email VARCHAR(255),
role VARCHAR(50) DEFAULT 'boat_owner',
vessel_size VARCHAR(50),
vessel_name VARCHAR(255),
subscription_tier VARCHAR(20) DEFAULT 'free' CHECK (subscription_tier IN ('free', 'premium')),
subscription_start_date TIMESTAMP WITH TIME ZONE,
subscription_end_date TIMESTAMP WITH TIME ZONE,
queries_today INTEGER DEFAULT 0,
max_daily_queries INTEGER DEFAULT 10,
total_queries INTEGER DEFAULT 0,
onboarding_completed BOOLEAN DEFAULT FALSE,
preferences JSONB DEFAULT '{}',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
last_active_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Index for fast phone number lookups
CREATE INDEX idx_users_phone_number ON users(phone_number);
CREATE INDEX idx_users_subscription_tier ON users(subscription_tier);
CREATE INDEX idx_users_last_active ON users(last_active_at);
-- ================================================
-- TABLE: conversations
-- Purpose: Store message history for context
-- ================================================
CREATE TABLE conversations (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
role VARCHAR(20) NOT NULL CHECK (role IN ('user', 'assistant', 'system')),
content TEXT NOT NULL,
content_type VARCHAR(20) DEFAULT 'text' CHECK (content_type IN ('text', 'image', 'audio', 'video')),
media_url TEXT,
metadata JSONB DEFAULT '{}',
tokens_used INTEGER,
model_used VARCHAR(100),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Indexes for conversation retrieval
CREATE INDEX idx_conversations_user_id ON conversations(user_id);
CREATE INDEX idx_conversations_created_at ON conversations(created_at DESC);
CREATE INDEX idx_conversations_user_created ON conversations(user_id, created_at DESC);
-- ================================================
-- TABLE: search_queries
-- Purpose: Log searches for analytics
-- ================================================
CREATE TABLE search_queries (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
category_id VARCHAR(10),
category_name VARCHAR(255),
location_id VARCHAR(10),
location_name VARCHAR(255),
search_term TEXT,
results_count INTEGER DEFAULT 0,
top_result_company VARCHAR(255),
user_query TEXT,
extracted_intent JSONB,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Indexes for analytics queries
CREATE INDEX idx_search_queries_user_id ON search_queries(user_id);
CREATE INDEX idx_search_queries_category ON search_queries(category_name);
CREATE INDEX idx_search_queries_location ON search_queries(location_name);
CREATE INDEX idx_search_queries_created_at ON search_queries(created_at DESC);
-- ================================================
-- TABLE: api_logs
-- Purpose: Track API calls for debugging/monitoring
-- ================================================
CREATE TABLE api_logs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES users(id) ON DELETE SET NULL,
endpoint VARCHAR(255) NOT NULL,
method VARCHAR(10) NOT NULL,
request_params JSONB,
response_status INTEGER,
response_time_ms INTEGER,
error_message TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_api_logs_created_at ON api_logs(created_at DESC);
CREATE INDEX idx_api_logs_endpoint ON api_logs(endpoint);
-- ================================================
-- TABLE: user_feedback
-- Purpose: Store user feedback and ratings
-- ================================================
CREATE TABLE user_feedback (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
conversation_id UUID REFERENCES conversations(id) ON DELETE SET NULL,
rating INTEGER CHECK (rating >= 1 AND rating <= 5),
feedback_text TEXT,
feedback_type VARCHAR(50) CHECK (feedback_type IN ('helpful', 'not_helpful', 'incorrect', 'bug', 'feature_request', 'other')),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_user_feedback_user_id ON user_feedback(user_id);
CREATE INDEX idx_user_feedback_rating ON user_feedback(rating);
CREATE INDEX idx_user_feedback_created_at ON user_feedback(created_at DESC);
-- ================================================
-- TABLE: system_metrics
-- Purpose: Track system performance metrics
-- ================================================
CREATE TABLE system_metrics (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
metric_type VARCHAR(100) NOT NULL,
metric_value NUMERIC,
metadata JSONB DEFAULT '{}',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_system_metrics_type ON system_metrics(metric_type);
CREATE INDEX idx_system_metrics_created_at ON system_metrics(created_at DESC);
-- ================================================
-- TABLE: subscription_history
-- Purpose: Track subscription changes and payments
-- ================================================
CREATE TABLE subscription_history (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
previous_tier VARCHAR(20),
new_tier VARCHAR(20) NOT NULL,
change_reason VARCHAR(255),
amount_paid NUMERIC(10, 2),
payment_method VARCHAR(50),
payment_status VARCHAR(50),
valid_from TIMESTAMP WITH TIME ZONE NOT NULL,
valid_until TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_subscription_history_user_id ON subscription_history(user_id);
CREATE INDEX idx_subscription_history_created_at ON subscription_history(created_at DESC);
-- ================================================
-- FUNCTIONS & TRIGGERS
-- ================================================
-- Function to 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';
-- Trigger for users table
CREATE TRIGGER update_users_updated_at BEFORE UPDATE ON users
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
-- Function to reset daily query count
CREATE OR REPLACE FUNCTION reset_daily_queries()
RETURNS void AS $$
BEGIN
UPDATE users SET queries_today = 0;
END;
$$ language 'plpgsql';
-- Function to increment user queries
CREATE OR REPLACE FUNCTION increment_user_query(p_user_id UUID)
RETURNS void AS $$
BEGIN
UPDATE users
SET
queries_today = queries_today + 1,
total_queries = total_queries + 1,
last_active_at = NOW()
WHERE id = p_user_id;
END;
$$ language 'plpgsql';
-- Function to get conversation context (last N messages)
CREATE OR REPLACE FUNCTION get_conversation_context(
p_user_id UUID,
p_limit INTEGER DEFAULT 10
)
RETURNS TABLE (
role VARCHAR(20),
content TEXT,
created_at TIMESTAMP WITH TIME ZONE
) AS $$
BEGIN
RETURN QUERY
SELECT c.role, c.content, c.created_at
FROM conversations c
WHERE c.user_id = p_user_id
ORDER BY c.created_at DESC
LIMIT p_limit;
END;
$$ language 'plpgsql';
-- ================================================
-- ROW LEVEL SECURITY (RLS) POLICIES
-- ================================================
-- Enable RLS on all tables
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
ALTER TABLE conversations ENABLE ROW LEVEL SECURITY;
ALTER TABLE search_queries ENABLE ROW LEVEL SECURITY;
ALTER TABLE user_feedback ENABLE ROW LEVEL SECURITY;
ALTER TABLE subscription_history ENABLE ROW LEVEL SECURITY;
-- Policy: Users can only read their own data
CREATE POLICY "Users can view own data" ON users
FOR SELECT USING (auth.uid()::text = id::text);
-- Policy: Users can update their own profile
CREATE POLICY "Users can update own profile" ON users
FOR UPDATE USING (auth.uid()::text = id::text);
-- Policy: Users can view their own conversations
CREATE POLICY "Users can view own conversations" ON conversations
FOR SELECT USING (auth.uid()::text = user_id::text);
-- Policy: Users can view their own search queries
CREATE POLICY "Users can view own searches" ON search_queries
FOR SELECT USING (auth.uid()::text = user_id::text);
-- ================================================
-- COMMENTS FOR DOCUMENTATION
-- ================================================
COMMENT ON TABLE users IS 'Stores user profiles, subscription status, and usage metrics';
COMMENT ON TABLE conversations IS 'Message history for providing conversation context to AI';
COMMENT ON TABLE search_queries IS 'Logs all search queries for analytics and improvement';
COMMENT ON TABLE api_logs IS 'Tracks API performance and errors for monitoring';
COMMENT ON TABLE user_feedback IS 'Stores user feedback and ratings for quality improvement';
COMMENT ON TABLE system_metrics IS 'System-wide performance and usage metrics';
COMMENT ON TABLE subscription_history IS 'Audit trail of subscription changes and payments';
COMMENT ON COLUMN users.preferences IS 'JSON object storing user preferences like language, notification settings';
COMMENT ON COLUMN conversations.metadata IS 'JSON object storing additional message metadata like processing time, model version';
COMMENT ON COLUMN search_queries.extracted_intent IS 'JSON object containing the extracted category, location, and search term'; |