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:
@@ -200,17 +200,20 @@ const greeting = computed(() => {
|
||||
return `${timeGreeting}, ${firstName.value}!`
|
||||
})
|
||||
|
||||
// Fetch non-archived sermons for the most recent sermon
|
||||
const { data: activeSermons } = await useFetch('/api/sermons?includeArchived=false')
|
||||
|
||||
// Fetch archived sermons for the previous sermons dropdown
|
||||
const { data: archivedSermons } = await useFetch('/api/sermons?includeArchived=true')
|
||||
// Fetch all sermons in a single request (more efficient than two separate calls)
|
||||
const { data: allSermons } = await useFetch('/api/sermons?includeArchived=true')
|
||||
|
||||
const selectedSermonSlug = ref('')
|
||||
|
||||
// Filter active (non-archived) sermons client-side
|
||||
const activeSermons = computed(() => {
|
||||
if (!allSermons.value) return []
|
||||
return allSermons.value.filter((s: any) => s.archived !== 1)
|
||||
})
|
||||
|
||||
// Get today's sermon (if one exists for today's date)
|
||||
const todaysSermon = computed(() => {
|
||||
if (!activeSermons.value || activeSermons.value.length === 0) return null
|
||||
if (activeSermons.value.length === 0) return null
|
||||
|
||||
const today = new Date()
|
||||
today.setHours(0, 0, 0, 0)
|
||||
@@ -222,7 +225,7 @@ const todaysSermon = computed(() => {
|
||||
if (sermonDate.getTime() === today.getTime()) {
|
||||
return { ...s, displayDate: s.date }
|
||||
}
|
||||
|
||||
|
||||
// Check additional dates if they exist
|
||||
if (s.dates) {
|
||||
try {
|
||||
@@ -232,7 +235,7 @@ const todaysSermon = computed(() => {
|
||||
additionalDate.setHours(0, 0, 0, 0)
|
||||
return additionalDate.getTime() === today.getTime()
|
||||
})
|
||||
|
||||
|
||||
if (matchingDate) {
|
||||
return { ...s, displayDate: matchingDate }
|
||||
}
|
||||
@@ -241,13 +244,13 @@ const todaysSermon = computed(() => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
// Get upcoming sermons (future dates)
|
||||
const upcomingSermons = computed(() => {
|
||||
if (!activeSermons.value) return []
|
||||
if (activeSermons.value.length === 0) return []
|
||||
|
||||
const today = new Date()
|
||||
today.setHours(0, 0, 0, 0)
|
||||
@@ -289,8 +292,8 @@ const upcomingSermons = computed(() => {
|
||||
|
||||
// Get archived sermons only for the previous sermons dropdown
|
||||
const previousSermons = computed(() => {
|
||||
if (!archivedSermons.value) return []
|
||||
return archivedSermons.value.filter((s: any) => s.archived === 1)
|
||||
if (!allSermons.value) return []
|
||||
return allSermons.value.filter((s: any) => s.archived === 1)
|
||||
})
|
||||
|
||||
// Check if there are any current or upcoming sermons
|
||||
|
||||
Reference in New Issue
Block a user