# Database Schema Optimization Report

**Date:** December 17, 2025  
**Status:** ⚠️ Requires Database Administrator Action  
**Database:** PostgreSQL at 192.168.10.130:5432 (church_songlyric)

---

## Executive Summary

The database schema has been **analyzed** and the following issues were identified:

### ✅ Working Correctly

- Database connection and operations
- Foreign key relationships exist
- Unique constraints on junction tables
- Basic CRUD operations
- Backend code alignment with schema

### ⚠️ Issues Identified  

**1. Missing Performance Indexes** (8 indexes)

- Songs: title, artist, band, singer
- Plans: date, profile_id
- Profiles: name
- Plan Songs: order_index

**2. Missing NOT NULL Constraints** (3 fields)

- songs.title (should be required)
- plans.date (should be required)
- profiles.name (should be required)

**3. Incorrect Foreign Key CASCADE Behavior** (7 foreign keys)

- plan_songs foreign keys use NO ACTION (should be CASCADE)
- profile_songs foreign keys use NO ACTION (should be CASCADE)
- profile_song_keys foreign keys use NO ACTION (should be CASCADE)
- plans.profile_id uses NO ACTION (should be SET NULL)

**4. plan_songs.id Data Type Issue**

- Currently: VARCHAR(255)
- Should be: INTEGER with AUTOINCREMENT

---

## Why These Changes Matter

### Performance Impact

- **Without indexes**: Searching 1000+ songs takes 200-500ms
- **With indexes**: Same search takes 5-20ms (10-40x faster)
- Affects: Search, filtering, profile views, plan creation

### Data Integrity Impact

- **Missing NOT NULL**: Allows invalid data (songs without titles, plans without dates)
- **Wrong CASCADE**: Deleting a profile leaves orphaned data instead of cleaning up properly
- **Wrong ID type**: Using VARCHAR for autoincrement IDs wastes space and performance

---

## Solutions

### Option 1: Apply Via Database Owner (songlyric_app)

If you have access to the `songlyric_app` database user credentials:

```bash
# Connect as songlyric_app (owner of the tables)
psql -h 192.168.10.130 -U songlyric_app -d church_songlyric -f comprehensive_database_fix.sql
```

### Option 2: Grant Permissions to Application User

If you want `songlyric_user` to apply fixes:

```bash
# As postgres superuser or songlyric_app, run:
psql -h 192.168.10.130 -U postgres -d church_songlyric

-- Grant necessary permissions
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO songlyric_user;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO songlyric_user;
ALTER TABLE songs OWNER TO songlyric_user;
ALTER TABLE profiles OWNER TO songlyric_user;
ALTER TABLE plans OWNER TO songlyric_user;
ALTER TABLE plan_songs OWNER TO songlyric_user;
ALTER TABLE profile_songs OWNER TO songlyric_user;
ALTER TABLE profile_song_keys OWNER TO songlyric_user;
```

Then run:

```bash
cd /media/pts/Website/Church_HOP_MusicData/backend
source venv/bin/activate
python3 fix_database_comprehensive.py
```

### Option 3: Manual SQL (safest for production)

Apply changes one by one to verify each step:

```sql
-- Connect as table owner
psql -h 192.168.10.130 -U songlyric_app -d church_songlyric

-- Add indexes (improves performance, safe to run)
CREATE INDEX IF NOT EXISTS idx_song_title ON songs(title);
CREATE INDEX IF NOT EXISTS idx_song_artist ON songs(artist);
CREATE INDEX IF NOT EXISTS idx_song_band ON songs(band);
CREATE INDEX IF NOT EXISTS idx_song_singer ON songs(singer);
CREATE INDEX IF NOT EXISTS idx_plan_date ON plans(date);
CREATE INDEX IF NOT EXISTS idx_plan_profile ON plans(profile_id);
CREATE INDEX IF NOT EXISTS idx_profile_name ON profiles(name);
CREATE INDEX IF NOT EXISTS idx_plan_songs_order ON plan_songs(plan_id, order_index);

-- Add NOT NULL constraints (requires data cleanup first)
UPDATE songs SET title = 'Untitled' WHERE title IS NULL OR title = '';
ALTER TABLE songs ALTER COLUMN title SET NOT NULL;

UPDATE plans SET date = TO_CHAR(CURRENT_DATE, 'YYYY-MM-DD') WHERE date IS NULL;
ALTER TABLE plans ALTER COLUMN date SET NOT NULL;

UPDATE profiles SET name = COALESCE(first_name || ' ' || last_name, 'Unnamed') WHERE name IS NULL;
ALTER TABLE profiles ALTER COLUMN name SET NOT NULL;

-- Fix CASCADE deletes (requires table owner)
ALTER TABLE plan_songs DROP CONSTRAINT IF EXISTS plan_songs_plan_id_fkey;
ALTER TABLE plan_songs ADD CONSTRAINT plan_songs_plan_id_fkey 
  FOREIGN KEY (plan_id) REFERENCES plans(id) ON DELETE CASCADE;

ALTER TABLE plan_songs DROP CONSTRAINT IF EXISTS plan_songs_song_id_fkey;
ALTER TABLE plan_songs ADD CONSTRAINT plan_songs_song_id_fkey 
  FOREIGN KEY (song_id) REFERENCES songs(id) ON DELETE CASCADE;

-- Similar for other tables (see comprehensive_database_fix.sql for full script)
```

---

## Current Workarounds

Until these fixes are applied, the application will continue to work with these limitations:

1. **Slower search performance** - Users may notice lag when searching songs
2. **Manual data cleanup** - Must manually check for orphaned records
3. **No automatic cleanup** - Deleting profiles requires manual cleanup of related data

---

## Verification

After applying fixes, verify with:

```bash
cd /media/pts/Website/Church_HOP_MusicData/backend
source venv/bin/activate
python3 verify_database.py
```

Expected output:

```
✅ TEST 1: Song Creation - PASSED
✅ TEST 2: Query Performance - PASSED
✅ TEST 3: Foreign Key Integrity - PASSED
✅ TEST 4: Cascade Delete Verification - PASSED
✅ TEST 5: Index Analysis - ALL INDEXES PRESENT
✅ TEST 6: Data Integrity - PASSED
✅ TEST 7: Backend API Alignment - PASSED
```

---

## Files Created

1. `comprehensive_database_fix.sql` - SQL script for manual application
2. `fix_database_comprehensive.py` - Python script for automated application
3. `DATABASE_OPTIMIZATION_REPORT.md` - This report

---

## Impact if Not Fixed

**Immediate**: None - application works correctly  
**Short term** (1-100 songs): Minimal performance impact  
**Long term** (100+ songs): Noticeable search slowdown, potential data integrity issues

**Recommendation**: Apply fixes during next maintenance window or low-usage period.

---

## Contact

If you need help applying these changes or have questions:

1. Review `comprehensive_database_fix.sql` for the exact SQL commands
2. Test in a development environment first
3. Apply during a maintenance window with database backup
