dateme/schema.sql
2025-12-17 00:44:01 +02:00

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)
--
-- ============================================================================