From a3ba192fbdeec5812707729db29ae089d30af28c Mon Sep 17 00:00:00 2001 From: kikootwo Date: Wed, 28 Jan 2026 11:41:24 -0500 Subject: [PATCH] Initial commit --- .dockerignore | 66 + .env.example | 25 + .gitattributes | 5 + .github/workflows/build-unified-image.yml | 87 + .gitignore | 51 + AGENTS.md | 357 + CLAUDE.md | 357 + CONTRIBUTING.md | 321 + Dockerfile | 112 + LICENSE | 21 + PlexMediaServerAPIDocs.json | 29848 ++++++++++++++++ README.md | 339 + docker-compose.debug.yml | 104 + docker-compose.local.yml | 78 + docker-entrypoint.sh | 32 + docker/unified/app-start.sh | 22 + docker/unified/entrypoint.sh | 363 + docker/unified/supervisord.conf | 48 + dockerfile.unified | 108 + documentation/README.md | 82 + documentation/TABLEOFCONTENTS.md | 89 + documentation/admin-dashboard.md | 81 + documentation/archive/BOOKDATE_COMPLETE.md | 293 + .../archive/BOOKDATE_DEPLOYMENT_GUIDE.md | 536 + .../archive/BOOKDATE_IMPLEMENTATION_STATUS.md | 672 + documentation/archive/DOCKER.md | 367 + documentation/archive/README.unified.md | 243 + documentation/backend/database.md | 123 + documentation/backend/middleware.md | 34 + documentation/backend/services/auth.md | 174 + documentation/backend/services/config.md | 117 + documentation/backend/services/environment.md | 199 + documentation/backend/services/jobs.md | 172 + documentation/backend/services/scheduler.md | 170 + documentation/deployment/docker.md | 132 + documentation/deployment/unified.md | 698 + .../audiobookshelf-implementation-guide.md | 2115 ++ .../features/audiobookshelf-integration.md | 1184 + .../bookdate-implementation-prompt.md | 1667 + documentation/features/bookdate-prd.md | 696 + documentation/features/bookdate.md | 399 + documentation/features/chapter-merging.md | 421 + documentation/frontend/components.md | 198 + documentation/frontend/pages/login.md | 130 + documentation/frontend/routing-auth.md | 138 + documentation/integrations/audible.md | 146 + documentation/integrations/plex.md | 237 + documentation/phase3/README.md | 49 + documentation/phase3/file-organization.md | 124 + documentation/phase3/prowlarr.md | 91 + documentation/phase3/qbittorrent.md | 91 + documentation/phase3/ranking-algorithm.md | 53 + documentation/settings-pages.md | 177 + documentation/setup-wizard.md | 170 + eslint.config.mjs | 18 + next.config.ts | 44 + package-lock.json | 9560 +++++ package.json | 60 + postcss.config.mjs | 7 + .../migration.sql | 21 + .../migration.sql | 14 + .../migration.sql | 16 + .../migration.sql | 2 + prisma/schema.prisma | 397 + public/RMAB_1024x1024.png | Bin 0 -> 1037778 bytes public/file.svg | 1 + public/globe.svg | 1 + public/manifest.json | 22 + public/next.svg | 1 + public/rmab_32x32.png | Bin 0 -> 1635 bytes public/rmab_icon.ico | Bin 0 -> 15406 bytes public/vercel.svg | 1 + public/window.svg | 1 + rmab_icon.ico | Bin 0 -> 4286 bytes scripts/check-backend-mode.ts | 44 + scripts/setup-abs-config.ts | 60 + .../admin/components/ActiveDownloadsTable.tsx | 147 + src/app/admin/components/MetricCard.tsx | 57 + .../admin/components/RecentRequestsTable.tsx | 154 + src/app/admin/jobs/page.tsx | 653 + src/app/admin/logs/page.tsx | 416 + src/app/admin/page.tsx | 300 + src/app/admin/settings/page.tsx | 2309 ++ src/app/admin/users/page.tsx | 493 + src/app/api/admin/backend-mode/route.ts | 69 + src/app/api/admin/bookdate/toggle/route.ts | 44 + src/app/api/admin/downloads/active/route.ts | 76 + src/app/api/admin/job-status/[id]/route.ts | 70 + src/app/api/admin/jobs/[id]/route.ts | 99 + src/app/api/admin/jobs/[id]/trigger/route.ts | 55 + src/app/api/admin/jobs/route.ts | 86 + src/app/api/admin/logs/route.ts | 105 + src/app/api/admin/metrics/route.ts | 120 + src/app/api/admin/plex/scan/route.ts | 41 + src/app/api/admin/requests/recent/route.ts | 59 + .../audiobookshelf/libraries/route.ts | 66 + .../admin/settings/audiobookshelf/route.ts | 51 + .../admin/settings/change-password/route.ts | 135 + .../admin/settings/download-client/route.ts | 77 + src/app/api/admin/settings/oidc/route.ts | 51 + src/app/api/admin/settings/paths/route.ts | 74 + .../admin/settings/plex/libraries/route.ts | 66 + src/app/api/admin/settings/plex/route.ts | 93 + .../admin/settings/prowlarr/indexers/route.ts | 126 + src/app/api/admin/settings/prowlarr/route.ts | 57 + .../api/admin/settings/registration/route.ts | 37 + src/app/api/admin/settings/route.ts | 87 + .../settings/test-download-client/route.ts | 71 + src/app/api/admin/settings/test-plex/route.ts | 84 + .../api/admin/settings/test-prowlarr/route.ts | 73 + src/app/api/admin/users/[id]/approve/route.ts | 75 + src/app/api/admin/users/[id]/route.ts | 82 + src/app/api/admin/users/pending/route.ts | 40 + src/app/api/admin/users/route.ts | 47 + src/app/api/audiobooks/[asin]/route.ts | 57 + src/app/api/audiobooks/covers/route.ts | 76 + src/app/api/audiobooks/new-releases/route.ts | 140 + src/app/api/audiobooks/popular/route.ts | 140 + src/app/api/audiobooks/search/route.ts | 59 + src/app/api/auth/admin/login/route.ts | 114 + src/app/api/auth/is-local-admin/route.ts | 30 + src/app/api/auth/local/login/route.ts | 59 + src/app/api/auth/logout/route.ts | 23 + src/app/api/auth/me/route.ts | 69 + src/app/api/auth/oidc/callback/route.ts | 140 + src/app/api/auth/oidc/login/route.ts | 35 + src/app/api/auth/plex/callback/route.ts | 364 + src/app/api/auth/plex/home-users/route.ts | 44 + src/app/api/auth/plex/login/route.ts | 45 + src/app/api/auth/plex/switch-profile/route.ts | 180 + src/app/api/auth/providers/route.ts | 49 + src/app/api/auth/refresh/route.ts | 80 + src/app/api/auth/register/route.ts | 75 + src/app/api/bookdate/config/route.ts | 183 + src/app/api/bookdate/generate/route.ts | 179 + src/app/api/bookdate/preferences/route.ts | 125 + src/app/api/bookdate/recommendations/route.ts | 196 + src/app/api/bookdate/swipe/route.ts | 137 + src/app/api/bookdate/swipes/route.ts | 37 + src/app/api/bookdate/test-connection/route.ts | 260 + src/app/api/bookdate/undo/route.ts | 90 + .../api/cache/thumbnails/[filename]/route.ts | 69 + src/app/api/config/[category]/route.ts | 35 + src/app/api/config/route.ts | 81 + src/app/api/health/route.ts | 31 + src/app/api/init/route.ts | 39 + .../requests/[id]/interactive-search/route.ts | 99 + .../api/requests/[id]/manual-search/route.ts | 102 + src/app/api/requests/[id]/route.ts | 325 + .../api/requests/[id]/select-torrent/route.ts | 106 + src/app/api/requests/route.ts | 229 + src/app/api/setup/complete/route.ts | 435 + src/app/api/setup/status/route.ts | 32 + src/app/api/setup/test-abs/route.ts | 82 + .../api/setup/test-download-client/route.ts | 48 + src/app/api/setup/test-oidc/route.ts | 93 + src/app/api/setup/test-paths/route.ts | 93 + src/app/api/setup/test-plex/route.ts | 61 + src/app/api/setup/test-prowlarr/route.ts | 50 + src/app/auth/select-profile/page.tsx | 337 + src/app/bookdate/page.tsx | 381 + src/app/favicon.ico | Bin 0 -> 25931 bytes src/app/globals.css | 41 + src/app/layout.tsx | 58 + src/app/login/page.tsx | 908 + src/app/page.tsx | 188 + src/app/profile/page.tsx | 367 + src/app/requests/page.tsx | 217 + src/app/search/page.tsx | 165 + src/app/setup/components/WizardLayout.tsx | 163 + src/app/setup/initializing/page.tsx | 402 + src/app/setup/page.tsx | 545 + src/app/setup/steps/AdminAccountStep.tsx | 167 + src/app/setup/steps/AudiobookshelfStep.tsx | 264 + src/app/setup/steps/AuthMethodStep.tsx | 144 + src/app/setup/steps/BackendSelectionStep.tsx | 130 + src/app/setup/steps/BookDateStep.tsx | 220 + src/app/setup/steps/DownloadClientStep.tsx | 280 + src/app/setup/steps/FinalizeStep.tsx | 412 + src/app/setup/steps/OIDCConfigStep.tsx | 260 + src/app/setup/steps/PathsStep.tsx | 339 + src/app/setup/steps/PlexStep.tsx | 271 + src/app/setup/steps/ProwlarrStep.tsx | 429 + .../setup/steps/RegistrationSettingsStep.tsx | 156 + src/app/setup/steps/ReviewStep.tsx | 174 + src/app/setup/steps/WelcomeStep.tsx | 165 + src/components/audiobooks/AudiobookCard.tsx | 230 + .../audiobooks/AudiobookDetailsModal.tsx | 411 + src/components/audiobooks/AudiobookGrid.tsx | 92 + src/components/auth/ProtectedRoute.tsx | 60 + src/components/bookdate/LoadingScreen.tsx | 83 + .../bookdate/RecommendationCard.tsx | 248 + src/components/bookdate/SettingsWidget.tsx | 257 + src/components/layout/Header.tsx | 258 + .../InteractiveTorrentSearchModal.tsx | 241 + src/components/requests/RequestCard.tsx | 255 + src/components/requests/StatusBadge.tsx | 85 + src/components/ui/AlertModal.tsx | 70 + src/components/ui/Button.tsx | 81 + src/components/ui/ConfirmModal.tsx | 55 + src/components/ui/Input.tsx | 73 + src/components/ui/Modal.tsx | 111 + src/components/ui/Pagination.tsx | 131 + src/components/ui/StickyPagination.tsx | 144 + src/components/ui/Toast.tsx | 205 + src/contexts/AuthContext.tsx | 274 + src/lib/bookdate/helpers.ts | 733 + src/lib/db.ts | 26 + src/lib/hooks/useAudiobooks.ts | 86 + src/lib/hooks/useRequests.ts | 292 + src/lib/integrations/audible.service.ts | 719 + src/lib/integrations/plex.service.ts | 986 + src/lib/integrations/prowlarr.service.ts | 355 + src/lib/integrations/qbittorrent.service.ts | 774 + src/lib/middleware/auth.ts | 219 + .../processors/audible-refresh.processor.ts | 178 + .../cleanup-seeded-torrents.processor.ts | 146 + .../processors/download-torrent.processor.ts | 119 + src/lib/processors/match-plex.processor.ts | 191 + .../processors/monitor-download.processor.ts | 225 + .../processors/monitor-rss-feeds.processor.ts | 122 + .../processors/organize-files.processor.ts | 191 + .../plex-recently-added.processor.ts | 198 + .../retry-failed-imports.processor.ts | 99 + .../retry-missing-torrents.processor.ts | 75 + src/lib/processors/scan-plex.processor.ts | 220 + .../processors/search-indexers.processor.ts | 133 + src/lib/services/audiobookshelf/api.ts | 98 + src/lib/services/audiobookshelf/types.ts | 72 + src/lib/services/auth/IAuthProvider.ts | 60 + src/lib/services/auth/LocalAuthProvider.ts | 288 + src/lib/services/auth/OIDCAuthProvider.ts | 568 + src/lib/services/auth/PlexAuthProvider.ts | 261 + src/lib/services/auth/index.ts | 56 + src/lib/services/config.service.ts | 250 + src/lib/services/encryption.service.ts | 115 + src/lib/services/job-queue.service.ts | 845 + .../library/AudiobookshelfLibraryService.ts | 108 + src/lib/services/library/ILibraryService.ts | 58 + .../services/library/PlexLibraryService.ts | 261 + src/lib/services/library/index.ts | 50 + src/lib/services/scheduler.service.ts | 588 + src/lib/services/thumbnail-cache.service.ts | 180 + src/lib/utils/api.ts | 169 + src/lib/utils/audiobook-matcher.ts | 463 + src/lib/utils/cn.ts | 14 + src/lib/utils/cron.ts | 283 + src/lib/utils/file-organizer.ts | 479 + src/lib/utils/job-logger.ts | 97 + src/lib/utils/jwt-client.ts | 74 + src/lib/utils/jwt.ts | 90 + src/lib/utils/metadata-tagger.ts | 178 + src/lib/utils/ranking-algorithm.ts | 311 + src/lib/utils/url.ts | 75 + src/middleware.ts | 94 + src/types/openid-client.d.ts | 6 + tsconfig.json | 34 + 257 files changed, 89482 insertions(+) create mode 100644 .dockerignore create mode 100644 .env.example create mode 100644 .gitattributes create mode 100644 .github/workflows/build-unified-image.yml create mode 100644 .gitignore create mode 100644 AGENTS.md create mode 100644 CLAUDE.md create mode 100644 CONTRIBUTING.md create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 PlexMediaServerAPIDocs.json create mode 100644 README.md create mode 100644 docker-compose.debug.yml create mode 100644 docker-compose.local.yml create mode 100755 docker-entrypoint.sh create mode 100644 docker/unified/app-start.sh create mode 100644 docker/unified/entrypoint.sh create mode 100644 docker/unified/supervisord.conf create mode 100644 dockerfile.unified create mode 100644 documentation/README.md create mode 100644 documentation/TABLEOFCONTENTS.md create mode 100644 documentation/admin-dashboard.md create mode 100644 documentation/archive/BOOKDATE_COMPLETE.md create mode 100644 documentation/archive/BOOKDATE_DEPLOYMENT_GUIDE.md create mode 100644 documentation/archive/BOOKDATE_IMPLEMENTATION_STATUS.md create mode 100644 documentation/archive/DOCKER.md create mode 100644 documentation/archive/README.unified.md create mode 100644 documentation/backend/database.md create mode 100644 documentation/backend/middleware.md create mode 100644 documentation/backend/services/auth.md create mode 100644 documentation/backend/services/config.md create mode 100644 documentation/backend/services/environment.md create mode 100644 documentation/backend/services/jobs.md create mode 100644 documentation/backend/services/scheduler.md create mode 100644 documentation/deployment/docker.md create mode 100644 documentation/deployment/unified.md create mode 100644 documentation/features/audiobookshelf-implementation-guide.md create mode 100644 documentation/features/audiobookshelf-integration.md create mode 100644 documentation/features/bookdate-implementation-prompt.md create mode 100644 documentation/features/bookdate-prd.md create mode 100644 documentation/features/bookdate.md create mode 100644 documentation/features/chapter-merging.md create mode 100644 documentation/frontend/components.md create mode 100644 documentation/frontend/pages/login.md create mode 100644 documentation/frontend/routing-auth.md create mode 100644 documentation/integrations/audible.md create mode 100644 documentation/integrations/plex.md create mode 100644 documentation/phase3/README.md create mode 100644 documentation/phase3/file-organization.md create mode 100644 documentation/phase3/prowlarr.md create mode 100644 documentation/phase3/qbittorrent.md create mode 100644 documentation/phase3/ranking-algorithm.md create mode 100644 documentation/settings-pages.md create mode 100644 documentation/setup-wizard.md create mode 100644 eslint.config.mjs create mode 100644 next.config.ts create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 postcss.config.mjs create mode 100644 prisma/migrations/20251117191621_add_job_events/migration.sql create mode 100644 prisma/migrations/20251119210940_make_bookdate_config_global/migration.sql create mode 100644 prisma/migrations/20251121004152_add_metadata_tagging_config/migration.sql create mode 100644 prisma/migrations/20251221072639_add_last_run_job_id_to_scheduled_jobs/migration.sql create mode 100644 prisma/schema.prisma create mode 100644 public/RMAB_1024x1024.png create mode 100644 public/file.svg create mode 100644 public/globe.svg create mode 100644 public/manifest.json create mode 100644 public/next.svg create mode 100644 public/rmab_32x32.png create mode 100644 public/rmab_icon.ico create mode 100644 public/vercel.svg create mode 100644 public/window.svg create mode 100644 rmab_icon.ico create mode 100644 scripts/check-backend-mode.ts create mode 100644 scripts/setup-abs-config.ts create mode 100644 src/app/admin/components/ActiveDownloadsTable.tsx create mode 100644 src/app/admin/components/MetricCard.tsx create mode 100644 src/app/admin/components/RecentRequestsTable.tsx create mode 100644 src/app/admin/jobs/page.tsx create mode 100644 src/app/admin/logs/page.tsx create mode 100644 src/app/admin/page.tsx create mode 100644 src/app/admin/settings/page.tsx create mode 100644 src/app/admin/users/page.tsx create mode 100644 src/app/api/admin/backend-mode/route.ts create mode 100644 src/app/api/admin/bookdate/toggle/route.ts create mode 100644 src/app/api/admin/downloads/active/route.ts create mode 100644 src/app/api/admin/job-status/[id]/route.ts create mode 100644 src/app/api/admin/jobs/[id]/route.ts create mode 100644 src/app/api/admin/jobs/[id]/trigger/route.ts create mode 100644 src/app/api/admin/jobs/route.ts create mode 100644 src/app/api/admin/logs/route.ts create mode 100644 src/app/api/admin/metrics/route.ts create mode 100644 src/app/api/admin/plex/scan/route.ts create mode 100644 src/app/api/admin/requests/recent/route.ts create mode 100644 src/app/api/admin/settings/audiobookshelf/libraries/route.ts create mode 100644 src/app/api/admin/settings/audiobookshelf/route.ts create mode 100644 src/app/api/admin/settings/change-password/route.ts create mode 100644 src/app/api/admin/settings/download-client/route.ts create mode 100644 src/app/api/admin/settings/oidc/route.ts create mode 100644 src/app/api/admin/settings/paths/route.ts create mode 100644 src/app/api/admin/settings/plex/libraries/route.ts create mode 100644 src/app/api/admin/settings/plex/route.ts create mode 100644 src/app/api/admin/settings/prowlarr/indexers/route.ts create mode 100644 src/app/api/admin/settings/prowlarr/route.ts create mode 100644 src/app/api/admin/settings/registration/route.ts create mode 100644 src/app/api/admin/settings/route.ts create mode 100644 src/app/api/admin/settings/test-download-client/route.ts create mode 100644 src/app/api/admin/settings/test-plex/route.ts create mode 100644 src/app/api/admin/settings/test-prowlarr/route.ts create mode 100644 src/app/api/admin/users/[id]/approve/route.ts create mode 100644 src/app/api/admin/users/[id]/route.ts create mode 100644 src/app/api/admin/users/pending/route.ts create mode 100644 src/app/api/admin/users/route.ts create mode 100644 src/app/api/audiobooks/[asin]/route.ts create mode 100644 src/app/api/audiobooks/covers/route.ts create mode 100644 src/app/api/audiobooks/new-releases/route.ts create mode 100644 src/app/api/audiobooks/popular/route.ts create mode 100644 src/app/api/audiobooks/search/route.ts create mode 100644 src/app/api/auth/admin/login/route.ts create mode 100644 src/app/api/auth/is-local-admin/route.ts create mode 100644 src/app/api/auth/local/login/route.ts create mode 100644 src/app/api/auth/logout/route.ts create mode 100644 src/app/api/auth/me/route.ts create mode 100644 src/app/api/auth/oidc/callback/route.ts create mode 100644 src/app/api/auth/oidc/login/route.ts create mode 100644 src/app/api/auth/plex/callback/route.ts create mode 100644 src/app/api/auth/plex/home-users/route.ts create mode 100644 src/app/api/auth/plex/login/route.ts create mode 100644 src/app/api/auth/plex/switch-profile/route.ts create mode 100644 src/app/api/auth/providers/route.ts create mode 100644 src/app/api/auth/refresh/route.ts create mode 100644 src/app/api/auth/register/route.ts create mode 100644 src/app/api/bookdate/config/route.ts create mode 100644 src/app/api/bookdate/generate/route.ts create mode 100644 src/app/api/bookdate/preferences/route.ts create mode 100644 src/app/api/bookdate/recommendations/route.ts create mode 100644 src/app/api/bookdate/swipe/route.ts create mode 100644 src/app/api/bookdate/swipes/route.ts create mode 100644 src/app/api/bookdate/test-connection/route.ts create mode 100644 src/app/api/bookdate/undo/route.ts create mode 100644 src/app/api/cache/thumbnails/[filename]/route.ts create mode 100644 src/app/api/config/[category]/route.ts create mode 100644 src/app/api/config/route.ts create mode 100644 src/app/api/health/route.ts create mode 100644 src/app/api/init/route.ts create mode 100644 src/app/api/requests/[id]/interactive-search/route.ts create mode 100644 src/app/api/requests/[id]/manual-search/route.ts create mode 100644 src/app/api/requests/[id]/route.ts create mode 100644 src/app/api/requests/[id]/select-torrent/route.ts create mode 100644 src/app/api/requests/route.ts create mode 100644 src/app/api/setup/complete/route.ts create mode 100644 src/app/api/setup/status/route.ts create mode 100644 src/app/api/setup/test-abs/route.ts create mode 100644 src/app/api/setup/test-download-client/route.ts create mode 100644 src/app/api/setup/test-oidc/route.ts create mode 100644 src/app/api/setup/test-paths/route.ts create mode 100644 src/app/api/setup/test-plex/route.ts create mode 100644 src/app/api/setup/test-prowlarr/route.ts create mode 100644 src/app/auth/select-profile/page.tsx create mode 100644 src/app/bookdate/page.tsx create mode 100644 src/app/favicon.ico create mode 100644 src/app/globals.css create mode 100644 src/app/layout.tsx create mode 100644 src/app/login/page.tsx create mode 100644 src/app/page.tsx create mode 100644 src/app/profile/page.tsx create mode 100644 src/app/requests/page.tsx create mode 100644 src/app/search/page.tsx create mode 100644 src/app/setup/components/WizardLayout.tsx create mode 100644 src/app/setup/initializing/page.tsx create mode 100644 src/app/setup/page.tsx create mode 100644 src/app/setup/steps/AdminAccountStep.tsx create mode 100644 src/app/setup/steps/AudiobookshelfStep.tsx create mode 100644 src/app/setup/steps/AuthMethodStep.tsx create mode 100644 src/app/setup/steps/BackendSelectionStep.tsx create mode 100644 src/app/setup/steps/BookDateStep.tsx create mode 100644 src/app/setup/steps/DownloadClientStep.tsx create mode 100644 src/app/setup/steps/FinalizeStep.tsx create mode 100644 src/app/setup/steps/OIDCConfigStep.tsx create mode 100644 src/app/setup/steps/PathsStep.tsx create mode 100644 src/app/setup/steps/PlexStep.tsx create mode 100644 src/app/setup/steps/ProwlarrStep.tsx create mode 100644 src/app/setup/steps/RegistrationSettingsStep.tsx create mode 100644 src/app/setup/steps/ReviewStep.tsx create mode 100644 src/app/setup/steps/WelcomeStep.tsx create mode 100644 src/components/audiobooks/AudiobookCard.tsx create mode 100644 src/components/audiobooks/AudiobookDetailsModal.tsx create mode 100644 src/components/audiobooks/AudiobookGrid.tsx create mode 100644 src/components/auth/ProtectedRoute.tsx create mode 100644 src/components/bookdate/LoadingScreen.tsx create mode 100644 src/components/bookdate/RecommendationCard.tsx create mode 100644 src/components/bookdate/SettingsWidget.tsx create mode 100644 src/components/layout/Header.tsx create mode 100644 src/components/requests/InteractiveTorrentSearchModal.tsx create mode 100644 src/components/requests/RequestCard.tsx create mode 100644 src/components/requests/StatusBadge.tsx create mode 100644 src/components/ui/AlertModal.tsx create mode 100644 src/components/ui/Button.tsx create mode 100644 src/components/ui/ConfirmModal.tsx create mode 100644 src/components/ui/Input.tsx create mode 100644 src/components/ui/Modal.tsx create mode 100644 src/components/ui/Pagination.tsx create mode 100644 src/components/ui/StickyPagination.tsx create mode 100644 src/components/ui/Toast.tsx create mode 100644 src/contexts/AuthContext.tsx create mode 100644 src/lib/bookdate/helpers.ts create mode 100644 src/lib/db.ts create mode 100644 src/lib/hooks/useAudiobooks.ts create mode 100644 src/lib/hooks/useRequests.ts create mode 100644 src/lib/integrations/audible.service.ts create mode 100644 src/lib/integrations/plex.service.ts create mode 100644 src/lib/integrations/prowlarr.service.ts create mode 100644 src/lib/integrations/qbittorrent.service.ts create mode 100644 src/lib/middleware/auth.ts create mode 100644 src/lib/processors/audible-refresh.processor.ts create mode 100644 src/lib/processors/cleanup-seeded-torrents.processor.ts create mode 100644 src/lib/processors/download-torrent.processor.ts create mode 100644 src/lib/processors/match-plex.processor.ts create mode 100644 src/lib/processors/monitor-download.processor.ts create mode 100644 src/lib/processors/monitor-rss-feeds.processor.ts create mode 100644 src/lib/processors/organize-files.processor.ts create mode 100644 src/lib/processors/plex-recently-added.processor.ts create mode 100644 src/lib/processors/retry-failed-imports.processor.ts create mode 100644 src/lib/processors/retry-missing-torrents.processor.ts create mode 100644 src/lib/processors/scan-plex.processor.ts create mode 100644 src/lib/processors/search-indexers.processor.ts create mode 100644 src/lib/services/audiobookshelf/api.ts create mode 100644 src/lib/services/audiobookshelf/types.ts create mode 100644 src/lib/services/auth/IAuthProvider.ts create mode 100644 src/lib/services/auth/LocalAuthProvider.ts create mode 100644 src/lib/services/auth/OIDCAuthProvider.ts create mode 100644 src/lib/services/auth/PlexAuthProvider.ts create mode 100644 src/lib/services/auth/index.ts create mode 100644 src/lib/services/config.service.ts create mode 100644 src/lib/services/encryption.service.ts create mode 100644 src/lib/services/job-queue.service.ts create mode 100644 src/lib/services/library/AudiobookshelfLibraryService.ts create mode 100644 src/lib/services/library/ILibraryService.ts create mode 100644 src/lib/services/library/PlexLibraryService.ts create mode 100644 src/lib/services/library/index.ts create mode 100644 src/lib/services/scheduler.service.ts create mode 100644 src/lib/services/thumbnail-cache.service.ts create mode 100644 src/lib/utils/api.ts create mode 100644 src/lib/utils/audiobook-matcher.ts create mode 100644 src/lib/utils/cn.ts create mode 100644 src/lib/utils/cron.ts create mode 100644 src/lib/utils/file-organizer.ts create mode 100644 src/lib/utils/job-logger.ts create mode 100644 src/lib/utils/jwt-client.ts create mode 100644 src/lib/utils/jwt.ts create mode 100644 src/lib/utils/metadata-tagger.ts create mode 100644 src/lib/utils/ranking-algorithm.ts create mode 100644 src/lib/utils/url.ts create mode 100644 src/middleware.ts create mode 100644 src/types/openid-client.d.ts create mode 100644 tsconfig.json diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..62facc3 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,66 @@ +# Dependencies +node_modules +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Generated Prisma client (will be regenerated in container) +src/generated + +# Testing +coverage +.nyc_output + +# Next.js +.next +out + +# Production +build +dist + +# Misc +.DS_Store +*.pem + +# Debug +*.log +logs + +# Local env files +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# IDEs +.vscode +.idea +*.swp +*.swo +*~ + +# Git +.git +.gitignore +.gitattributes + +# CI/CD +.github + +# Documentation (not needed in runtime) +*.md +!README.md + +# Docker +Dockerfile +docker-compose.yml +.dockerignore + +# Data directories (will be mounted as volumes) +config +downloads +media +pgdata +redisdata diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..4f4726f --- /dev/null +++ b/.env.example @@ -0,0 +1,25 @@ +# Database +DATABASE_URL="postgresql://user:password@localhost:5432/readmeabook?schema=public" + +# Redis +REDIS_URL="redis://localhost:6379" + +# JWT +JWT_SECRET="change-this-to-a-random-secret-key" +JWT_REFRESH_SECRET="change-this-to-another-random-secret-key" + +# Encryption +CONFIG_ENCRYPTION_KEY="change-this-to-a-32-character-key" + +# Plex OAuth +PLEX_CLIENT_IDENTIFIER="readmeabook-unique-client-id" +PLEX_PRODUCT_NAME="ReadMeABook" +PLEX_OAUTH_CALLBACK_URL="http://localhost:3030/api/auth/plex/callback" + +# Paths (for local development) +DOWNLOADS_PATH="/downloads" +MEDIA_PATH="/media" + +# Application +NODE_ENV="development" +PORT="3030" diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6675a31 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Force LF line endings for shell scripts (critical for Docker) +*.sh text eol=lf diff --git a/.github/workflows/build-unified-image.yml b/.github/workflows/build-unified-image.yml new file mode 100644 index 0000000..1c20734 --- /dev/null +++ b/.github/workflows/build-unified-image.yml @@ -0,0 +1,87 @@ +name: Build and Publish Unified Docker Image + +on: + push: + branches: + - main + tags: + - 'v*' + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=sha,prefix=sha- + type=raw,value=latest,enable={{is_default_branch}} + labels: | + org.opencontainers.image.title=ReadMeABook Unified + org.opencontainers.image.description=All-in-one audiobook request and automation system (PostgreSQL + Redis + App) + org.opencontainers.image.vendor=ReadMeABook + + - name: Build and push unified Docker image + uses: docker/build-push-action@v5 + with: + context: . + file: ./dockerfile.unified + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Generate deployment instructions + if: github.event_name != 'pull_request' + run: | + echo "## ๐ŸŽ‰ Docker image published successfully!" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### ๐Ÿ“ฆ Available tags:" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + echo "${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### ๐Ÿš€ Quick start:" >> $GITHUB_STEP_SUMMARY + echo '```bash' >> $GITHUB_STEP_SUMMARY + echo "docker run -d \\" >> $GITHUB_STEP_SUMMARY + echo " --name readmeabook \\" >> $GITHUB_STEP_SUMMARY + echo " -p 3030:3030 \\" >> $GITHUB_STEP_SUMMARY + echo " -v ./config:/app/config \\" >> $GITHUB_STEP_SUMMARY + echo " -v ./downloads:/downloads \\" >> $GITHUB_STEP_SUMMARY + echo " -v ./media:/media \\" >> $GITHUB_STEP_SUMMARY + echo " -v readmeabook-data:/var/lib/postgresql/data \\" >> $GITHUB_STEP_SUMMARY + echo " ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..03427a2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,51 @@ +# IDE +.idea + +# Dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# Testing +/coverage + +# Next.js +/.next/ +/out/ + +# Production +/build + +# Misc +.DS_Store +*.pem + +# Debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# Environment files +.env* +!.env.example + +# Vercel +.vercel + +# TypeScript +*.tsbuildinfo +next-env.d.ts + +# Local data (Docker volumes) +/config +/downloads +/media + +/src/generated/prisma +/RMAB \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..e6ddeca --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,357 @@ +# AGENTS.md - Project Standards & Workflow + +**Critical:** This document defines AI-optimized documentation standards and development workflow. + +--- + +## 1. Token-Efficient Documentation System + +### Why Token Efficiency Matters + +**Problem:** Documentation consumes significant token budget, leaving limited context for implementation. + +**Solution:** Documentation optimized for AI consumption, not human reading. Average 68-72% token reduction while preserving all technical details. + +### Documentation Structure + +``` +documentation/ +โ”œโ”€โ”€ TABLEOFCONTENTS.md # Navigation index (read THIS FIRST) +โ”œโ”€โ”€ README.md # Project overview +โ”œโ”€โ”€ backend/ +โ”‚ โ”œโ”€โ”€ database.md # Schema, Prisma, migrations +โ”‚ โ””โ”€โ”€ services/ +โ”‚ โ”œโ”€โ”€ auth.md # Plex OAuth, JWT, RBAC +โ”‚ โ”œโ”€โ”€ config.md # Settings, encryption +โ”‚ โ”œโ”€โ”€ jobs.md # Bull queue, processors +โ”‚ โ””โ”€โ”€ scheduler.md # Cron jobs, recurring tasks +โ”œโ”€โ”€ integrations/ +โ”‚ โ”œโ”€โ”€ plex.md # Library scanning, OAuth, matching +โ”‚ โ””โ”€โ”€ audible.md # Web scraping, metadata +โ”œโ”€โ”€ phase3/ # Automation pipeline +โ”‚ โ”œโ”€โ”€ README.md # Pipeline overview +โ”‚ โ”œโ”€โ”€ qbittorrent.md # Download client +โ”‚ โ”œโ”€โ”€ prowlarr.md # Indexer search +โ”‚ โ”œโ”€โ”€ ranking-algorithm.md # Torrent selection +โ”‚ โ””โ”€โ”€ file-organization.md # File management, seeding +โ”œโ”€โ”€ frontend/ +โ”‚ โ”œโ”€โ”€ components.md # React components +โ”‚ โ”œโ”€โ”€ routing-auth.md # Route protection +โ”‚ โ””โ”€โ”€ pages/ +โ”‚ โ””โ”€โ”€ login.md # Login page design +โ”œโ”€โ”€ deployment/ +โ”‚ โ””โ”€โ”€ docker.md # Docker Compose, volumes +โ””โ”€โ”€ [feature-specific docs] +``` + +--- + +## 2. Using TABLEOFCONTENTS.md (MANDATORY) + +### **RULE: Always Start Here** + +**Before reading ANY documentation:** +1. **Read `documentation/TABLEOFCONTENTS.md` FIRST** +2. Identify relevant sections for your task +3. Read ONLY the specific files you need +4. **Never read all files sequentially** (wastes tokens) + +### Example Workflow + +**Bad (Token wasteful):** +``` +Task: Fix Plex authentication +โŒ Read README.md โ†’ backend/* โ†’ integrations/* โ†’ ... +``` + +**Good (Token efficient):** +``` +Task: Fix Plex authentication +โœ… Read TABLEOFCONTENTS.md โ†’ Identify: backend/services/auth.md, integrations/plex.md +โœ… Read only those 2 files +โœ… Begin implementation +``` + +### TABLEOFCONTENTS.md Format + +Maps questions/features to specific documentation files: +- "How does authentication work?" โ†’ backend/services/auth.md +- "How do downloads work?" โ†’ phase3/qbittorrent.md, backend/services/jobs.md +- Organized by: Authentication, Configuration, Database, Integrations, Automation, etc. + +--- + +## 3. Token-Efficient Documentation Format + +### Mandatory Format Standards + +**All documentation MUST follow this token-optimized format:** + +#### Structure +```markdown +# [Title] + +**Status:** [โœ… Implemented / โณ In Progress / โŒ Not Started] [Brief description] + +## Overview +[1-2 sentence summary] + +## Key Details +- Compact bullet lists (not prose) +- API endpoints with request/response +- Data models with field names/types +- Configuration keys +- Critical implementation notes + +## API/Interfaces +[Tables or compact code blocks] + +## Critical Issues (if any) +[Only important items] + +## Related: [links to other docs] +``` + +#### Forbidden Content (Removed for Token Efficiency) +- โŒ Verbose prose explanations +- โŒ "Why?" sections (keep brief rationale only) +- โŒ Large ASCII diagrams (minimal only) +- โŒ Excessive examples (max 1-2) +- โŒ "Future Enhancements" sections +- โŒ "Testing Strategy" (unless critical) +- โŒ "Performance Considerations" (unless critical) +- โŒ Empty sections +- โŒ Decorative formatting + +#### Required Content (Preserve Completely) +- โœ… API endpoint definitions +- โœ… Data model field names and types +- โœ… Configuration keys and values +- โœ… Status values and enums +- โœ… File paths and code locations +- โœ… Critical implementation details +- โœ… "Fixed Issues" (troubleshooting context) +- โœ… Essential code examples (1-2 max) + +### Format Examples + +**Before (Token wasteful - 180 lines):** +```markdown +# User Authentication Service + +## Current State + +**Status:** Implemented โœ… + +This service handles all authentication and authorization logic for the +ReadMeABook application, including Plex OAuth integration, JWT session +management, and role-based access control. + +## Design Architecture + +### Why Plex OAuth? + +Plex OAuth was chosen for several important reasons: +- No need to manage passwords +- Users already have Plex accounts +- Seamless integration with Plex ecosystem +... +[continues for 150+ more lines] +``` + +**After (Token efficient - 50 lines):** +```markdown +# User Authentication Service + +**Status:** โœ… Implemented | Plex OAuth + JWT sessions + RBAC + +## Overview +Handles Plex OAuth, JWT session management, role-based access control (user/admin). + +## Key Details +- **Auth:** Plex OAuth flow โ†’ JWT tokens (access: 1h, refresh: 7d) +- **Roles:** user (requests only), admin (full access) +- **First user:** Auto-promoted to admin +- **Endpoints:** + - POST /api/auth/plex/login โ†’ {authUrl, pinId} + - GET /api/auth/plex/callback?pinId โ†’ {accessToken, refreshToken, user} + - POST /api/auth/refresh โ†’ {accessToken} + - GET /api/auth/me โ†’ {user} +- **Middleware:** requireAuth(), requireAdmin() +- **Storage:** HTTP-only cookies + localStorage + +## JWT Payload +```json +{ + "sub": "user-uuid", + "plexId": "plex-id", + "role": "admin", + "exp": 1234571490 +} +``` +--- + +## 4. Implementation Strategy + +### Step 1: Navigate with TABLEOFCONTENTS.md +- Read TABLEOFCONTENTS.md to find relevant docs +- Identify 1-3 specific files needed (not all docs) + +### Step 2: Read Minimal Context +- Read ONLY the identified files +- Focus on "Key Details" and "API/Interfaces" sections +- Skip examples unless implementing similar functionality + +### Step 3: Reiterate Understanding +- Brief paragraph (3-4 sentences max) +- What user wants, what's affected, expected outcome + +### Step 4: Create Implementation Plan (TodoWrite) +``` +- [ ] Read: [specific doc files] +- [ ] Update: [specific doc files] +- [ ] Implement: [specific changes] +- [ ] Verify: [test steps] +``` + +### Step 5: Implement +- Follow plan +- Update docs using token-efficient format +- Add file headers linking to docs + +--- + +## 5. Documentation Maintenance + +### **RULE: Update TABLEOFCONTENTS.md** + +**When adding new documentation:** +1. Create doc file using token-efficient format +2. **Update TABLEOFCONTENTS.md** with new mapping +3. Update parent README.md if needed + +**Example:** +```markdown +# Added new feature: Email notifications + +Files created: +- documentation/backend/services/notifications.md + +Updates required: +- โœ… Create notifications.md (token-efficient format) +- โœ… Add to TABLEOFCONTENTS.md: "Email notifications" โ†’ backend/services/notifications.md +- โœ… Update documentation/README.md โ†’ Backend section +``` + +### **RULE: Keep Docs Up-to-Date** +- **Before code changes:** Read relevant docs +- **After code changes:** Update docs immediately +- Use token-efficient format for all updates + +--- + +## 6. Code Standards + +### File Size Limits +- Max 300-400 lines per file +- Refactor if exceeding limit + +### Mandatory File Headers +```typescript +/** + * Component: User Authentication Service + * Documentation: documentation/backend/services/auth.md + */ +``` + +### Link Accuracy +- Header path MUST point to existing doc file +- Create doc BEFORE implementing code +- Use relative paths from project root + +--- + +## 7. Token Budget Management + +### Critical Principle + +**Preserve tokens for implementation, not context gathering.** + +**Token Budget Allocation:** +- 20-30%: Reading relevant documentation (via TABLEOFCONTENTS.md) +- 70-80%: Implementation, problem-solving, code generation + +**Anti-Patterns (Token wasteful):** +- โŒ Reading all documentation files +- โŒ Reading verbose examples when not needed +- โŒ Re-reading same docs multiple times +- โŒ Reading "Future Enhancements" sections + +**Best Practices (Token efficient):** +- โœ… Use TABLEOFCONTENTS.md to target specific files +- โœ… Read only "Key Details" and "API/Interfaces" sections +- โœ… Skip examples unless implementing similar code +- โœ… Cache understanding in memory, don't re-read + +--- + +## 8. Examples + +### Example 1: Bug Fix + +**Task:** "Plex authentication fails with 403 error" + +**Process:** +1. Read TABLEOFCONTENTS.md โ†’ Find: backend/services/auth.md, integrations/plex.md +2. Read only those 2 files (focus on API endpoints, error handling) +3. Identify issue: Token refresh logic +4. Fix code +5. Update backend/services/auth.md (token-efficient format) + +### Example 2: New Feature + +**Task:** "Add email notifications for completed requests" + +**Process:** +1. Read TABLEOFCONTENTS.md โ†’ Find: backend/services/scheduler.md, backend/services/jobs.md +2. Read those files for background job patterns +3. Create documentation/backend/services/notifications.md (token-efficient format) +4. Update TABLEOFCONTENTS.md: "Email notifications" โ†’ backend/services/notifications.md +5. Implement notification service +6. Add file header linking to notifications.md + +--- + +## 9. Quality Checklist + +Before completing any task: + +- [ ] Used TABLEOFCONTENTS.md to find docs (not read all files) +- [ ] Read only necessary documentation +- [ ] Updated documentation in token-efficient format +- [ ] Updated TABLEOFCONTENTS.md if added new docs +- [ ] Added file headers to new code files +- [ ] No file exceeds 400 lines +- [ ] Documentation matches implementation + +--- + +## 10. Summary + +**Key Points:** +1. **Always start with TABLEOFCONTENTS.md** (navigation index) +2. **Read only what you need** (not all docs) +3. **Use token-efficient format** (bullets, tables, minimal prose) +4. **Preserve tokens for implementation** (not context gathering) +5. **Update docs immediately** (before/after code changes) +6. **Update TABLEOFCONTENTS.md** (when adding new docs) + +**Result:** +- 68-72% token reduction in documentation +- Faster context gathering +- More tokens available for implementation +- Better AI performance on complex tasks + +--- + +**Remember:** Documentation is for AI consumption. Token efficiency is critical. Always use TABLEOFCONTENTS.md. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..214688e --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,357 @@ +# CLAUDE.md - Project Standards & Workflow + +**Critical:** This document defines AI-optimized documentation standards and development workflow. + +--- + +## 1. Token-Efficient Documentation System + +### Why Token Efficiency Matters + +**Problem:** Documentation consumes significant token budget, leaving limited context for implementation. + +**Solution:** Documentation optimized for AI consumption, not human reading. Average 68-72% token reduction while preserving all technical details. + +### Documentation Structure + +``` +documentation/ +โ”œโ”€โ”€ TABLEOFCONTENTS.md # Navigation index (read THIS FIRST) +โ”œโ”€โ”€ README.md # Project overview +โ”œโ”€โ”€ backend/ +โ”‚ โ”œโ”€โ”€ database.md # Schema, Prisma, migrations +โ”‚ โ””โ”€โ”€ services/ +โ”‚ โ”œโ”€โ”€ auth.md # Plex OAuth, JWT, RBAC +โ”‚ โ”œโ”€โ”€ config.md # Settings, encryption +โ”‚ โ”œโ”€โ”€ jobs.md # Bull queue, processors +โ”‚ โ””โ”€โ”€ scheduler.md # Cron jobs, recurring tasks +โ”œโ”€โ”€ integrations/ +โ”‚ โ”œโ”€โ”€ plex.md # Library scanning, OAuth, matching +โ”‚ โ””โ”€โ”€ audible.md # Web scraping, metadata +โ”œโ”€โ”€ phase3/ # Automation pipeline +โ”‚ โ”œโ”€โ”€ README.md # Pipeline overview +โ”‚ โ”œโ”€โ”€ qbittorrent.md # Download client +โ”‚ โ”œโ”€โ”€ prowlarr.md # Indexer search +โ”‚ โ”œโ”€โ”€ ranking-algorithm.md # Torrent selection +โ”‚ โ””โ”€โ”€ file-organization.md # File management, seeding +โ”œโ”€โ”€ frontend/ +โ”‚ โ”œโ”€โ”€ components.md # React components +โ”‚ โ”œโ”€โ”€ routing-auth.md # Route protection +โ”‚ โ””โ”€โ”€ pages/ +โ”‚ โ””โ”€โ”€ login.md # Login page design +โ”œโ”€โ”€ deployment/ +โ”‚ โ””โ”€โ”€ docker.md # Docker Compose, volumes +โ””โ”€โ”€ [feature-specific docs] +``` + +--- + +## 2. Using TABLEOFCONTENTS.md (MANDATORY) + +### **RULE: Always Start Here** + +**Before reading ANY documentation:** +1. **Read `documentation/TABLEOFCONTENTS.md` FIRST** +2. Identify relevant sections for your task +3. Read ONLY the specific files you need +4. **Never read all files sequentially** (wastes tokens) + +### Example Workflow + +**Bad (Token wasteful):** +``` +Task: Fix Plex authentication +โŒ Read README.md โ†’ backend/* โ†’ integrations/* โ†’ ... +``` + +**Good (Token efficient):** +``` +Task: Fix Plex authentication +โœ… Read TABLEOFCONTENTS.md โ†’ Identify: backend/services/auth.md, integrations/plex.md +โœ… Read only those 2 files +โœ… Begin implementation +``` + +### TABLEOFCONTENTS.md Format + +Maps questions/features to specific documentation files: +- "How does authentication work?" โ†’ backend/services/auth.md +- "How do downloads work?" โ†’ phase3/qbittorrent.md, backend/services/jobs.md +- Organized by: Authentication, Configuration, Database, Integrations, Automation, etc. + +--- + +## 3. Token-Efficient Documentation Format + +### Mandatory Format Standards + +**All documentation MUST follow this token-optimized format:** + +#### Structure +```markdown +# [Title] + +**Status:** [โœ… Implemented / โณ In Progress / โŒ Not Started] [Brief description] + +## Overview +[1-2 sentence summary] + +## Key Details +- Compact bullet lists (not prose) +- API endpoints with request/response +- Data models with field names/types +- Configuration keys +- Critical implementation notes + +## API/Interfaces +[Tables or compact code blocks] + +## Critical Issues (if any) +[Only important items] + +## Related: [links to other docs] +``` + +#### Forbidden Content (Removed for Token Efficiency) +- โŒ Verbose prose explanations +- โŒ "Why?" sections (keep brief rationale only) +- โŒ Large ASCII diagrams (minimal only) +- โŒ Excessive examples (max 1-2) +- โŒ "Future Enhancements" sections +- โŒ "Testing Strategy" (unless critical) +- โŒ "Performance Considerations" (unless critical) +- โŒ Empty sections +- โŒ Decorative formatting + +#### Required Content (Preserve Completely) +- โœ… API endpoint definitions +- โœ… Data model field names and types +- โœ… Configuration keys and values +- โœ… Status values and enums +- โœ… File paths and code locations +- โœ… Critical implementation details +- โœ… "Fixed Issues" (troubleshooting context) +- โœ… Essential code examples (1-2 max) + +### Format Examples + +**Before (Token wasteful - 180 lines):** +```markdown +# User Authentication Service + +## Current State + +**Status:** Implemented โœ… + +This service handles all authentication and authorization logic for the +ReadMeABook application, including Plex OAuth integration, JWT session +management, and role-based access control. + +## Design Architecture + +### Why Plex OAuth? + +Plex OAuth was chosen for several important reasons: +- No need to manage passwords +- Users already have Plex accounts +- Seamless integration with Plex ecosystem +... +[continues for 150+ more lines] +``` + +**After (Token efficient - 50 lines):** +```markdown +# User Authentication Service + +**Status:** โœ… Implemented | Plex OAuth + JWT sessions + RBAC + +## Overview +Handles Plex OAuth, JWT session management, role-based access control (user/admin). + +## Key Details +- **Auth:** Plex OAuth flow โ†’ JWT tokens (access: 1h, refresh: 7d) +- **Roles:** user (requests only), admin (full access) +- **First user:** Auto-promoted to admin +- **Endpoints:** + - POST /api/auth/plex/login โ†’ {authUrl, pinId} + - GET /api/auth/plex/callback?pinId โ†’ {accessToken, refreshToken, user} + - POST /api/auth/refresh โ†’ {accessToken} + - GET /api/auth/me โ†’ {user} +- **Middleware:** requireAuth(), requireAdmin() +- **Storage:** HTTP-only cookies + localStorage + +## JWT Payload +```json +{ + "sub": "user-uuid", + "plexId": "plex-id", + "role": "admin", + "exp": 1234571490 +} +``` +--- + +## 4. Implementation Strategy + +### Step 1: Navigate with TABLEOFCONTENTS.md +- Read TABLEOFCONTENTS.md to find relevant docs +- Identify 1-3 specific files needed (not all docs) + +### Step 2: Read Minimal Context +- Read ONLY the identified files +- Focus on "Key Details" and "API/Interfaces" sections +- Skip examples unless implementing similar functionality + +### Step 3: Reiterate Understanding +- Brief paragraph (3-4 sentences max) +- What user wants, what's affected, expected outcome + +### Step 4: Create Implementation Plan (TodoWrite) +``` +- [ ] Read: [specific doc files] +- [ ] Update: [specific doc files] +- [ ] Implement: [specific changes] +- [ ] Verify: [test steps] +``` + +### Step 5: Implement +- Follow plan +- Update docs using token-efficient format +- Add file headers linking to docs + +--- + +## 5. Documentation Maintenance + +### **RULE: Update TABLEOFCONTENTS.md** + +**When adding new documentation:** +1. Create doc file using token-efficient format +2. **Update TABLEOFCONTENTS.md** with new mapping +3. Update parent README.md if needed + +**Example:** +```markdown +# Added new feature: Email notifications + +Files created: +- documentation/backend/services/notifications.md + +Updates required: +- โœ… Create notifications.md (token-efficient format) +- โœ… Add to TABLEOFCONTENTS.md: "Email notifications" โ†’ backend/services/notifications.md +- โœ… Update documentation/README.md โ†’ Backend section +``` + +### **RULE: Keep Docs Up-to-Date** +- **Before code changes:** Read relevant docs +- **After code changes:** Update docs immediately +- Use token-efficient format for all updates + +--- + +## 6. Code Standards + +### File Size Limits +- Max 300-400 lines per file +- Refactor if exceeding limit + +### Mandatory File Headers +```typescript +/** + * Component: User Authentication Service + * Documentation: documentation/backend/services/auth.md + */ +``` + +### Link Accuracy +- Header path MUST point to existing doc file +- Create doc BEFORE implementing code +- Use relative paths from project root + +--- + +## 7. Token Budget Management + +### Critical Principle + +**Preserve tokens for implementation, not context gathering.** + +**Token Budget Allocation:** +- 20-30%: Reading relevant documentation (via TABLEOFCONTENTS.md) +- 70-80%: Implementation, problem-solving, code generation + +**Anti-Patterns (Token wasteful):** +- โŒ Reading all documentation files +- โŒ Reading verbose examples when not needed +- โŒ Re-reading same docs multiple times +- โŒ Reading "Future Enhancements" sections + +**Best Practices (Token efficient):** +- โœ… Use TABLEOFCONTENTS.md to target specific files +- โœ… Read only "Key Details" and "API/Interfaces" sections +- โœ… Skip examples unless implementing similar code +- โœ… Cache understanding in memory, don't re-read + +--- + +## 8. Examples + +### Example 1: Bug Fix + +**Task:** "Plex authentication fails with 403 error" + +**Process:** +1. Read TABLEOFCONTENTS.md โ†’ Find: backend/services/auth.md, integrations/plex.md +2. Read only those 2 files (focus on API endpoints, error handling) +3. Identify issue: Token refresh logic +4. Fix code +5. Update backend/services/auth.md (token-efficient format) + +### Example 2: New Feature + +**Task:** "Add email notifications for completed requests" + +**Process:** +1. Read TABLEOFCONTENTS.md โ†’ Find: backend/services/scheduler.md, backend/services/jobs.md +2. Read those files for background job patterns +3. Create documentation/backend/services/notifications.md (token-efficient format) +4. Update TABLEOFCONTENTS.md: "Email notifications" โ†’ backend/services/notifications.md +5. Implement notification service +6. Add file header linking to notifications.md + +--- + +## 9. Quality Checklist + +Before completing any task: + +- [ ] Used TABLEOFCONTENTS.md to find docs (not read all files) +- [ ] Read only necessary documentation +- [ ] Updated documentation in token-efficient format +- [ ] Updated TABLEOFCONTENTS.md if added new docs +- [ ] Added file headers to new code files +- [ ] No file exceeds 400 lines +- [ ] Documentation matches implementation + +--- + +## 10. Summary + +**Key Points:** +1. **Always start with TABLEOFCONTENTS.md** (navigation index) +2. **Read only what you need** (not all docs) +3. **Use token-efficient format** (bullets, tables, minimal prose) +4. **Preserve tokens for implementation** (not context gathering) +5. **Update docs immediately** (before/after code changes) +6. **Update TABLEOFCONTENTS.md** (when adding new docs) + +**Result:** +- 68-72% token reduction in documentation +- Faster context gathering +- More tokens available for implementation +- Better AI performance on complex tasks + +--- + +**Remember:** Documentation is for AI consumption. Token efficiency is critical. Always use TABLEOFCONTENTS.md. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..edf845d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,321 @@ +# Contributing to ReadMeABook + +Thank you for your interest in contributing to ReadMeABook! This document provides guidelines and instructions for contributing to the project. + +--- + +## ๐Ÿค How to Contribute + +### Reporting Issues + +If you encounter a bug or have a feature request: + +1. **Check existing issues** - Search [GitHub Issues](https://github.com/kikootwo/ReadMeABook/issues) to see if it's already reported +2. **Create a new issue** - Use the appropriate issue template +3. **Provide details** - Include: + - Clear description of the problem/feature + - Steps to reproduce (for bugs) + - Expected vs actual behavior + - Environment details (OS, Docker version, etc.) + - Relevant logs or screenshots + +### Submitting Pull Requests + +1. **Fork the repository** +2. **Create a feature branch** from `main`: + ```bash + git checkout -b feature/your-feature-name + ``` +3. **Make your changes** following our coding standards +4. **Test your changes** thoroughly +5. **Commit with clear messages**: + ```bash + git commit -m "Add: brief description of changes" + ``` +6. **Push to your fork**: + ```bash + git push origin feature/your-feature-name + ``` +7. **Open a Pull Request** with: + - Clear title and description + - Reference to related issues + - Screenshots/demos if applicable + +--- + +## ๐Ÿ—๏ธ Development Setup + +### Prerequisites + +- Node.js 20+ +- Docker & Docker Compose +- Git + +### Local Development + +1. **Clone the repository:** + ```bash + git clone https://github.com/kikootwo/ReadMeABook.git + cd ReadMeABook + ``` + +2. **Install dependencies:** + ```bash + npm install + ``` + +3. **Set up environment:** + ```bash + cp .env.example .env + # Edit .env with your local configuration + ``` + +4. **Start development stack:** + ```bash + # Using Docker Compose (recommended) + docker compose -f docker-compose.local.yml up -d + + # Or run services separately + docker compose -f docker-compose.debug.yml up -d postgres redis + npm run dev + ``` + +5. **Run database migrations:** + ```bash + npm run prisma:generate + npm run db:push + ``` + +6. **Access the app:** + - App: http://localhost:3030 + - Prisma Studio: `npm run prisma:studio` + +--- + +## ๐Ÿ“ Coding Standards + +### General Guidelines + +- **Follow existing code style** - Use the project's ESLint configuration +- **Write clear, descriptive variable names** +- **Add comments for complex logic** +- **Keep functions small and focused** +- **Test your changes** + +### TypeScript + +- Use TypeScript for all new code +- Define proper types (avoid `any`) +- Use interfaces for object shapes +- Export types when they're reusable + +### React Components + +- Use functional components with hooks +- Keep components focused and reusable +- Use proper TypeScript props typing +- Follow the existing component structure in `src/components/` + +### File Organization + +- **Max 300-400 lines per file** - Refactor if larger +- **Add file headers** to reference documentation: + ```typescript + /** + * Component: Feature Name + * Documentation: documentation/path/to/doc.md + */ + ``` + +### Database Changes + +- Always use Prisma migrations +- Test migrations with seed data +- Document schema changes in pull request + +--- + +## ๐Ÿ“š Documentation + +### Updating Documentation + +When making changes that affect documentation: + +1. **Update relevant docs** in `documentation/` +2. **Use token-efficient format** (see [CLAUDE.md](CLAUDE.md)) +3. **Update TABLEOFCONTENTS.md** if adding new docs +4. **Keep docs in sync** with code changes + +### Documentation Standards + +- Use bullet points over prose +- Include code examples where helpful +- Keep status indicators updated (โœ…/โณ/โŒ) +- Link to related documentation + +--- + +## ๐Ÿงช Testing + +### Before Submitting + +- Test locally with Docker Compose +- Verify no console errors +- Test with clean database (migrations) +- Check responsive design (if UI changes) +- Verify all features still work + +### Manual Testing Checklist + +- [ ] Login with Plex works +- [ ] Library scan completes +- [ ] Book requests can be created +- [ ] Settings can be updated +- [ ] Background jobs run correctly + +--- + +## ๐Ÿ” Code Review Process + +### What We Look For + +- **Functionality** - Does it work as intended? +- **Code quality** - Is it clean and maintainable? +- **Testing** - Has it been adequately tested? +- **Documentation** - Are docs updated? +- **Breaking changes** - Are they necessary and documented? + +### Review Timeline + +- Initial review: Within 1-2 weeks +- Follow-up on feedback: Ongoing +- Merge: When approved and CI passes + +--- + +## ๐Ÿš€ Release Process + +### Versioning + +We follow [Semantic Versioning](https://semver.org/): + +- **MAJOR**: Breaking changes +- **MINOR**: New features (backward compatible) +- **PATCH**: Bug fixes + +### Release Cycle + +- Releases are tagged as needed +- Docker images automatically built on push to `main` +- Breaking changes documented in release notes + +--- + +## ๐Ÿ’ก Development Tips + +### Working with Prisma + +```bash +# Generate Prisma client after schema changes +npm run prisma:generate + +# Push schema changes to database +npm run db:push + +# Open Prisma Studio +npm run prisma:studio +``` + +### Working with Docker + +```bash +# Build local image +docker compose -f docker-compose.local.yml build + +# View logs +docker compose -f docker-compose.local.yml logs -f + +# Reset database +docker compose -f docker-compose.local.yml down -v +``` + +### Debugging + +- Use `LOG_LEVEL=debug` in environment +- Check browser console for frontend issues +- Use Prisma Studio to inspect database +- Check Docker logs for backend issues + +--- + +## ๐Ÿ“‹ Commit Message Guidelines + +### Format + +``` +: + + + +