summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
2026-05-18Add Dockerfile.flutter-ci and update android.yml to use project imagePaul Buetow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18Add e2e-llm harness runner and READMEPaul Buetow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18Add .woodpecker/android.yml and .woodpecker/nightly.yml CI pipelinesPaul Buetow
android.yml: Flutter Android pipeline running flutter analyze + flutter test on every push or PR touching player-android/**. Uses ghcr.io/cirruslabs/flutter:stable with a flutter-pub-cache named volume. Path-scoped so Go-only changes do not trigger the Flutter runner. nightly.yml: Nightly LLM e2e stub pipeline on cron 0 2 * * * (main only). Injects ANTHROPIC_API_KEY from a protected Woodpecker project secret, includes a belt-and-suspenders branch guard, a placeholder llm-e2e step (exits 0), and a cost-log step that emits a parseable cost summary line for future monitoring. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18Add .woodpecker/server.yml: Go server CI pipelinePaul Buetow
Stage 1 (server-unit) runs go test -race -count=1 ./... on every push for a fast ~10-15 s feedback gate. Stage 2 (server-integration + web-smoke) runs only on pushes to main or PRs targeting main, after Stage 1 passes. web-smoke builds the server binary, waits for /healthz readiness via curl --retry, then runs the Playwright Chromium suite against testmedia. Go module, build, and Playwright Chromium caches use named Woodpecker host volumes to avoid redundant downloads. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18Add CI pipeline design proposalPaul Buetow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18Add LLM-driven e2e test design proposalPaul Buetow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18Add Android testing strategy proposalPaul Buetow
Produces player-android/docs/testing-strategy.md as a decision gate covering test scope, CI emulator options, integration_test vs Patrol, and LLM access mode. Reviewed by sub-agent; all issues addressed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18Add Dart unit tests for models and API client constructorPaul Buetow
Add fromJson/toJson round-trip tests for all 9 Dart models (Media, MediaSet, User, Tag, Note, Share, PodcastFeed, PodcastEpisode, PlaybackHint) and 3 PlayerApiClient constructor tests. Each model group covers a fully-populated round-trip (including int-to-double cast verification and ISO-8601 DateTime value comparison) and an exhaustive defaults-from-empty-map test. All 21 tests run via 'flutter test' with no emulator. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18Add web UI smoke test suitePaul Buetow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18Choose Playwright for web UI smoke testsPaul Buetow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18Add /api/v1/ integration test suitePaul Buetow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18Rewrite api.md as exhaustive multi-client API contractPaul Buetow
- Expanded docs/api.md from 83 lines to full coverage: all 58 registered routes documented with method, both /api/ and /api/v1/ path aliases, request/response JSON schemas, status codes, and curl examples - Added Authentication section: Bearer token vs session cookie, auth precedence in RequireSession middleware, first-time bootstrap flow - Added API Versioning section: /api/ (legacy/web) vs /api/v1/ (stable contract), handleBoth convention, recommendation for mobile clients - Added Error Envelope section: {error: ...} documented once with full status code table - Added Token Lifecycle subsection: minting (one-time plaintext), expiry enforcement, last_used_at semantics, and revocation behaviour - Added Range header support documentation for streaming endpoints - Added Quick Reference table mapping every route to its auth level - Updated AGENTS.md with two new sections: Bearer-or-cookie unified middleware pattern in RequireSession, and handleBoth route registration convention to prevent multi-client contract drift Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18Add test coverage audit and gap reportPaul Buetow
Documents per-package coverage (73.6% overall), identifies untested functions (progress_transaction.go at 0%, several podcast sub-service methods, API share handlers), and catalogues reusable test helpers found in *_test.go files for use by later test-addition tasks. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18Add playback hints endpoint for client codec/container decisionsPaul Buetow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17Add bulk progress sync endpoint for offline mobile clientsPaul Buetow
2026-05-17Add /api/v1/auth/tokens endpoints for API token managementPaul Buetow
2026-05-17Add Bearer token authentication alongside session cookiesPaul Buetow
2026-05-17Add TokenManager for API token generation and hashingPaul Buetow
2026-05-17Add api_tokens table, model, and repositoryPaul Buetow
2026-05-17Add CORS middleware for multi-origin clientsPaul Buetow
2026-05-17Add /api/v1/ versioning aliasPaul Buetow
2026-05-17Add monorepo root orientationPaul Buetow
2026-05-17Track player-android Flutter lockfilePaul Buetow
2026-05-17Complete player-android Flutter scaffoldPaul Buetow
2026-05-17Add player-android/ Flutter skeletonPaul Buetow
2026-05-17Restructure repo: move Go server into player-server/Paul Buetow
2026-05-17Fix in-progress media thresholdPaul Buetow
2026-05-17Add in-progress frontend actionsPaul Buetow
2026-05-17Add progress status API routesPaul Buetow
2026-05-17Add progress service completion methodsPaul Buetow
2026-05-17Add playback repository cleanup queriesPaul Buetow
2026-05-17Add finished flag to playback progressPaul Buetow
2026-05-16Configure SQLite for NFS-backed deploymentsPaul Buetow
2026-05-16Migrate stale sets schema for podcastsPaul Buetow
2026-05-10refactor: move ServeHTTP above unexported helpers for public-method orderingPaul Buetow
2026-05-10refactor(cmd/player): move appDeps and parseVersionFlag above mainPaul Buetow
2026-05-10Decompose podcastService (SRP): split subscription, episode, and ↵Paul Buetow
feed-checker into sub-services Extract three role-focused sub-services from the monolithic podcastService: - podcast_sub.go: podcastSubscriptionService handles SubscribeFeed, ListFeeds, EditFeed, UnsubscribeFeed and podcast set lifecycle. - podcast_episode.go: podcastEpisodeService handles ListEpisodes, DownloadEpisode, ToggleEpisodeComplete and enclosure downloading. - podcast_checker.go: podcastFeedChecker handles CheckFeeds, conditional GET, backoff and episode upserting. - podcast_helpers.go: shared helpers (podcastFolderName, sanitizeSetName, sanitizeFilename). podcast.go becomes a thin composite that embeds the three sub-services and exposes a PodcastEpisodeService-compatible interface, preserving existing API-layer wiring and tests.
2026-05-10Move self-deletion guard from handler into AdminService (DeleteUser) to fix ↵Paul Buetow
SoC violation - Add ErrCannotDeleteSelf sentinel error in service layer. - Change DeleteUser signature to (ctx, callerID, id) across all layers. - Move self-deletion guard from handleDeleteUser handler into userAdminService.DeleteUser. - Update handleError to map ErrCannotDeleteSelf to 400 BadRequest. - Adjust all affected tests to use the new signature.
2026-05-10refactor(service,scanner): return concrete types from constructorsPaul Buetow
Apply the Go best-practice convention 'accept interfaces, return concrete types' across the service and scanner packages: - NewBrowseService -> *browseService - NewWriteService -> *writeService - NewMediaStreamer -> *mediaStreamer - NewFSScanner -> *FSScanner - NewFSScannerWithLogger -> *FSScanner - NewPodcastBrowseService -> *podcastBrowseService - NewTagService -> *tagService - NewShareService -> *shareService - NewProgressService -> *progressService - NewAdminService -> *adminService - NewAdminServiceWithLogger -> *adminService - NewAuthService -> *authService - NewNoteService -> *noteService - NewFavService -> *favService - NewMediaService -> *mediaService - NewMediaServiceWithPodcastBrowser -> *mediaService Callers continue to work unchanged because Go allows assigning a concrete type to an interface variable. All tests pass with -race -cover.
2026-05-10fix(browse): return ErrNotFound when set cover is missingPaul Buetow
GetSetCover was returning a stale os.Stat wrapped error when no thumbnail candidate was found (line 465), and was not translating os.IsNotExist to ErrNotFound when the candidate thumbnail was missing (line 468). Both cases now return service.ErrNotFound so the caller/handler can respond with 404 instead of 500.
2026-05-10api: reject id==0 in handleDeleteUser to avoid 200 OK for invalid pathPaul Buetow
2026-05-10internal/service: stop swallowing CreateEpisode errors in ↵Paul Buetow
insertPodcastEpisodes and upsertFeedEpisodes - insertPodcastEpisodes now returns an error when CreateEpisode fails so callers (e.g. SubscribeFeed) can log it instead of silently dropping episodes. - upsertFeedEpisodes now logs per-episode lookup/insert failures, collects the failed GUIDs, and returns a summary error so the background CheckFeeds caller can log a warning while continuing to process the rest of the feed. All tests pass with -race -cover.
2026-05-10podcast: propagate UpdateFeed error on 304 Not Modified pathPaul Buetow
Previously checkFeed silently discarded the DB update error when a feed returned 304 Not Modified. If the update failed, LastCheckedAt was not persisted, causing the next background check to re-fetch the same unchanged feed unnecessarily. Now the error is propagated back to CheckFeeds so it is logged like any other feed-check failure.
2026-05-10player: log downloadCover errors in podcast subscribe and feed checkPaul Buetow
2026-05-10refactor(api): replace all writeJSON 500 error patterns with handleError helperPaul Buetow
2026-05-10fix(tests): handle json.Unmarshal errors explicitly in *_test.goPaul Buetow
2026-05-10Add compile-time interface assertions for FFProber, FFmpegGenerator, FFRemuxerPaul Buetow
2026-05-10internal/service: fix ListEpisodes global pagination by using cross-feed SQL ↵Paul Buetow
query Previously ListEpisodes requested per-feed episodes with the full limit from every feed, concatenated them, and then sliced the resulting slice in memory. This silently skipped episodes from deeper pages because the per-feed DB limit never returned them. Fix: Add a new repository method ListEpisodesByFeedIDsWithStatus that takes a slice of feed IDs and applies LIMIT/OFFSET globally in a single SQL query (IN (...)). The service builds the feed ID list and delegates pagination to the database instead of emulating it in memory. Files changed: - internal/repository/podcast.go: add ListEpisodesByFeedIDsWithStatus - internal/repository/podcast_repo.go: extend PodcastRepo interface - internal/repository/mock.go: add mock implementation - internal/service/podcast.go: replace per-feed loop with new method - internal/service/podcast_test.go: add tests for ListEpisodes - internal/repository/podcast_test.go: add integration tests for new repo method - internal/api/handlers_test.go: add mockPingStore method
2026-05-10Add circuit breaker / backoff for failing podcast feeds in CheckFeedsPaul Buetow
- DB: add consecutive_failures and next_check_at to podcast_feeds - model: add ConsecutiveFailures and NextCheckAt to PodcastFeed struct - repository: update CRUD queries to handle new columns and ListFeedsNeedingCheck to skip feeds with future next_check_at - service: update CheckFeeds to use new query, update checkFeed to reset counters on success and increment exponential backoff on failure - tests: adapt mock signatures, add backoff integration test
2026-05-10fix: close destination file and clean up partial copies in copyFilePaul Buetow
- Add defer out.Close() after os.Create in copyFile to prevent fd leak. - Remove redundant explicit out.Close() calls in error and success paths. - Best-effort remove partially written destination file on io.Copy error.