dateme/schema.sql
2025-12-17 06:20:46 +02:00

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;