20 Commits

Author SHA1 Message Date
Your Name fc8071b7aa fix: issue triage -- #155 #156 #154 #25, CI hardening, E2E improvements
Issue fixes:
- #155: /api/browse/playlists/parse now handles YouTube/YouTube Music URLs
- #156: stop passing album MBID to verifyArtistName (was calling MB /artist/{id}
  with an album MBID, always 404d); fix spotify trackCount stale value
- #154: remove hardcoded port-3030 detection from getApiBaseUrl -- now returns
  relative URLs by default so any host:port mapping works
- #25 (partial): fix spotify playlist trackCount to use tracks.length instead of
  stale playlist.tracks.total after pagination

Dead code / quality:
- Remove unused rootFolderPath param from processDownload + call sites
- Remove unused req params in route handlers (prefix _req)
- Remove dead push condition from integration.yml job gate
- Remove dead baseUrl constructor param and private field from ApiService
- Fix LibraryTabs hover effect: remove inline style={{ opacity: 0.1 }} that
  overrode Tailwind group-hover; change to group-hover:opacity-10
- Fix mobile tab centering in LibraryTabs (add justify-center)

CI security:
- Mask TEST_PASS before writing to GITHUB_ENV in all three workflow files
- Add missing concurrency block to nightly.yml
- Add username validation + remove credential echo in create-e2e-user.sh
- Fix global.setup.ts error message to mention .env.test

E2E:
- Fix vibe test race condition: replace Promise.race + transient text with
  stable trackCount.or(noData) assertion
- Fix security test flakiness: toBe(beforeCount) -> not.toBeGreaterThan for
  playlist count check (parallel tests can delete playlists concurrently)
- Fix global.setup.ts error message to reference .env.test file

Vibe map:
- Increase cluster label size (13->15 / 10->12 px) and opacity (50->70 / 35->50)
  for slightly better readability
2026-03-17 10:04:03 -05:00
Your Name 632d7d5030 fix: integration tests no longer run on every push to main 2026-03-16 23:04:10 -05:00
Your Name fd8f67109d fix: docker-nightly runs on schedule only, add concurrency cancellation to integration
docker-nightly was triggering on every push to main -- a full multi-arch
Docker build on every commit. Moved to schedule-only (4am UTC) + workflow_dispatch.

Added concurrency groups so rapid pushes to main cancel the previous
in-progress integration run rather than stacking.
2026-03-16 22:59:15 -05:00
Your Name ec40c235bb fix: generate random E2E credentials at runtime -- no hardcoded passwords in source
Each CI run generates a fresh random password with openssl rand, writes it to
GITHUB_ENV, and passes it to both create-e2e-user.sh and Playwright. The test
user is ephemeral (container torn down after the run) but the password is now
unique per run and never committed to source.

Previously KimaE2ETest2026! was hardcoded as a fallback -- an admin account
backdoor anyone with repo access could exploit on a production instance that
had run the setup script.
2026-03-16 22:54:31 -05:00
Your Name 4080426cbb fix: nightly -- global setup falls back to default creds, add issues:write permission 2026-03-16 22:52:15 -05:00
Your Name 92ab5f8c88 fix: bump E2E job timeout to 60 min -- cold Docker build takes ~10 min for ML model downloads 2026-03-16 19:20:28 -05:00
Your Name 602e81c6b4 fix: CI E2E credentials -- fall back to default test user when secrets not set 2026-03-16 18:47:31 -05:00
Your Name 9083835bfd chore: v1.7.0 -- vibe galaxy, CI pipeline, enrichment hardening, PWA, preprod sweep
- Bump frontend and backend to 1.7.0
- Update CHANGELOG with full 1.7.0 release notes
- Remove vibe-test dev prototype page and unused R3F components
  (VibeUniverse, TrackCloud, TrackTooltip, universeUtils)
- Fix stale audio.completed counter: flush live DB count at isFullyComplete
  transition -- counter was frozen at last audioQueued > 0 cycle value
- Add GitHub Actions CI pipeline: lint/typecheck, unit tests, security scan,
  E2E predeploy, nightly Docker build and push to Hub + GHCR
- Add E2E enrichment cycle spec with 55-min timeout and memory monitoring script
- Add E2E vibe spec covering map, song path, search, alchemy, similar tracks
- PWA hardening: offline fallback, update banner, WCO, manifest fixes
- Production readiness: OOM memory caps in both compose files, DoS/SSRF/auth fixes
- Remove double-auth in systemSettings (requireAdmin already enforces auth)
- Fix mobile vibe page full-height rendering, vibe map timer leak, abort signal wiring
- Fix E2E test helpers: graceful skip with waitFor + try/catch for empty-library CI
- Fix create-e2e-user.sh: admin role, bcrypt shell expansion, psql heredoc quoting
2026-03-16 18:25:08 -05:00
Your Name c9ccd97eb9 test: replace theater tests with real security and route tests
Remove:
- api-contracts.spec.ts (100% theater -- shape checks with no bug-catching value)

Add auth middleware unit tests (backend/src/middleware/__tests__/auth.test.ts):
- 14 tests covering real code branches: missing header, wrong scheme,
  empty token, expired JWT, tokenVersion mismatch (password-change
  invalidation), legacy token without tokenVersion claim, deleted user,
  requireAdmin 401/403 distinction, requireAuthOrToken query param path
- All tests assert on observable behavior that would fail if specific
  lines of production code were removed

Add supertest route integration tests with mocked Prisma:
- auth.route.test.ts: login shape (no passwordHash in response), token
  claims verification, no username enumeration (identical 401 for wrong
  password and nonexistent user), refresh tokenVersion mismatch, role
  injection rejected, admin-only endpoint 403 enforcement
- playlists.route.test.ts: IDOR for GET/PUT/DELETE -- each test asserts
  BOTH the 403 status AND that the DB write was not called (catches
  ownership check removed or moved after the mutation)

Enhance security.spec.ts (e2e against real Docker stack):
- IDOR: add PUT and DELETE scenarios (not just read)
- All IDOR tests now verify state after failed attempt (re-fetch confirms
  resource unchanged/still exists -- not just checking status code)
- Enforce 403 specifically (not [403, 404]) -- 404 masks broken auth checks
- Add img onerror XSS vector alongside script tag vector
- Input validation: verify playlist count unchanged after 400
- Error response: add prisma/ORM internals to leakage checks

Add test infrastructure:
- src/__mocks__/test-env.cjs: sets JWT_SECRET before module load (setupFiles)
- jest.config.js: add setupFiles entry
- supertest + @types/supertest added to backend devDependencies
2026-03-16 11:20:30 -05:00
Your Name d6e414f2d1 ci: add full test suite and GitHub Actions CI agents
- Rewrite pr-checks.yml: typecheck (frontend + backend), backend unit
  tests (Jest, webhookEventStore excluded), dep audit, Docker build gate
- Add integration.yml: Docker stack + Playwright e2e on push to main or
  run-e2e label (predeploy, queue, playlists, api-contracts, security)
- Add nightly.yml: full Playwright suite at 03:00 UTC, opens GH issue on
  failure
- Add security.yml: npm audit blocking on critical + security.spec.ts
  against Docker stack on PRs and weekly

New tests:
- security.spec.ts: IDOR, XSS, unauthenticated access, input validation,
  mass assignment (12 tests, all verified against localhost:3030)
- api-contracts.spec.ts: auth shapes, CRUD contracts, library/search
  validation, health check (15 tests, all verified)
- playlists.spec.ts, queue.spec.ts: functional e2e tests
- global.setup.ts: shared auth token setup

Backend fixes:
- Fix discoverySeeding tests: add _max.playedAt to recentPlays mocks,
  sync getFallbackSeedArtists mock to new artist.findMany+albums path,
  add unavailableAlbum to Prisma mock factory
- Fix enrichmentStateMachine tests: add clearGate to mock, update
  orphaned-audio assertion to match new where clause
- Add p-queue.cjs CJS mock + moduleNameMapper (pure ESM incompatible
  with Jest CJS runner)
- Add typecheck scripts to frontend/backend package.json

scripts/create-e2e-user.sh: fix bcrypt hash corruption by passing
password via Docker -e env var instead of shell interpolation
2026-03-16 10:42:20 -05:00
Your Name cd84509509 fix(ci): lowercase GHCR image name to comply with OCI naming rules
github.repository_owner preserves casing but GHCR requires all-lowercase.
Compute image name at runtime using bash lowercase conversion.
2026-02-28 22:09:09 -06:00
Your Name 97c3d711a6 feat(ci): publish Docker image to GHCR alongside Docker Hub (#48)
Adds GitHub Container Registry as a second publish target on release.
Users can now pull from ghcr.io as an alternative to Docker Hub,
avoiding Docker Hub's pull rate limits.

Based on PR #48 by @SupremeMortal, adapted for kima naming.
2026-02-28 21:35:42 -06:00
Your Name d67c8f49ef release: v1.5.7
BullMQ enrichment migration
- Rewrote enrichment pipeline on BullMQ v5: artist, track, podcast workers with
  pause/resume/stop support and Bull Board visibility
- Essentia publishes audio:analysis:complete events; CLAP subscribes reactively
  instead of polling (eliminates scan delay between phases)
- Thread-safe DB pool in CLAP worker, all DB calls in run_in_executor
- Fixed psycopg2.pool submodule import crash on BullMQ vibe worker startup
- Silenced EnrichmentStateService disconnect error on already-closed Redis conn

Enrichment fixes
- lastfmTags NULL caused mood-tags phase to silently skip all tracks; migration
  backfills NULL -> '{}' and sets column default
- Cover art fetch errors for temp-MBID albums (temp-* passed to Cover Art Archive)
- VIBE-VOCAB vocabulary JSON not copied to Docker image (TypeScript omits .json)
- Wired cleanupOldResolved() to run daily; added missing enrichment status indexes
- Fixed circuit breaker reset, orphan cleanup, podcast entityType, hang detection

Soulseek
- Track search-page downloads in activity tracker
- Use async fs.promises.access instead of synchronous existsSync
- Verify file exists on disk before emitting download:complete (#110)

Docker image size: 28.4 GB -> 12.2 GB
- Removed all CUDA/NVIDIA dependencies; switched to CPU-only PyTorch/TensorFlow
- tensorflow-cpu + essentia-tensorflow --no-deps (avoids GPU TF transitive dep)
- Fixed .dockerignore: **/node_modules and **/.next now excluded from build context

PWA / mobile
- Background audio session loss on iOS/Android: SilenceKeepalive singleton,
  tryResume() in MediaSession play handler, direct track load on 'ended' event,
  visibilitychange/pageshow foreground recovery
- Lock orientation to portrait for Android device lock (#117)

Discovery
- Retry All re-importing albums already in library: apply same three-level filter
  as GET /current before creating download jobs; delete stale UnavailableAlbum
  records for already-present albums. Closes #34

CI / release
- linux/arm64 added to release and nightly Docker builds (#87)
- Isolated release CI from nightly GHA cache (cache-from/cache-to removed from
  docker-publish.yml to guarantee clean release builds)
- Redis vm.overcommit_memory=1 sysctl added to prod and server compose files

Other fixes
- Cross-artist album fallback by title+year prevents library splitting (#50)
- Retry temp-MBID artists after 24h not 7 days; hide temp MBIDs from API (#112)
- 3-attempt ECONNRESET retry on all Deezer getPlaylist call sites (#119)
- check response.ok on health probe — fetch does not throw on 5xx (#104)
- Z-index stacking hierarchy established (MiniPlayer through OverlayPlayer)
- API token display overflow on iPhone (min-w-0/overflow-hidden on flex container)
2026-02-23 17:19:46 -06:00
Your Name e1c3fea68c ci: allow manual trigger of nightly build 2026-02-17 20:16:59 -06:00
Your Name cc434bc592 ci: rebrand GitHub workflows and templates to Kima 2026-02-16 09:41:18 -06:00
Your Name abea0d19f7 fix: remove dynamic expression from workflow name 2026-01-22 10:03:18 -06:00
Your Name 0ac805b6fc chore: Release v1.3.3 - Critical bug fixes and QoL improvements
Critical Fixes:
- Docker permissions for PostgreSQL/Redis bind mounts
  Fixes #59, fixes #62
- Audio analyzer memory consumption and OOM crashes
  Fixes #21, fixes #26, fixes #53
- LastFM array normalization preventing .map crashes
  Fixes #37, fixes #39
- Wikidata 403 errors from missing User-Agent
  Fixes #57
- Singles directory creation race conditions
  Fixes #58
- Firefox FLAC playback stopping at ~4:34 mark
  Fixes #42, fixes #17

Quality of Life:
- Add Releases link to desktop sidebar navigation
  Fixes #41
- iPhone safe area insets for Dynamic Island/notch
  Fixes #54

Contributors: @arsaboo, @rustyricky, @RustyJonez, @tombatossals

No regressions detected, backward compatible, production ready.
2026-01-09 18:46:16 -06:00
Your Name cc8d0f6969 Release v1.3.0: Multi-source downloads, audio analyzer resilience, mobile improvements
Major Features:
- Multi-source download system (Soulseek/Lidarr with fallback)
- Configurable enrichment speed control (1-5x)
- Mobile touch drag support for seek sliders
- iOS PWA media controls (Control Center, Lock Screen)
- Artist name alias resolution via Last.fm
- Circuit breaker pattern for audio analysis

Critical Fixes:
- Audio analyzer stability (non-ASCII, BrokenProcessPool, OOM)
- Discovery system race conditions and import failures
- Radio decade categorization using originalYear
- LastFM API response normalization
- Mood bucket infinite loop prevention

Security:
- Bull Board admin authentication
- Lidarr webhook signature verification
- JWT token expiration and refresh
- Encryption key validation on startup

Closes #2, #6, #9, #13, #21, #26, #31, #34, #35, #37, #40, #43
2026-01-06 20:07:33 -06:00
Kevin O'Neill 9e59f92fa7 v1.0.2: Mood mix optimizations and media player improvements
- Fixed player seek flicker on podcasts (30s skip buttons)
- Added dual-layer seek lock mechanism to prevent stale time updates
- Optimized cached podcast seeking (direct seek before reload fallback)
- Large skips now execute immediately for responsive feel
- Mood mix performance optimizations
2025-12-26 13:14:32 -06:00
Kevin O'Neill 021aec7a63 Initial release v1.0.0 2025-12-25 18:58:06 -06:00