--- title: Database Setup description: Configure and manage your PostgreSQL database --- ## Prerequisites - PostgreSQL 14 or higher - Database created - Database user with permissions ## Installation ### Using Docker ```bash docker run -d \ --name plunk-postgres \ -e POSTGRES_PASSWORD=your-password \ -e POSTGRES_DB=plunk \ -p 5432:5432 \ -v postgres_data:/var/lib/postgresql/data \ postgres:14 ``` ### Using Package Manager #### Ubuntu/Debian ```bash sudo apt update sudo apt install postgresql postgresql-contrib ``` #### macOS ```bash brew install postgresql@14 brew services start postgresql@14 ``` ## Database Creation ```sql CREATE DATABASE plunk; CREATE USER plunk WITH ENCRYPTED PASSWORD 'your-password'; GRANT ALL PRIVILEGES ON DATABASE plunk TO plunk; ``` ## Connection String ```bash DATABASE_URL="postgresql://plunk:your-password@localhost:5432/plunk" DIRECT_DATABASE_URL="postgresql://plunk:your-password@localhost:5432/plunk" ``` ## Running Migrations ### Development ```bash yarn workspace @plunk/db migrate:dev ``` ### Production ```bash yarn workspace @plunk/db migrate:prod ``` ## Database Schema Plunk uses Prisma ORM. The schema is located at: ``` packages/db/prisma/schema.prisma ``` ### Core Tables - **User**: User accounts - **Project**: Workspaces/tenants - **Membership**: User-project relationships - **Contact**: Email contacts - **Template**: Email templates - **Campaign**: Email campaigns - **Workflow**: Automated sequences - **Email**: Email tracking - **Event**: Custom events ## Indexes Important indexes for performance: ```sql -- Contact email index (unique per project) CREATE INDEX idx_contact_email ON "Contact" (email, "projectId"); -- Contact subscription index CREATE INDEX idx_contact_subscribed ON "Contact" (subscribed); -- Email tracking indexes CREATE INDEX idx_email_contact ON "Email" ("contactId"); CREATE INDEX idx_email_created ON "Email" ("createdAt"); -- Event indexes CREATE INDEX idx_event_contact ON "Event" ("contactId"); CREATE INDEX idx_event_name ON "Event" (event); ``` ## Performance Tuning ### For Large Datasets (1M+ contacts) ```sql -- Increase shared buffers (25% of RAM) ALTER SYSTEM SET shared_buffers = '2GB'; -- Increase work memory ALTER SYSTEM SET work_mem = '50MB'; -- Increase maintenance work memory ALTER SYSTEM SET maintenance_work_mem = '512MB'; -- Enable parallel queries ALTER SYSTEM SET max_parallel_workers_per_gather = 4; -- Reload configuration SELECT pg_reload_conf(); ``` ### Vacuum and Analyze Run regularly for optimal performance: ```bash # Manual vacuum vacuumdb --analyze --verbose plunk # Auto-vacuum (enabled by default) ``` ## Backup and Restore ### Backup ```bash pg_dump -U plunk -d plunk > backup-$(date +%Y%m%d).sql ``` ### Restore ```bash psql -U plunk -d plunk < backup.sql ``` ### Automated Backups Set up cron job: ```bash 0 2 * * * pg_dump -U plunk plunk > /backups/plunk-$(date +\%Y\%m\%d).sql ``` ## Monitoring ### Connection Count ```sql SELECT count(*) FROM pg_stat_activity; ``` ### Database Size ```sql SELECT pg_size_pretty(pg_database_size('plunk')); ``` ### Table Sizes ```sql SELECT schemaname, tablename, pg_size_pretty(pg_total_relation_size(schemaname || '.' || tablename)) AS size FROM pg_tables WHERE schemaname = 'public' ORDER BY pg_total_relation_size(schemaname || '.' || tablename) DESC; ``` ### Slow Queries ```sql SELECT query, calls, total_time, mean_time FROM pg_stat_statements ORDER BY mean_time DESC LIMIT 10; ``` ## Troubleshooting ### Connection refused Check PostgreSQL is running: ```bash sudo systemctl status postgresql ``` ### Authentication failed Verify credentials in connection string. ### Too many connections Increase max_connections: ```sql ALTER SYSTEM SET max_connections = 200; SELECT pg_reload_conf(); ``` ## Next Steps - [Configure email delivery](/self-hosting/email-setup) - [Deploy with Docker](/self-hosting/docker) - [Environment variables](/self-hosting/environment-variables)