Add covering indexes for recommendation rank ordering, title staleness scans,
and type+status filtering. Replace N+1 per-row staleness checks in cron jobs
with set-based batch queries. Wrap availability refresh in a transaction for
atomicity. Batch episode stills query and use existence check instead of
loading all rows for count.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Integrate TMDB credits data into the app: cast carousels on title detail
pages, person detail pages with biography and filmography, and person
search results in the command palette. Includes new persons/titleCast
DB tables, profile image caching, and a nightly credits refresh cron job.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add createLogger to tmdb client, image-cache, availability, and
webhooks services. Replace all silent .catch(() => {}) in metadata.ts
with debug-level error logging. Add progress and success logs in cron
job bodies, colors extraction, and webhook processing. Fix pre-existing
unused parameter lint warning in title-card.tsx.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace nested loop queries with batch fetches using inArray() across
discovery, tracking, metadata, settings, and system-health services.
The biggest win is getContinueWatchingFeed() going from ~375+ queries
to 5. Add a cached getSession() wrapper via React.cache() to deduplicate
auth lookups shared between layouts and pages. Parallelize independent
async operations in importTitle(), cacheImagesJob(), and the explore page.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rebuild the background jobs card as a sortable table showing each job's
schedule, last run time (live-updating via a new useTimeAgo hook), last
duration, and a manual trigger button backed by a new POST
/api/admin/jobs/trigger route. Extract StatusDot into a shared
component. Add cronToHuman() to display schedule patterns as readable
strings (e.g. "Every 6h", "Daily at 03:00"). Replace static
formatDistanceToNow calls throughout the health section with a
LiveTimeAgo component that refreshes every 30 seconds. Also swap a
handful of section icons for better visual matches across settings cards.
Checks current version against latest GitHub release every 6 hours via
cron job, caches result in appSettings, and surfaces updates through a
toast notification (once per browser session) and an animated badge in
the settings footer. Includes an admin toggle to enable/disable checks
(enabled by default). Also renames ServerSection to RegistrationSection
now that update checks are in their own card.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Make backup frequency (6h/12h/1d/7d), time, and day-of-week
configurable via settings, stored in appSettings key-value table
- Add rescheduleBackup() to dynamically update cron job at runtime
- Differentiate manual (sofa-manual-*) vs scheduled (sofa-scheduled-*)
backup filenames with source icons and tooltips in the backup list
- Pruning now only targets scheduled backups, leaving manual ones intact
- Merge backup-actions.ts into actions.ts, use shadcn DropdownMenu for
all selectors (consistent with dashboard stats cards)
- Fix hydration mismatch on relative backup timestamps
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Created a new `cronRuns` table to track job execution history, including job name, status, timestamps, and error messages.
- Updated job scheduling logic to log job status in the `cronRuns` table, capturing success and error states.
- Enhanced error handling to log detailed error messages in the database.
This commit establishes a foundation for monitoring scheduled jobs and their outcomes.
- Backup service using VACUUM INTO for WAL-safe atomic snapshots
- Server-side storage in DATA_DIR/backups with download/upload API routes
- Restore with integrity validation and automatic pre-restore safety backup
- Scheduled daily backups via cron with configurable retention
- Admin-only settings UI consolidated under single Server section
- Clean up account section sign-out button, fix switch sub-pixel rendering
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
drizzle-orm/bun-sqlite is fully synchronous — all queries return values
directly, not promises. Remove await from all db calls, drop async from
functions that no longer need it, simplify Promise.all patterns that
wrapped sync operations, and fix setSetting() which was missing .run()
(previously masked by await triggering execution via thenable).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Swap the hand-rolled Scheduler class (setInterval-based) for croner,
a battle-tested cron library with overlap protection and proper cron
expressions. Consolidate lib/jobs/ into a single lib/cron.ts and
remove the unused admin jobs API route.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>