Commit Graph
45 Commits
Author SHA1 Message Date
jake 271069cc0c Replace server actions with API routes and add SWR data-fetching hooks
- Convert discover, stats, status, and system-health server actions to
  proper API route handlers under `app/api/`; delete `lib/actions/explore.ts`,
  `lib/actions/settings.ts`, and `lib/actions/setup.ts`
- Add `use-discover`, `use-stats`, and `use-system-health` SWR hooks
  that call the new routes; update `command-palette`, `title-card`,
  `update-toast`, and `stats-display` to consume them
- Lift auth centering wrapper from individual login/register pages into
  `(auth)/layout.tsx`; switch both pages from `auth.api.getSession` to
  the cached `getSession()` helper
- Relocate setup wizard from `app/(auth)/setup/` to `app/setup/` (outside
  auth group) with dedicated `copy-button` and `refresh-button` client
  components
- Move `not-found.tsx` and `error.tsx` to app root so they apply
  globally instead of only within the pages route group
2026-03-08 19:09:21 -04:00
jake 0838e5fb74 Replace hand-written TMDB types with openapi-fetch + generated schema
- Add `openapi-fetch` dependency; generate `lib/tmdb/schema.d.ts` from
  TMDB's OpenAPI spec and delete `lib/tmdb/types.ts`
- Rewrite `lib/tmdb/client.ts` to use the typed fetch client against
  the generated schema, exporting `TmdbMovieDetails`, `TmdbTvDetails`,
  `TmdbVideo`, and `TmdbGenre` directly
- Fix null-safety across services (`credits`, `availability`,
  `metadata`, `person`, `webhooks`) and call sites (explore page,
  search route, explore actions) to handle optional fields produced
  by the stricter generated types
- Update `metadata.ts` and `metadata.test.ts` to import shared types
  from `@/lib/tmdb/client` instead of the removed `types.ts`
- Exclude `lib/tmdb/schema.d.ts` from Biome linting
2026-03-08 14:07:32 -04:00
jake ad8ec62317 Refactor tmdbImageUrl to accept semantic category instead of size string
- Change primary argument from TMDB size string (`w500`, `w1280`, etc.)
  to category name (`posters`, `backdrops`, `stills`, `logos`,
  `profiles`); optional size override remains as third argument
- Update all call sites across services, actions, pages, and route
  handlers to use the new category-based API
- Update image.test.ts to match the new signature and replace
  size-mapping test descriptions with category-name descriptions
2026-03-08 12:33:07 -04:00
jake 17fe19e85b Extract shared constants into lib/constants.ts
- Add `lib/constants.ts` exporting `DATA_DIR`, `DATABASE_URL`, `CACHE_DIR`,
  `BACKUP_DIR`, `AVATAR_DIR`, `TMDB_API_BASE_URL`, and `TMDB_IMAGE_BASE_URL`
- Replace inline `process.env` derivations in `db/client`, `backup`,
  `image-cache`, `system-health`, `tmdb/client`, `actions/settings`,
  and `api/avatars` with imports from the new module
2026-03-08 11:06:29 -04:00
jake 84c4356a9f Add user avatar upload to account settings and nav bar
- Add `uploadAvatarAction` and `removeAvatarAction` server actions;
  store files under `DATA_DIR/avatars/{userId}.{ext}` via Bun.write
- Add `GET /api/avatars/[userId]` route that scans the avatar dir with
  Bun.Glob and serves with immutable Cache-Control (cache-busted via
  query param)
- Refactor AccountSection with hover overlay, AnimatePresence fade,
  and file input; click avatar to upload (no image) or remove (has image)
- Replace NavBar user initial badge with Avatar + DropdownMenu showing
  name, email, settings link, and sign-out
- Thread `userEmail` and `userImage` props through AuthenticatedShell
  → NavBar and SettingsPage → AccountSection
2026-03-08 11:02:33 -04:00
jake 7ed172d675 Replace Jotai atoms with local state, add Suspense for PPR compatibility
- Delete filterable-row, backup-schedule, integrations, and system-health
  atom files; replace with useState/useTransition + server action calls
- Replace /api/explore/discover route with discoverByGenre server action;
  refactor FilterableTitleRow to call it directly via useTransition
- Wrap PagesLayout and AuthLayout children in Suspense to fix dynamic
  rendering errors during PPR static generation; remove StoreProvider
- Sequence ExplorePage session fetch before TMDB calls to prevent
  build-time requests during static generation
- Drop unnecessary "use client" directives from dashboard and person
  components that have no client-side hooks or browser API usage
- Improve Dockerfile: add bun install layer cache mount, copy
  .next/cache from builder, reorder ENV declarations
2026-03-07 16:00:19 -05:00
jake 8d8c49a7f0 Replace API route handlers with server actions across the app
- Delete 10 API routes (stats, system-health, update-check, jobs/trigger,
  backup/restore, person, titles import/resolve, registration/status) and
  move logic into server actions in lib/actions/settings.ts and
  lib/actions/watchlist.ts
- Refactor SystemHealthCards to accept initialData prop and hydrate Jotai
  atoms via useHydrateAtoms; replace useSystemHealth SWR hook with a
  lightweight useSystemHealthRefresh that calls getSystemHealthAction
- Convert BackupRestoreSection to use restoreBackupAction + useTransition
  instead of a raw fetch call
- Split SystemStatusCard, BackgroundJobsCard, and StorageCard into
  standalone components reading from systemHealthDataAtom
- Make SetupPage async with connection() to opt into dynamic rendering
2026-03-06 17:31:14 -05:00
jake 73b07f5ff6 Refactor auth session handling and server actions across app
- Overhaul `lib/auth/server.ts` and `lib/auth/session.ts`; update all API
  routes and server actions to use the revised session pattern
- Refactor server actions (settings, titles, watchlist, setup) for
  consistency with new auth layer
- Extract `SetupForm` into its own client component with `useActionState`,
  animated steps, and copyable env snippets
- Move landing page redirect logic into `app/page.tsx`; slim down
  `LandingPage` component
- Add `proxy.ts` for local dev proxying
- Minor cleanup to `NavBar`, `MobileTabBar`, and `TitleCard`
2026-03-06 17:05:49 -05:00
jake 49cea568a9 Add Sonarr and Radarr list integrations
- New `lists` service fetches Sonarr/Radarr library via their REST APIs
  and auto-imports matching titles from TMDB into the user's watchlist
- `app/api/lists/[token]/route.ts` webhook endpoint triggers a list sync
- Unified `IntegrationCard` component replaces `WebhookCard`, handling
  both webhook-style (Plex/Jellyfin/Emby) and list-style (Sonarr/Radarr)
  integrations with per-type config forms
- Schema migration adds `sonarr` and `radarr` to the integration type
  enum and a `listConnections` table for list-based integrations
- 212 tests added for the lists service covering import, deduplication,
  and error handling
2026-03-06 15:34:34 -05:00
jakeandClaude Opus 4.6 61908778c9 Ensure enrichment data is always available on title pages
Cast, availability, recommendations, colors, and trailers were missing
on first load because importTitle fire-and-forgot enrichment tasks.
getTitleWithChildren now calls ensureEnriched() to backfill any missing
data before rendering — works for new imports, old titles, and shells.

Also removes the awaitEnrichment option from importTitle (redundant now)
and optimizes DB queries: reuses already-read data for existence checks,
caches fetchSeasonsFromDb result, and skips re-reads when no backfill ran.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 20:18:38 -05:00
jakeandClaude Opus 4.6 be18531ea7 Add genre and content rating storage and display on title pages
Store TMDB genres in normalized tables (genres + titleGenres) and content
ratings as a column on titles. Both are fetched during import/refresh using
append_to_response for content ratings (no extra API calls). Displayed in
the title hero between type badge and year. Also fixes pre-existing type
error for profile_path on TmdbSearchResult.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 20:02:42 -05:00
jakeandClaude Opus 4.6 b565fb1023 Fix wrong TMDB field for person profile images in search
Person results from multi-search were using poster_path instead of
profile_path, causing missing profile images.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 19:18:27 -05:00
jakeandClaude Opus 4.6 cd5d773e98 Add actor/cast information with person pages and search support
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>
2026-03-05 14:36:39 -05:00
jake f3a425a5a9 Harden API input validation, error handling, and optimistic rollbacks
Add try/catch around `request.json()` in all POST routes to return a
400 instead of crashing on malformed bodies. Validate `type` as a
strict `"movie" | "tv"` enum in search, discover, import, and resolve
routes. Validate `tmdbId` as a positive integer. Add a
`SORT_BY_PATTERN` regex and page-range check (1–500) to the discover
route. Wrap all outbound TMDB calls in try/catch and return 502 on
failure so clients get a structured error rather than an unhandled
rejection.

Fix optimistic-update rollbacks in `use-title-actions`: capture
`prevStatus` and `prevWatches` before each mutation and restore both
atoms in the catch block for catchUp, handleMarkSeason,
handleUnmarkSeason, and single-episode toggle.

Fix a bug in `getContinueWatchingFeed` where the watchDateMap could
hold a stale date for episodes watched more than once; the map now
keeps the most-recent `watchedAt` per episode.
2026-03-05 13:16:08 -05:00
jake 107eb9a9e7 Overhaul system health section with job trigger controls and live timestamps
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.
2026-03-05 11:52:37 -05:00
jakeandClaude Opus 4.6 a5791b150f Add version update check feature for admin users
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>
2026-03-05 10:36:05 -05:00
jakeandClaude Opus 4.6 bafa45ec79 Add Emby webhook integration and remove unused username field
Add Emby as a third media server integration alongside Plex and Jellyfin.
Emby webhooks use a similar payload format (JSON with nested Item object
and ProviderIds). Also removes the mediaServerUsername field from all
webhook connections since it was never used for authentication — the
token-in-URL is the sole auth mechanism. This simplifies the connection
UX to a single "Connect" button.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 00:50:32 -05:00
jakeandClaude Opus 4.6 7a64ced5e0 Add system health dashboard and split settings into separate cards
Add admin-only system health API and UI showing database stats, TMDB
connection status, background job history, storage usage, and environment
variables (with redacted secrets). Split monolithic backup card into
three focused cards (backups, schedule, restore) with dedicated section
headers for Server, Security, and Backups.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 18:30:22 -05:00
jakeandClaude 83456c6a21 Migrate from Node.js built-ins to Bun-native APIs (#1)
Co-authored-by: Claude <noreply@anthropic.com>
2026-03-04 12:49:38 -05:00
jakeandClaude Opus 4.6 36afbcb8c0 Add sparkline charts to stats cards, use rolling periods, upgrade recharts to v3
Background sparkline area charts on Movies and Episodes cards show watch
activity distribution over the selected period. Periods now use rolling
windows (past 24h/7d/30d/365d) instead of calendar boundaries. Bumped
stats grid breakpoint to lg. Upgraded recharts 2.15.4 → 3.7.0 and fixed
chart.tsx types for v3 (TooltipContentProps, LegendPayload).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 21:13:43 -05:00
jakeandClaude Opus 4.6 1b7f64d327 Add dynamic period selector to dashboard stats cards
Movies and Episodes cards now have an interactive dropdown to switch
between Today, This Week, This Month, and This Year. Extracts reusable
getWatchCount helper in discovery service and adds /api/stats route.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 20:42:41 -05:00
jakeandClaude Opus 4.6 e59364e126 Add database backup/restore feature with admin UI
- 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>
2026-03-03 20:01:10 -05:00
jakeandClaude Opus 4.6 eb836eb2c7 Add LOG_LEVEL logger helper with createLogger() utility
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 19:25:44 -05:00
jakeandClaude Opus 4.6 d9b408128b Remove unnecessary await/async from sync bun:sqlite db calls
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>
2026-03-03 19:04:40 -05:00
jakeandClaude Opus 4.6 0f345c8cd6 Replace custom setInterval scheduler with croner
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>
2026-03-03 18:52:05 -05:00
jakeandClaude Opus 4.6 2fb329e0dc Switch from Node.js + pnpm to Bun runtime and package manager
Replace @libsql/client with bun:sqlite for zero-dependency SQLite access,
swap drizzle-orm/libsql adapter for drizzle-orm/bun-sqlite, and rewrite
Dockerfile to use oven/bun:1-alpine. The raw Database instance is no longer
exported via Proxy (native C++ methods lose `this` binding through
Reflect.get); instead, a closeDatabase() helper handles graceful shutdown
and the health check uses Drizzle's db.run() directly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 15:17:57 -05:00
jakeandClaude Opus 4.6 fb785645f8 Add optional OIDC authentication via Better Auth genericOAuth plugin
Support self-hosted OIDC providers (Authentik, Authelia, Keycloak, etc.)
configured entirely via environment variables. Uses Better Auth's
hooks.before to gate email/password sign-up at the endpoint level, and
disables emailAndPassword entirely when DISABLE_PASSWORD_LOGIN is set.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 13:39:15 -05:00
jake d5e985efd9 Add auth guards to search and discover API routes 2026-03-03 11:13:14 -05:00
jakeandClaude Opus 4.6 8487c3d7b1 Convert settings page to server component with server actions
Replace client-side data fetching with server-side queries and server
actions, eliminating 3 API route files. Extract page into granular
client components (account, integrations, server, webhook card) with
optimistic updates. Rename sections: Media Servers → Integrations,
Administration → Server. Add admin badge to account section.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 09:32:18 -05:00
jakeandClaude Opus 4.6 f16ccc2f3f Replace title mutation API routes with server actions
Move all title page mutations (status, rating, movie watch, episode
watch/unwatch, season watch/unwatch) from API route handlers to server
actions called directly from TitleInteractionProvider. Same optimistic
update pattern, no behavioral change — just eliminates the fetch()
round-trip through 5 API routes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:47:04 -05:00
jakeandClaude Opus 4.6 c1867a4f23 Convert dashboard and title pages to server components with granular Suspense
Replace fully client-side dashboard and title detail pages with server
component orchestrators that fetch data directly via service functions,
eliminating extra network round-trips through API routes. Each section
streams independently through its own Suspense boundary.

- Extract getUserStats(), getTitleWithChildren(), getRecommendationsForTitle()
  into service layer; update getNewAvailableFeed() to include tmdbId/voteAverage
- Split dashboard into server sections (stats, continue watching, library,
  recommendations) with client children for animations
- Split title page into server hero + client interaction provider with shared
  context for optimistic mutations across actions and seasons
- Add generateMetadata with OG tags, server-side TMDB ID resolution via
  redirect(), loading.tsx and not-found.tsx for both pages
- Add per-section skeleton components, fix ContinueWatchingSkeleton dimensions
- Remove 6 unused API routes (feed/*, titles/[id] GET, titles/[id]/recommendations)
- Remove components/stats-summary.tsx, add lib/types/title.ts for shared types

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:42:42 -05:00
jakeandClaude Opus 4.6 081f53beac Add instant navigation from search results via TMDB IDs in URL
Navigate instantly to /titles/tmdb-{id}-{type} and show a skeleton
while the new /api/titles/resolve endpoint handles the full import
(TMDB fetch, availability, recommendations, colors). Existing titles
resolve in ~5ms; the URL is replaced with the UUID once resolved.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:13:51 -05:00
jakeandClaude Opus 4.6 18385386d5 Add SQLite connectivity check to healthcheck endpoint
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:59:52 -05:00
jakeandClaude Opus 4.6 ee723e41d6 Add TMDB image caching pipeline and resolve image URLs server-side
Introduce a local disk cache for TMDB images served through a proxy API
route (/api/images/[...path]), eliminating direct client-side CDN
dependencies. Images are cached by category (posters, backdrops, stills,
logos) and served with immutable cache headers.

Move all tmdbImageUrl() calls from client components to API routes and
server components so clients receive ready-to-use URLs. This removes the
need to expose TMDB_IMAGE_BASE_URL and IMAGE_CACHE_ENABLED via
next.config.ts env block. The landing page is split into a server
wrapper (app/page.tsx) and client component (components/landing-page.tsx).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:10:17 -05:00
jakeandClaude Opus 4.6 cb0f366d44 Add dynamic color theming from poster art using node-vibrant
Extract dominant colors from movie/TV poster images server-side and use
them to create per-title atmospheric effects on detail pages — tinted
backdrop gradients, ambient glow orbs, and colored poster shadows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 12:29:13 -05:00
jakeandClaude Opus 4.6 67356e04c6 Add Plex and Jellyfin webhook integration for automatic watch tracking
When a user finishes watching on their media server, a webhook fires and
Sofa logs it as watched, triggering all existing auto-transitions. Each
user configures their connection in settings and gets a unique webhook URL.

- Add webhookConnections and webhookEventLog schema tables
- Add TMDB findByExternalId for resolving IMDB/TVDB IDs
- Add source parameter to tracking functions (plex/jellyfin)
- Add webhook processing service with payload parsers, title resolution,
  and deduplication
- Add public webhook receiver route (token-based auth)
- Add authenticated settings API routes for managing connections
- Add Media Servers section to settings UI with Plex/Jellyfin cards

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 16:24:39 -05:00
jakeandClaude Opus 4.6 e098180dda Replace search page with explore page for rich discovery experience
The command palette (⌘K) already handles direct title search. Replace the
redundant /search page with a new /explore page featuring trending titles,
popular movies/TV, and genre browsing powered by TMDB discovery endpoints.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 15:11:53 -05:00
jakeandClaude Opus 4.6 db3a6cc3d4 Add auto-close registration and admin settings page
First user to register automatically becomes admin and registration
closes. Admins can re-open registration from a new settings page.
Uses Better Auth admin plugin for role management and a new appSettings
table for the registration flag. Mobile tab bar now links to settings
instead of inline logout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 13:51:20 -05:00
jakeandClaude Opus 4.6 8fc4c110b6 Add setup page and graceful handling for missing TMDB API key
Without TMDB_API_KEY the app silently fails on search and import.
This adds a /setup page that guides admins through obtaining and
configuring the key, redirects unconfigured visitors from the
landing page, and returns clear error messages from the search API.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 13:30:31 -05:00
jakeandClaude Opus 4.6 96213c3086 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>
2026-03-01 13:14:57 -05:00
jakeandClaude Opus 4.6 0aac1d0d37 Add unwatch support for episodes/seasons, fix nested button hydration error
Toggle episode watched state, bulk unwatch seasons via new DELETE endpoints,
and replace outer <button> with <div role="button"> in season accordion to
avoid invalid nested button HTML that caused hydration errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:15:44 -05:00
jakeandClaude Opus 4.6 bebc4dc9fa Fix intermittent missing episodes for TV shows
TV episodes were missing when: (1) a title existed as a recommendation
"shell" with no episode data, (2) a prior refreshTvChildren() call
failed partway through, or (3) the title detail page was loaded before
episodes finished importing. importTitle() now re-fetches episodes for
existing TV titles with zero seasons, the GET endpoint hydrates shell
titles on access, and refreshTvChildren() handles per-season errors
gracefully instead of aborting entirely.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:10:04 -05:00
jakeandClaude Opus 4.6 b6aaad243f UX overhaul: motion animations, command palette, warm cinema theme
Add premium "Late Night Screening Room" experience with warm indigo/amber
palette, framer-motion spring animations, Cmd+K command palette with TMDB
search, keyboard shortcuts (G H, G S, ?, W, M, 1-5), sonner toasts with
optimistic updates, skeleton loading states, stats dashboard, search
autocomplete with filter tabs, cinematic backdrop with film grain, season
progress bars, and staggered card reveal animations throughout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 15:30:35 -05:00
jakeandClaude Opus 4.6 095b64ab42 Simplify auth, remove abstraction layers, add shadcn components
- Delete lib/api/errors.ts and lib/api/auth-guard.ts, inline
  NextResponse.json() error responses directly in route handlers
- Replace non-standard amber CSS variables with primary/primary-foreground
- Regenerate shadcn UI components with biome-ignore comments
- Add CLAUDE.md for repository guidance
- Update dependencies and pnpm lockfile

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 15:00:15 -05:00
jakeandClaude Opus 4.6 b02ff1cdc1 Implement full Couch Potato movie & TV tracking app
Add all 10 milestones: Drizzle ORM + SQLite database with WAL mode,
Better Auth email/password authentication, TMDB API integration for
search and metadata import, TV season/episode caching, user tracking
(watchlist/status/watches/ratings with auto-transitions), discovery
feeds (continue watching, library, recommendations), US streaming
availability via TMDB providers, background job scheduler with
instrumentation hook, and dark cinema-themed frontend with DM Serif
Display + DM Sans typography and amber accent design system.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 14:42:13 -05:00