Add Docker packaging and migrate from better-sqlite3 to libsql

Docker self-hosting support:
- Dockerfile (multi-stage Alpine build with tini init)
- docker-compose.yml with named volume for SQLite persistence
- /api/health endpoint for container health checks
- Auto-migration on startup via drizzle-orm/libsql/migrator
- Graceful shutdown (SIGTERM stops scheduler, closes DB)
- Next.js standalone output mode for minimal image size

Database driver migration (better-sqlite3 → @libsql/client):
- Eliminates native C++ compilation, enabling Alpine Docker images
- All DB queries converted from sync to async across services and routes
- DATABASE_URL now uses libsql file: prefix format
- drizzle.config.ts dialect changed to turso for libsql support
- Initial migration files generated in drizzle/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-01 13:14:57 -05:00
co-authored by Claude Opus 4.6
parent 8f99a20a9c
commit 96213c3086
33 changed files with 3837 additions and 593 deletions
+4 -4
View File
@@ -27,7 +27,7 @@ export async function GET() {
weekStart.setDate(now.getDate() - (dayOfWeek === 0 ? 6 : dayOfWeek - 1));
weekStart.setHours(0, 0, 0, 0);
const [moviesThisMonth] = db
const [moviesThisMonth] = await db
.select({ count: sql<number>`count(*)` })
.from(userMovieWatches)
.where(
@@ -38,7 +38,7 @@ export async function GET() {
)
.all();
const [episodesThisWeek] = db
const [episodesThisWeek] = await db
.select({ count: sql<number>`count(*)` })
.from(userEpisodeWatches)
.where(
@@ -49,13 +49,13 @@ export async function GET() {
)
.all();
const [librarySize] = db
const [librarySize] = await db
.select({ count: sql<number>`count(*)` })
.from(userTitleStatus)
.where(eq(userTitleStatus.userId, userId))
.all();
const [completedCount] = db
const [completedCount] = await db
.select({ count: sql<number>`count(*)` })
.from(userTitleStatus)
.where(