File size: 10,754 Bytes
851cd13 a758b0c 2860609 bcd0eb8 b7a94e7 2860609 bcd0eb8 2860609 bcd0eb8 62054ce bcd0eb8 62054ce 2dbf283 2860609 df9de2d 2860609 2dbf283 2860609 a758b0c 851cd13 a758b0c 2860609 df9de2d 2860609 851cd13 a758b0c 2860609 851cd13 a758b0c 851cd13 a758b0c 2860609 bcd0eb8 851cd13 a758b0c 851cd13 a758b0c bcd0eb8 2860609 bcd0eb8 2860609 2dbf283 2860609 df9de2d 2860609 2dbf283 2860609 2dbf283 2860609 df9de2d 2860609 2dbf283 2860609 2dbf283 2860609 df9de2d 2dbf283 2860609 2dbf283 2860609 2dbf283 2860609 2dbf283 762b66d | 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 | -- Create users table for WhatsApp AI Agent
CREATE TABLE IF NOT EXISTS users (
wa_id TEXT PRIMARY KEY,
name TEXT NOT NULL DEFAULT 'Unknown',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Create chat_sessions table
CREATE TABLE IF NOT EXISTS chat_sessions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
wa_id TEXT NOT NULL REFERENCES users(wa_id) ON DELETE CASCADE,
started_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
last_activity TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
ended BOOLEAN DEFAULT FALSE
);
-- Create messages table
CREATE TABLE IF NOT EXISTS messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
session_id UUID NOT NULL REFERENCES chat_sessions(id) ON DELETE CASCADE,
wa_id TEXT NOT NULL REFERENCES users(wa_id) ON DELETE CASCADE,
wamid TEXT NOT NULL, -- Meta message ID
role TEXT NOT NULL CHECK (role IN ('user', 'assistant')),
content TEXT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Create user_personas table for user preferences and context
CREATE TABLE IF NOT EXISTS user_personas (
wa_id TEXT PRIMARY KEY REFERENCES users(wa_id) ON DELETE CASCADE,
language TEXT,
tone TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Create user_intents table for session-specific property search intent
CREATE TABLE IF NOT EXISTS user_intents (
session_id UUID PRIMARY KEY REFERENCES chat_sessions(id) ON DELETE CASCADE,
wa_id TEXT NOT NULL REFERENCES users(wa_id) ON DELETE CASCADE,
location_preference TEXT,
budget INTEGER,
size_preference_sqm INTEGER,
must_have TEXT[],
transaction_type TEXT CHECK (transaction_type IN ('rent', 'buy')),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Migration: Add transaction_type column to existing user_intents table (if it doesn't exist)
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name = 'user_intents' AND column_name = 'transaction_type') THEN
ALTER TABLE user_intents ADD COLUMN transaction_type TEXT CHECK (transaction_type IN ('rent', 'buy'));
END IF;
END $$;
-- Migration: Add tags column to existing properties table (if it doesn't exist)
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name = 'properties' AND column_name = 'tags') THEN
ALTER TABLE properties ADD COLUMN tags TEXT[];
END IF;
END $$;
-- Create properties table for property listings
CREATE TABLE IF NOT EXISTS properties (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title TEXT NOT NULL,
description TEXT,
location TEXT NOT NULL,
city TEXT NOT NULL,
address TEXT,
size_sqm INTEGER,
price INTEGER,
price_type TEXT DEFAULT 'monthly',
listing_url TEXT,
images TEXT[],
features TEXT[],
tags TEXT[],
floorplan_pdf TEXT,
video_url TEXT,
is_active BOOLEAN DEFAULT TRUE,
is_featured BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Create indexes for better query performance
CREATE INDEX IF NOT EXISTS idx_users_created_at ON users(created_at DESC);
CREATE INDEX IF NOT EXISTS idx_users_updated_at ON users(updated_at DESC);
CREATE INDEX IF NOT EXISTS idx_chat_sessions_wa_id ON chat_sessions(wa_id);
CREATE INDEX IF NOT EXISTS idx_chat_sessions_last_activity ON chat_sessions(last_activity DESC);
CREATE INDEX IF NOT EXISTS idx_chat_sessions_ended ON chat_sessions(ended);
CREATE INDEX IF NOT EXISTS idx_messages_session_id ON messages(session_id);
CREATE INDEX IF NOT EXISTS idx_messages_wa_id ON messages(wa_id);
CREATE INDEX IF NOT EXISTS idx_messages_created_at ON messages(created_at DESC);
CREATE INDEX IF NOT EXISTS idx_messages_wamid ON messages(wamid);
CREATE INDEX IF NOT EXISTS idx_user_personas_wa_id ON user_personas(wa_id);
CREATE INDEX IF NOT EXISTS idx_user_personas_updated_at ON user_personas(updated_at DESC);
CREATE INDEX IF NOT EXISTS idx_user_intents_session_id ON user_intents(session_id);
CREATE INDEX IF NOT EXISTS idx_user_intents_wa_id ON user_intents(wa_id);
CREATE INDEX IF NOT EXISTS idx_user_intents_updated_at ON user_intents(updated_at DESC);
CREATE INDEX IF NOT EXISTS idx_properties_is_active ON properties(is_active);
CREATE INDEX IF NOT EXISTS idx_properties_city ON properties(city);
CREATE INDEX IF NOT EXISTS idx_properties_location ON properties(location);
CREATE INDEX IF NOT EXISTS idx_properties_address ON properties(address);
CREATE INDEX IF NOT EXISTS idx_properties_price ON properties(price);
CREATE INDEX IF NOT EXISTS idx_properties_size_sqm ON properties(size_sqm);
CREATE INDEX IF NOT EXISTS idx_properties_is_featured ON properties(is_featured);
CREATE INDEX IF NOT EXISTS idx_properties_created_at ON properties(created_at DESC);
-- Enable Row Level Security (RLS) - optional but recommended
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
ALTER TABLE chat_sessions ENABLE ROW LEVEL SECURITY;
ALTER TABLE messages ENABLE ROW LEVEL SECURITY;
ALTER TABLE user_personas ENABLE ROW LEVEL SECURITY;
ALTER TABLE user_intents ENABLE ROW LEVEL SECURITY;
ALTER TABLE properties ENABLE ROW LEVEL SECURITY;
-- Create policies to allow all operations (you can restrict this based on your needs)
CREATE POLICY "Allow all operations on users" ON users
FOR ALL USING (true);
CREATE POLICY "Allow all operations on chat_sessions" ON chat_sessions
FOR ALL USING (true);
CREATE POLICY "Allow all operations on messages" ON messages
FOR ALL USING (true);
CREATE POLICY "Allow all operations on user_personas" ON user_personas
FOR ALL USING (true);
CREATE POLICY "Allow all operations on user_intents" ON user_intents
FOR ALL USING (true);
CREATE POLICY "Allow all operations on properties" ON properties
FOR ALL USING (true);
-- Optional: Create a function to automatically update the updated_at timestamp
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ language 'plpgsql';
-- Create trigger to automatically update updated_at for users
CREATE TRIGGER update_users_updated_at
BEFORE UPDATE ON users
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
-- Create trigger to automatically update last_activity for chat_sessions
CREATE OR REPLACE FUNCTION update_last_activity_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.last_activity = NOW();
RETURN NEW;
END;
$$ language 'plpgsql';
CREATE TRIGGER update_chat_sessions_last_activity
BEFORE UPDATE ON chat_sessions
FOR EACH ROW
EXECUTE FUNCTION update_last_activity_column();
-- Create trigger to automatically update updated_at for user_personas
CREATE TRIGGER update_user_personas_updated_at
BEFORE UPDATE ON user_personas
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
-- Create trigger to automatically update updated_at for user_intents
CREATE TRIGGER update_user_intents_updated_at
BEFORE UPDATE ON user_intents
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
-- Create trigger to automatically update updated_at for properties
CREATE TRIGGER update_properties_updated_at
BEFORE UPDATE ON properties
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
-- Insert some sample properties for testing
INSERT INTO properties (title, description, location, city, address, size_sqm, price, price_type, listing_url, images, features, tags, is_active, is_featured) VALUES
(
'2-3 person office space in Edenvale',
'Modern office space perfect for small teams',
'Edenvale',
'Johannesburg',
'Greenstone Shopping Centre, 1 Emerald Boulevard, Modderfontein, 1609, South Africa',
40,
15000,
'lease',
'https://example.com/office-edenvale',
ARRAY['https://example.com/image1.jpg', 'https://example.com/image2.jpg'],
ARRAY['3 phase power', 'Parking', 'Kitchen', 'Meeting room'],
ARRAY['Security', 'Air conditioning', 'High-speed internet', 'Furnished', 'Near transport'],
TRUE,
TRUE
),
(
'Warehouse space in Sandton',
'Large warehouse space with loading dock',
'Sandton',
'Johannesburg',
'Sandton City Shopping Centre, 83 Rivonia Rd, Sandhurst, Sandton, 2196, South Africa',
200,
25000,
'lease',
'https://example.com/warehouse-sandton',
ARRAY['https://example.com/warehouse1.jpg'],
ARRAY['Loading dock', '3 phase power', 'Security', '24/7 access'],
ARRAY['CCTV', 'Alarm system', 'Fire suppression', 'Truck access', 'Industrial area'],
TRUE,
FALSE
),
(
'Small office in Cape Town CBD',
'Cozy office space in the heart of Cape Town',
'CBD',
'Cape Town',
'V&A Waterfront, Dock Rd, Cape Town, 8001, South Africa',
30,
12000,
'lease',
'https://example.com/office-cape-town',
ARRAY['https://example.com/cape-town1.jpg'],
ARRAY['WiFi', 'Reception', 'Lift'],
ARRAY['Security', 'Ocean view', 'Restaurant nearby', 'Public transport', 'Prestigious address'],
TRUE,
FALSE
);
-- Add some sample sale properties for testing
INSERT INTO properties (title, description, location, city, address, size_sqm, price, price_type, listing_url, images, features, is_active, is_featured) VALUES
(
'Office Building for Sale in Sandton',
'Modern office building with excellent investment potential',
'Sandton',
'Johannesburg',
'1 Sandton Drive, Sandton, 2196, South Africa',
500,
2500000,
'sale',
'https://example.com/office-building-sale',
ARRAY['https://example.com/building1.jpg', 'https://example.com/building2.jpg'],
ARRAY['Elevator', 'Parking', 'Security', 'Reception'],
TRUE,
TRUE
),
(
'Warehouse for Sale in Midrand',
'Industrial warehouse with great location for logistics',
'Midrand',
'Johannesburg',
'New Road, Midrand, 1685, South Africa',
1000,
3200000,
'sale',
'https://example.com/warehouse-sale',
ARRAY['https://example.com/warehouse-sale1.jpg'],
ARRAY['Loading dock', 'High ceiling', '3 phase power', 'Truck access'],
TRUE,
FALSE
),
(
'Commercial Property for Sale in Cape Town',
'Prime commercial property in Cape Town CBD',
'CBD',
'Cape Town',
'Long Street, Cape Town, 8001, South Africa',
300,
1800000,
'sale',
'https://example.com/commercial-sale-ct',
ARRAY['https://example.com/commercial1.jpg'],
ARRAY['Street frontage', 'High foot traffic', 'Parking'],
TRUE,
FALSE
); |