273 lines
10 KiB
SQL
273 lines
10 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 all privileges on database to dating_app_user
|
|
GRANT ALL PRIVILEGES ON DATABASE dating_app TO dating_app_user;
|
|
|
|
-- Grant all privileges on all tables in public schema to dating_app_user
|
|
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO dating_app_user;
|
|
|
|
-- Grant all privileges on all sequences in public schema to dating_app_user
|
|
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO dating_app_user;
|
|
|
|
-- Grant all privileges on schema itself
|
|
GRANT ALL PRIVILEGES ON SCHEMA public TO dating_app_user;
|
|
|
|
-- Set default privileges for future tables
|
|
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO dating_app_user;
|
|
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO dating_app_user;
|
|
|
|
-- ============================================================================
|
|
-- TABLE: USERS
|
|
-- ============================================================================
|
|
-- Stores user account information
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id SERIAL PRIMARY KEY,
|
|
username VARCHAR(255) UNIQUE NOT NULL,
|
|
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);
|
|
CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
|
|
|
|
-- ============================================================================
|
|
-- 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,
|
|
read_at TIMESTAMP,
|
|
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 (username, email, hashed_password)
|
|
VALUES ('alice', 'alice@example.com', '$2b$12$u9bdKguk7ROP404cOx9FIuyKZoc3DK6el3y5muR8ayUnHG1bJewh2')
|
|
ON CONFLICT (email) DO NOTHING;
|
|
|
|
-- Test user 2: Bob
|
|
INSERT INTO users (username, email, hashed_password)
|
|
VALUES ('bob', 'bob@example.com', '$2b$12$u9bdKguk7ROP404cOx9FIuyKZoc3DK6el3y5muR8ayUnHG1bJewh2')
|
|
ON CONFLICT (email) DO NOTHING;
|
|
|
|
-- Test user 3: Charlie
|
|
INSERT INTO users (username, email, hashed_password)
|
|
VALUES ('charlie', 'charlie@example.com', '$2b$12$u9bdKguk7ROP404cOx9FIuyKZoc3DK6el3y5muR8ayUnHG1bJewh2')
|
|
ON CONFLICT (email) DO NOTHING;
|
|
|
|
-- Test user 4: Diana
|
|
INSERT INTO users (username, email, hashed_password)
|
|
VALUES ('diana', 'diana@example.com', '$2b$12$u9bdKguk7ROP404cOx9FIuyKZoc3DK6el3y5muR8ayUnHG1bJewh2')
|
|
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;
|
|
|
|
-- ============================================================================
|
|
-- 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$u9bdKguk7ROP404cOx9FIuyKZoc3DK6el3y5muR8ayUnHG1bJewh2
|
|
-- - 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)
|
|
--
|
|
-- ============================================================================
|
|
|
|
-- ============================================================================
|
|
-- MIGRATIONS (Run these if tables already exist and need updates)
|
|
-- ============================================================================
|
|
-- Uncomment and run the following lines to update existing database:
|
|
|
|
-- Add username column to users table if it doesn't already exist:
|
|
-- ALTER TABLE users ADD COLUMN username VARCHAR(255) UNIQUE;
|
|
|
|
-- Add index on username for faster lookups:
|
|
-- CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
|
|
|
|
-- Update dating_app_user permissions:
|
|
-- GRANT ALL PRIVILEGES ON DATABASE dating_app TO dating_app_user;
|
|
-- GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO dating_app_user;
|
|
-- GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO dating_app_user;
|
|
-- GRANT ALL PRIVILEGES ON SCHEMA public TO dating_app_user;
|