perf: Comprehensive efficiency optimizations

Implemented all 5 critical efficiency improvements to optimize
performance, reduce resource usage, and improve scalability.

## 1. Database Indexes
- Added indexes on sermon_notes foreign keys (user_id, sermon_id)
- Added composite index on sermons (archived, date DESC)
- Added indexes on frequently queried columns across all tables
- Impact: Faster queries as data grows, better JOIN performance

## 2. Eliminated N+1 Query Pattern
- Reduced 2 API calls to 1 on home page load
- Changed from separate active/archived fetches to single call
- Filter archived sermons client-side using computed properties
- Impact: 50% reduction in HTTP requests per page load

## 3. Scheduled Database Cleanup
- Extended existing plugin to clean expired sessions hourly
- Added cleanup for expired rate limits every hour
- Added cleanup for expired password reset codes every hour
- Sermon cleanup continues to run daily based on retention policy
- Impact: Prevents database table growth, better performance

## 4. Multi-stage Docker Build
- Implemented 3-stage build: deps -> builder -> runtime
- Separated build-time and runtime dependencies
- Added non-root user (nuxt:nodejs) for security
- Integrated dumb-init for proper signal handling
- Added health check endpoint at /api/health
- Impact: Smaller image size, faster deployments, better security

## 5. HTTP Caching
- Static assets: 1 year cache (immutable)
- Logos/images: 1 year cache (immutable)
- API routes: No cache (always fresh)
- HTML pages: 10 minute cache with revalidation
- Impact: Reduced bandwidth, faster page loads, less server load

All optimizations follow best practices and maintain backward
compatibility with existing functionality.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-06 08:01:45 -05:00
parent 0126b7e835
commit 287284c2fe
6 changed files with 180 additions and 37 deletions

View File

@@ -278,6 +278,11 @@ export function getDatabase() {
UNIQUE(user_id, sermon_id)
)
`)
// Create indexes for foreign keys to optimize queries
// SQLite doesn't automatically index foreign keys
db.exec(`CREATE INDEX IF NOT EXISTS idx_sermon_notes_user_id ON sermon_notes(user_id)`)
db.exec(`CREATE INDEX IF NOT EXISTS idx_sermon_notes_sermon_id ON sermon_notes(sermon_id)`)
db.exec(`
CREATE TABLE IF NOT EXISTS sessions (
@@ -317,6 +322,26 @@ export function getDatabase() {
)
`)
// Create additional performance indexes for frequently queried columns
// Sermons: date is used for sorting and filtering
db.exec(`CREATE INDEX IF NOT EXISTS idx_sermons_date ON sermons(date DESC)`)
db.exec(`CREATE INDEX IF NOT EXISTS idx_sermons_archived ON sermons(archived, date DESC)`)
// Users: email lookups for password reset
db.exec(`CREATE INDEX IF NOT EXISTS idx_users_email ON users(email)`)
// Sessions: token lookups for authentication
db.exec(`CREATE INDEX IF NOT EXISTS idx_sessions_token ON sessions(token)`)
db.exec(`CREATE INDEX IF NOT EXISTS idx_sessions_expires_at ON sessions(expires_at)`)
// Rate limits: identifier+endpoint lookups
db.exec(`CREATE INDEX IF NOT EXISTS idx_rate_limits_identifier_endpoint ON rate_limits(identifier, endpoint)`)
db.exec(`CREATE INDEX IF NOT EXISTS idx_rate_limits_reset_at ON rate_limits(reset_at)`)
// Password reset codes: email+code lookups
db.exec(`CREATE INDEX IF NOT EXISTS idx_password_reset_codes_email ON password_reset_codes(email)`)
db.exec(`CREATE INDEX IF NOT EXISTS idx_password_reset_codes_expires_at ON password_reset_codes(expires_at)`)
// Initialize AUTH_SECRET (generate if needed)
initializeAuthSecret()