93cc0b6eb06d36f7b6dce7e77e93d28212923179
Three compounding issues caused the 4+ second load: 1. getAllRatings() ran sequentially after the first Promise.all group, adding it unnecessarily to the critical path. Now runs in parallel with listBooks/getVotedSlugs/getSavedSlugs (all 4 concurrent). 2. discovery_votes was fetched twice on every page load — once inside getBooksForDiscovery (via getVotedSlugs) and again by getVotedBooks. Fixed by caching getVotedSlugs results with a 30s TTL so the second call hits cache instead of PocketBase. 3. getVotedSlugs and getSavedSlugs were always uncached, hitting PocketBase on every navigation. Added short-TTL per-user Valkey cache entries (voted: 30s, saved: 60s). Cache is invalidated immediately after each write (upsertDiscoveryVote, clearDiscoveryVotes, undoDiscoveryVote, saveBook) so stale data is never served.
LibNovel
Self-hosted audiobook platform. Go backend + SvelteKit UI + MinIO/PocketBase/Meilisearch.
Requirements
- Docker + Docker Compose
- just
- Doppler CLI
Setup
doppler login
doppler setup # project=libnovel, config=prd
Usage
just up # start everything
just down # stop
just logs # tail all logs
just log backend # tail one service
just build # rebuild images
just restart # down + up
just secrets # view/edit secrets
Secrets
Managed via Doppler (project=libnovel, config=prd). No .env files.
To add or update a secret:
doppler secrets set MY_SECRET=value
Description