318 lines
12 KiB
SQL
318 lines
12 KiB
SQL
-- Dating App Database Schema
|
|
-- PostgreSQL 15+ Compatible
|
|
-- Run this script to create the database and all tables
|
|
|
|
-- ============================================================================
|
|
-- DATABASE CREATION
|
|
-- ============================================================================
|
|
|
|
-- Create the database user (if doesn't exist)
|
|
DO
|
|
$do$
|
|
BEGIN
|
|
CREATE ROLE dating_app_user WITH LOGIN PASSWORD 'Aa123456';
|
|
EXCEPTION WHEN DUPLICATE_OBJECT THEN
|
|
RAISE NOTICE 'Role dating_app_user already exists';
|
|
END
|
|
$do$;
|
|
|
|
-- Grant privileges to user before database creation
|
|
ALTER DEFAULT PRIVILEGES GRANT ALL ON TABLES TO dating_app_user;
|
|
ALTER DEFAULT PRIVILEGES GRANT ALL ON SEQUENCES TO dating_app_user;
|
|
|
|
-- Create the database owned by dating_app_user
|
|
CREATE DATABASE dating_app OWNER dating_app_user;
|
|
|
|
-- Grant connection privileges
|
|
GRANT CONNECT ON DATABASE dating_app TO dating_app_user;
|
|
GRANT USAGE ON SCHEMA public TO dating_app_user;
|
|
GRANT CREATE ON SCHEMA public TO dating_app_user;
|
|
|
|
-- ============================================================================
|
|
-- TABLE: USERS
|
|
-- ============================================================================
|
|
-- Stores user account information
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id SERIAL PRIMARY KEY,
|
|
email VARCHAR(255) UNIQUE NOT NULL,
|
|
hashed_password VARCHAR(255) NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
|
|
|
|
-- ============================================================================
|
|
-- TABLE: PROFILES
|
|
-- ============================================================================
|
|
-- Stores user profile information
|
|
CREATE TABLE IF NOT EXISTS profiles (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id INTEGER NOT NULL UNIQUE,
|
|
display_name VARCHAR(255) NOT NULL,
|
|
age INTEGER NOT NULL,
|
|
gender VARCHAR(50) NOT NULL,
|
|
location VARCHAR(255) NOT NULL,
|
|
bio TEXT,
|
|
interests JSONB DEFAULT '[]',
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_profiles_user_id ON profiles(user_id);
|
|
|
|
-- ============================================================================
|
|
-- TABLE: PHOTOS
|
|
-- ============================================================================
|
|
-- Stores user profile photos
|
|
CREATE TABLE IF NOT EXISTS photos (
|
|
id SERIAL PRIMARY KEY,
|
|
profile_id INTEGER NOT NULL,
|
|
file_path VARCHAR(255) NOT NULL,
|
|
display_order INTEGER NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (profile_id) REFERENCES profiles(id) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_photos_profile_id ON photos(profile_id);
|
|
|
|
-- ============================================================================
|
|
-- TABLE: LIKES
|
|
-- ============================================================================
|
|
-- Tracks which users like which other users
|
|
CREATE TABLE IF NOT EXISTS likes (
|
|
id SERIAL PRIMARY KEY,
|
|
liker_id INTEGER NOT NULL,
|
|
liked_id INTEGER NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(liker_id, liked_id),
|
|
FOREIGN KEY (liker_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (liked_id) REFERENCES users(id) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_likes_liker_id ON likes(liker_id);
|
|
CREATE INDEX IF NOT EXISTS idx_likes_liked_id ON likes(liked_id);
|
|
|
|
-- ============================================================================
|
|
-- TABLE: CONVERSATIONS
|
|
-- ============================================================================
|
|
-- Stores 1:1 chat conversations between users
|
|
CREATE TABLE IF NOT EXISTS conversations (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id_1 INTEGER NOT NULL,
|
|
user_id_2 INTEGER NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(user_id_1, user_id_2),
|
|
FOREIGN KEY (user_id_1) REFERENCES users(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (user_id_2) REFERENCES users(id) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_conversations_users ON conversations(user_id_1, user_id_2);
|
|
|
|
-- ============================================================================
|
|
-- TABLE: MESSAGES
|
|
-- ============================================================================
|
|
-- Stores individual messages in conversations
|
|
CREATE TABLE IF NOT EXISTS messages (
|
|
id SERIAL PRIMARY KEY,
|
|
conversation_id INTEGER NOT NULL,
|
|
sender_id INTEGER NOT NULL,
|
|
content TEXT NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (conversation_id) REFERENCES conversations(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (sender_id) REFERENCES users(id) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_messages_conversation_id ON messages(conversation_id);
|
|
CREATE INDEX IF NOT EXISTS idx_messages_created_at ON messages(created_at);
|
|
|
|
-- ============================================================================
|
|
-- SAMPLE DATA (Optional - Uncomment to insert test users)
|
|
-- ============================================================================
|
|
|
|
-- Test user 1: Alice (Password hash for 'password123')
|
|
INSERT INTO users (email, hashed_password)
|
|
VALUES ('alice@example.com', '$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewY5YmMxSUmGEJiq')
|
|
ON CONFLICT (email) DO NOTHING;
|
|
|
|
-- Test user 2: Bob
|
|
INSERT INTO users (email, hashed_password)
|
|
VALUES ('bob@example.com', '$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewY5YmMxSUmGEJiq')
|
|
ON CONFLICT (email) DO NOTHING;
|
|
|
|
-- Test user 3: Charlie
|
|
INSERT INTO users (email, hashed_password)
|
|
VALUES ('charlie@example.com', '$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewY5YmMxSUmGEJiq')
|
|
ON CONFLICT (email) DO NOTHING;
|
|
|
|
-- Test user 4: Diana
|
|
INSERT INTO users (email, hashed_password)
|
|
VALUES ('diana@example.com', '$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewY5YmMxSUmGEJiq')
|
|
ON CONFLICT (email) DO NOTHING;
|
|
|
|
-- ============================================================================
|
|
-- SAMPLE PROFILES (Optional - Uncomment to create test profiles)
|
|
-- ============================================================================
|
|
|
|
-- Alice's profile
|
|
INSERT INTO profiles (user_id, display_name, age, gender, location, bio, interests)
|
|
VALUES (
|
|
(SELECT id FROM users WHERE email = 'alice@example.com'),
|
|
'Alice',
|
|
28,
|
|
'Female',
|
|
'San Francisco, CA',
|
|
'Love hiking and coffee. Looking for genuine connection.',
|
|
'["hiking", "coffee", "reading", "travel"]'
|
|
)
|
|
ON CONFLICT (user_id) DO NOTHING;
|
|
|
|
-- Bob's profile
|
|
INSERT INTO profiles (user_id, display_name, age, gender, location, bio, interests)
|
|
VALUES (
|
|
(SELECT id FROM users WHERE email = 'bob@example.com'),
|
|
'Bob',
|
|
30,
|
|
'Male',
|
|
'San Francisco, CA',
|
|
'Software engineer who enjoys cooking and photography.',
|
|
'["cooking", "photography", "gaming", "travel"]'
|
|
)
|
|
ON CONFLICT (user_id) DO NOTHING;
|
|
|
|
-- Charlie's profile
|
|
INSERT INTO profiles (user_id, display_name, age, gender, location, bio, interests)
|
|
VALUES (
|
|
(SELECT id FROM users WHERE email = 'charlie@example.com'),
|
|
'Charlie',
|
|
27,
|
|
'Male',
|
|
'Los Angeles, CA',
|
|
'Designer and musician. Love live music and good conversation.',
|
|
'["music", "design", "art", "travel"]'
|
|
)
|
|
ON CONFLICT (user_id) DO NOTHING;
|
|
|
|
-- Diana's profile
|
|
INSERT INTO profiles (user_id, display_name, age, gender, location, bio, interests)
|
|
VALUES (
|
|
(SELECT id FROM users WHERE email = 'diana@example.com'),
|
|
'Diana',
|
|
26,
|
|
'Female',
|
|
'Los Angeles, CA',
|
|
'Yoga instructor and nature lover. Adventure seeker!',
|
|
'["yoga", "hiking", "nature", "travel"]'
|
|
)
|
|
ON CONFLICT (user_id) DO NOTHING;
|
|
|
|
-- ============================================================================
|
|
-- SAMPLE LIKES (Optional - Uncomment to create test likes)
|
|
-- ============================================================================
|
|
|
|
-- Alice likes Bob
|
|
INSERT INTO likes (liker_id, liked_id)
|
|
SELECT (SELECT id FROM users WHERE email = 'alice@example.com'),
|
|
(SELECT id FROM users WHERE email = 'bob@example.com')
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM likes
|
|
WHERE liker_id = (SELECT id FROM users WHERE email = 'alice@example.com')
|
|
AND liked_id = (SELECT id FROM users WHERE email = 'bob@example.com')
|
|
);
|
|
|
|
-- Bob likes Alice (MATCH!)
|
|
INSERT INTO likes (liker_id, liked_id)
|
|
SELECT (SELECT id FROM users WHERE email = 'bob@example.com'),
|
|
(SELECT id FROM users WHERE email = 'alice@example.com')
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM likes
|
|
WHERE liker_id = (SELECT id FROM users WHERE email = 'bob@example.com')
|
|
AND liked_id = (SELECT id FROM users WHERE email = 'alice@example.com')
|
|
);
|
|
|
|
-- Charlie likes Diana
|
|
INSERT INTO likes (liker_id, liked_id)
|
|
SELECT (SELECT id FROM users WHERE email = 'charlie@example.com'),
|
|
(SELECT id FROM users WHERE email = 'diana@example.com')
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM likes
|
|
WHERE liker_id = (SELECT id FROM users WHERE email = 'charlie@example.com')
|
|
AND liked_id = (SELECT id FROM users WHERE email = 'diana@example.com')
|
|
);
|
|
|
|
-- ============================================================================
|
|
-- SAMPLE CONVERSATION (Optional - Uncomment for test chat)
|
|
-- ============================================================================
|
|
|
|
-- Create conversation between Alice and Bob (they matched!)
|
|
INSERT INTO conversations (user_id_1, user_id_2)
|
|
SELECT (SELECT id FROM users WHERE email = 'alice@example.com'),
|
|
(SELECT id FROM users WHERE email = 'bob@example.com')
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM conversations
|
|
WHERE (user_id_1 = (SELECT id FROM users WHERE email = 'alice@example.com')
|
|
AND user_id_2 = (SELECT id FROM users WHERE email = 'bob@example.com'))
|
|
);
|
|
|
|
-- Sample messages in conversation
|
|
INSERT INTO messages (conversation_id, sender_id, content)
|
|
SELECT c.id,
|
|
(SELECT id FROM users WHERE email = 'alice@example.com'),
|
|
'Hi Bob! Love your photography page.'
|
|
FROM conversations c
|
|
WHERE c.user_id_1 = (SELECT id FROM users WHERE email = 'alice@example.com')
|
|
AND c.user_id_2 = (SELECT id FROM users WHERE email = 'bob@example.com')
|
|
AND NOT EXISTS (
|
|
SELECT 1 FROM messages WHERE conversation_id = c.id
|
|
);
|
|
|
|
INSERT INTO messages (conversation_id, sender_id, content)
|
|
SELECT c.id,
|
|
(SELECT id FROM users WHERE email = 'bob@example.com'),
|
|
'Thanks Alice! Would love to grab coffee sometime?'
|
|
FROM conversations c
|
|
WHERE c.user_id_1 = (SELECT id FROM users WHERE email = 'alice@example.com')
|
|
AND c.user_id_2 = (SELECT id FROM users WHERE email = 'bob@example.com')
|
|
AND (SELECT COUNT(*) FROM messages WHERE conversation_id = c.id) < 2;
|
|
|
|
-- ============================================================================
|
|
-- VERIFICATION QUERIES
|
|
-- ============================================================================
|
|
-- Run these queries to verify everything was created correctly:
|
|
-- SELECT COUNT(*) as user_count FROM users;
|
|
-- SELECT COUNT(*) as profile_count FROM profiles;
|
|
-- SELECT COUNT(*) as photo_count FROM photos;
|
|
-- SELECT COUNT(*) as like_count FROM likes;
|
|
-- SELECT COUNT(*) as conversation_count FROM conversations;
|
|
-- SELECT COUNT(*) as message_count FROM messages;
|
|
|
|
-- ============================================================================
|
|
-- NOTES
|
|
-- ============================================================================
|
|
--
|
|
-- Password hashes used in sample data:
|
|
-- - Hash: $2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewY5YmMxSUmGEJiq
|
|
-- - Password: 'password123'
|
|
--
|
|
-- To generate your own bcrypt hash, use Python:
|
|
-- from passlib.context import CryptContext
|
|
-- pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
|
-- hash = pwd_context.hash("your_password_here")
|
|
--
|
|
-- IMPORTANT BEFORE PRODUCTION:
|
|
-- 1. Change all password hashes to actual user passwords
|
|
-- 2. Update email addresses to real users
|
|
-- 3. Consider using proper user import/registration instead of direct inserts
|
|
-- 4. Remove sample data if not needed
|
|
--
|
|
-- DATABASE CONNECTION INFO:
|
|
-- Database: dating_app
|
|
-- Host: localhost (or your PostgreSQL host)
|
|
-- Port: 5432 (default)
|
|
-- User: postgres (or your database user)
|
|
-- Password: (set when installing PostgreSQL)
|
|
--
|
|
-- ============================================================================
|