# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- **Listening history can now be recorded**: Added `POST /music/history/:trackId` so an authenticated client can append a play to a user's listening history. `ListeningHistoryService.recordPlay` resolves track metadata from the cache and upserts the `DeezerTrack` row (mirroring `FavoritesService.addFavorite`) before inserting a `PlayHistoryEntry`, so `GET /music/history`, `/music/history/recent`, and `/music/history/stats` finally return data. Previously the listening-history module exposed only read and clear routes and no code path ever wrote a `PlayHistoryEntry`.

### Changed

- **Canonical API pool no longer requires Vercel env**: API configuration, production startup validation, Worker deploys, origin readiness checks, and Vercel cluster sync now tolerate missing `API_URLS` by using `src/config/canonical-api-origins.json` as the code-defined cluster source of truth. `API_URLS` remains available only as a deliberate override and must match the canonical order when set.
- **Spotify and Last.fm provider values now prefer runtime DB config**: Spotify client ID/secret/redirect URI and Last.fm API key/shared secret/application metadata can now be set through the runtime config control plane and applied across the cluster. Env values are optional bootstrap fallbacks, with `preferEnv` available per key when a node should deliberately use env over DB.
- **Blob storage configuration is now hot-swappable**: `BLOB_READ_WRITE_TOKEN` and `CLUSTERED_STREAM_BLOB_CACHE` resolve through DB-backed runtime config with env fallback, and runtime value updates refresh the local blob client state immediately so shared stream chunk storage no longer needs a redeploy for token rotation or cache toggles.
- **Clustered stream tuning is now hot-swappable**: session TTL, L1 chunk cache size/count/TTL, and Redis materialization lock timing now resolve through DB-backed runtime config with env fallback, and runtime updates refresh the live streaming service without redeploying API nodes.
- **Runtime value batches can now be orchestrated through the hub**: protected cluster runtime updates now accept multiple allowlisted values in one request, so the frontend admin panel can apply coordinated streaming profiles across all API nodes as a single operation.
- **Runtime value reads are now hub-orchestrated**: protected cluster runtime value reads now fan out from the API hub to configured peers, giving the frontend admin panel one consolidated cluster view without owning node-to-node probing.
- **Cluster runtime value reads sanitize peer payloads defensively**: the hub strips unexpected raw values from secret entries while preserving public, raw-readable config values and safe metadata.
- **Cluster runtime value writes now fan out concurrently**: protected hub-owned runtime value updates still attempt every configured API node and preserve result ordering, but peer writes launch together so admin changes and stream-profile updates settle across the cluster faster without adding another env-controlled knob.
- **Cluster runtime value batches reuse peer service tokens**: multi-value runtime updates now mint at most one service bearer per peer for the request, reducing hub-to-node control-plane chatter while keeping existing token TTLs, env fallbacks, and per-node result visibility.
- **Cluster runtime value batches now use peer batch apply routes**: the hub sends one multi-value write to each peer that supports `/ops/runtime/values`, keeps safe per-key/per-node results, and falls back to existing per-key writes for older API nodes.
- **Clustered stream sessions now prime local chunks before returning**: session creation fills the node-local L1 chunk cache immediately and schedules shared encrypted Blob materialization through the existing coalesced/Redis-lock path, reducing cold-start waits without dropping peer-readable chunk storage.
- **Decrypted track buffer downloads now coalesce locally**: concurrent same-track/same-quality buffer requests share one in-flight Deezer download before the decrypted L1 cache is warm, and stream capabilities now report decrypted-buffer `localInFlight` for diagnostics.
- **Clustered chunk fallback now coordinates through Redis**: cold peer chunk requests that miss L1 and encrypted Blob now wait on or acquire the same materialization lock used by session warmup. The lock winner materializes the full chunk plan, so peers converge on shared encrypted chunks instead of each uploading one isolated fallback chunk.
- **Decrypted stream cache metrics are now exposed**: decrypted buffer cache hits, misses, in-flight joins, and download failures are tracked in `MusicStreamingService`, included in protected node capabilities, and exported from `/ops/metrics` as Prometheus counters/gauges.
- **Metadata cache metrics are now exposed**: `MetadataCacheService` now tracks cache hits, misses, in-flight joins, provider failures, and not-found/error responses, includes them in cache stats, and exports Prometheus counters/gauges through `/ops/metrics`.
- **Deezer lookup cache metrics are now exposed**: `DeezerService` now tracks track-ID cache hits, misses, negative-result hits, and expired entries, includes them in cache stats, and exports Prometheus counters through `/ops/metrics`.
- **Spotify cache metrics are now exposed**: `SpotifyService` now tracks search, recommendations, and other cache hits, misses, and expirations, includes them in cache stats, and exports Prometheus counters/gauges through `/ops/metrics`.
- **Auth session and rate-limit metrics are now exposed**: `SpotifyPkceSessionStoreService` now tracks safe session-store writes/consume outcomes, `AuthRateLimitGuard` tracks bucket hit/miss and allow/block behavior, and both are included in cache stats plus Prometheus counters/gauges through `/ops/metrics`.
- **Node metadata is now exposed in ops metrics**: `/ops/metrics` now emits Prometheus-safe `node_info` and `node_role_info` gauges for node ID, version, provider, region, runtime, git SHA, and route roles so cluster metrics can be grouped without relying on frontend-side inference.
- **Route latency and status metrics are now exposed**: `OpsMetricsMiddleware` now records always-on HTTP route counts and cumulative duration buckets, while `/ops/metrics` exports request totals, status classes, duration histograms, and cardinality pressure gauges.
- **Stream HTTP error counters are now exposed**: `OpsMetricsService` now records stream-specific HTTP errors by method, route, status, and status class, exporting `stream_http_errors_total` and stream error cardinality gauges from `/ops/metrics`.
- **Cache hit-rate gauges are now exposed**: `/ops/metrics` now exports precomputed hit-rate gauges for Spotify, Deezer, metadata, auth PKCE consumes, auth rate-limit buckets, decrypted stream buffers, and clustered stream L1/Blob chunk caches.
- **External API latency metrics are now exposed**: `OpsExternalHttpMetricsService` instruments Axios-backed upstream calls across API modules, and `/ops/metrics` exports request totals and duration histograms by provider, host, method, and status without storing request paths or query strings.
- **Cluster server diagnostics now include recent probe stats**: `/ops/cluster/servers` attaches rolling per-origin sample count, p50/p95 latency, recent error rate, last successful probe, and deploy/runtime age metadata so admin clients can render origin health without probing every node themselves.
- **Node capabilities now include safe ops alerts**: protected node diagnostics synthesize alert metadata for database unavailability/high latency, Redis unavailability/high latency, and incomplete Spotify, Last.fm, or Deezer provider configuration without exposing raw secrets, URLs, or failure details.
- **Track metadata cache now has shared Redis L2**: `MetadataCacheService` keeps its node-local L1 and in-flight join behavior, then uses Redis as a shared L2 plus a short distributed lock when configured so clustered nodes avoid duplicate Deezer metadata calls during cold queue and stream warmups. `/ops/metrics` now exports the shared metadata cache and lock counters.
- **REDIS_URL now resolves through DB-backed runtime config**: `REDIS_URL` is an allowlisted metadata-only secret in the ops runtime-values catalog, defaults to DB preference over bootstrap env, refreshes Redis clients in-place after updates, and remains env-compatible when no DB value exists or `preferEnv` is deliberately enabled.
- **REDIS_CACHE_URL now supports per-node cache Redis**: metadata cache Redis resolves from a node-scoped DB key first, then shared `REDIS_CACHE_URL`, then shared `REDIS_URL`, allowing cache-only Redis instances to differ per API node while coordination, auth, locks, and runtime secrets keep using the shared Redis URL.
- **Node purpose options are now DB-backed per node**: protected ops routes can persist public node options under per-node runtime config keys, public config and node capabilities expose purpose/roles/weight/disabled/notes metadata, and diagnostics can show what each origin is intended to do without relying on more Vercel env values.

### Fixed

- **API hub origin pool is now guarded as a canonical 12-node contract**: Added a shared canonical production origin list covering `songbirdapi.com`, `darkfloor.one`, and `zero` through `nine.darkfloor.art`; production API startup, Vercel replica env sync, Cloudflare Worker deploys, origin readiness checks, and edge verification now all validate that exact order so the public hub cannot quietly ship a 10-node `/cluster/sync` summary while protected node diagnostics see all 12 nodes.

## [1.10.11] - 2026-05-07

### Added

- **Runtime Deezer ARL rotation for API nodes**: Added protected `POST`/`PUT` routes at `/ops/deezer/arl` and `/api/v2/ops/deezer/arl` so admin tooling can replace the active streaming ARL on each node without redeploying. Successful updates reinitialize `@soulwax/d-fi-core`, clear stream caches, return only safe metadata/fingerprints, and persist the override through Redis when `REDIS_URL` is configured so serverless cold starts recover the rotated credential.
- **Vercel cluster sync covers zero through nine by default**: The Vercel replica defaults and production origin inventory now include `eight.darkfloor.art` and `nine.darkfloor.art`, keeping sync, readiness checks, and documented `API_URLS` aligned with the full numbered cluster.

## [1.10.10] - 2026-05-05

### Added

- **Vercel cluster sync renders per-instance Worker primary origins**: `scripts/sync-vercel-cluster.js` now includes `seven.darkfloor.art` in the default Vercel replica set and renders `CF_WORKER_PRIMARY_ORIGIN` per target host, so each Vercel cluster instance points Worker metadata at its own public origin during env sync.
- **Vercel cluster sync targets real dotted cluster project names by default**: The Vercel project template now defaults to `{host}` so numbered `*.darkfloor.art` replicas sync to the existing production cluster projects instead of dash-slug lookalikes.
- **Vercel cluster sync keeps Worker deploy credentials local**: `CF_API_TOKEN` and `CLOUDFLARE_API_TOKEN` are now excluded from Vercel cluster env sync so Cloudflare deployment credentials are not pushed into API replica runtimes.
- **Vercel cluster sync accepts pnpm argument separators**: `scripts/sync-vercel-cluster.js` now ignores a standalone `--`, so `pnpm vercel:cluster:sync -- --dry-run` works like the other cluster scripts.
- **Vercel cluster sync caps serverless DB pools by default**: Replica env rendering now adds conservative `DB_POOL_*` defaults unless the source env overrides them, reducing the chance that many warm serverless nodes exhaust the shared Postgres connection limit.
- **Vercel deployments exclude all local env files**: `.vercelignore` now excludes every `.env*` file except `.env.example`, preventing scratch or per-host env files from being uploaded with serverless deployments.
- **Edge cluster verification command**: Added `pnpm cluster:edge:check` to validate the Worker sync payload, fail when read-path Worker routing headers are missing, probe each configured origin directly, and collect repeated p50/p95 latency samples for routing and cold-start baselines.
- **Origin rollout readiness command**: Added `pnpm cluster:origins:check` to read `API_URLS`, gently probe every origin for `/config/public`, `/health/ready`, and `/cluster/sync`, verify public `APP_URL` alignment and expected origin count, and optionally fail when an origin's own cluster view is not fully healthy and in sync.
- **Protected node capabilities diagnostics**: Added `GET /ops/node/capabilities` and `/api/v2/ops/node/capabilities` for scoped ops/service-token diagnostics covering node identity, version/git metadata, runtime, roles, DB/Redis connectivity, provider configuration flags, cache stats, and stream capability flags without exposing raw env values.
- **HOST-driven replica runtime config**: API replicas can now set a single `HOST` value and derive `APP_URL`, `AUTH_COOKIE_DOMAIN`, `AUTH_FRONTEND_SUCCESS_REDIRECT`, `SPOTIFY_REDIRECT_URI`, and Worker primary origin at runtime. Literal shell templates such as `${HOST_URL}` are ignored so copied Vercel env values do not become broken public URLs.
- **Worker health probe timeout is configurable**: The Cloudflare Worker deploy now renders `CF_WORKER_HEALTH_TIMEOUT_MS` into the edge hub, defaulting to `6000ms` so cold Vercel replicas have enough time to answer diagnostics without affecting normal user-request retry budgets.
- **Cloudflare Worker route-aware origin metadata**: The Worker deploy script now derives role, weight, runtime, region, and auth/stream safety metadata from `API_URLS`, accepts either `CF_API_TOKEN` or `CLOUDFLARE_API_TOKEN`, defaults the Worker reference origin to the first `API_URLS` entry unless a concrete `CF_WORKER_PRIMARY_ORIGIN` explicitly overrides it, ignores Vercel render templates such as `https://{host}`, and the edge hub uses that metadata to route `read`, `write`, `auth`, `stream`, and `ops` traffic through the appropriate origin set while exposing selected origin, route role, attempt count, request correlation headers, cached cluster-sync status, per-origin probe latency, and safe routing metadata.

## [1.10.9] - 2026-05-04

### Added

- **Oxmgr process management support**: Added `oxfile.toml`, backend-local `oxmgr:*` package scripts, and an Oxmgr lifecycle helper so the API can be validated, started, reloaded, restarted, logged, and inspected alongside the existing PM2 flow. Backend AI/tooling guidance now treats Oxmgr as the default local production process manager and PM2 as deprecated legacy/migration tooling.
- **Standalone API Oxmgr refresh command**: Added `pnpm oxmgr:run` for API-only cluster nodes; it runs a frozen install, builds the backend, and dynamically restarts or applies the `darkfloor-api-v2` Oxmgr process.
- **Vercel Git deploy commands in source control**: Declared the backend Vercel framework preset, frozen pnpm install command, and Prisma generation build command in `vercel.json` so Vercel-backed API clusters have consistent behavior on Git pushes.
- **Cluster diagnostics env guidance**: Documented `API_URLS` and `API_SYNC_TIMEOUT_MS` in the sample API environment and clarified that one-node diagnostics usually means the API runtime has no origin pool configured.

### Fixed

- **Generated preview images now canonicalize Darkfloor branding to `darkfloor.org`**: The preview renderer now honors the frontend proxy's public-origin hint and maps legacy `darkfloor.one` hosts to `darkfloor.org` for default and song images.
- **Oxmgr API start now handles stale local production listeners during migration**: The backend Oxmgr helper now clears stale repo-local API processes that still own the configured port before applying a missing process, avoiding readiness failures caused by orphaned Node servers.
- **Oxmgr API restarts no longer depend on daemon PATH state**: The backend Oxmgr helper now applies resolved configs with an absolute working directory and the active Node executable before restarting, fixing `failed to spawn node` under a user-space systemd Oxmgr daemon.

## [1.10.0] - 2026-03-31

### Added

- **Local-dev auth rate limit configuration**: Added `AUTH_RATE_LIMIT_LOCAL_DEV_WINDOW_MS`, `AUTH_RATE_LIMIT_LOCAL_DEV_MAX`, and `AUTH_RATE_LIMIT_LOCAL_DEV_ELECTRON_MAX` so trusted localhost auth flows can use a much softer budget than public traffic.
- **Auth guard coverage for local frontend and Electron hints**: Added focused unit coverage for loopback callback targets, forwarded `localhost:3222` host headers, and Electron-marked local auth requests.

### Changed

- **Lenient auth throttling for localhost `:3222`**: Authentication rate limiting now distinguishes direct loopback traffic from trusted local frontend requests and applies a substantially higher allowance for requests clearly tied to `http://localhost:3222` or `http://127.0.0.1:3222`.
- **Electron-aware local auth throttling**: Requests carrying the `is-electron: true` hint now receive the most permissive local-development auth budget instead of sharing the normal external limit.
- **Forwarded auth request hints**: The frontend auth proxy and Spotify auth client now forward or synthesize the `is-electron` header so local Electron auth/session refresh traffic is identified correctly by the API.
- **Version bump**: Bumped application version from `1.9.4` to `1.10.0`.

## [1.9.3] - 2026-03-02

### Fixed

- **Body-based Spotify refresh token rotation for frontend clients**: `POST /auth/spotify/refresh` now returns the rotated `refreshToken` when the request uses body token fallback (`{ "refreshToken": "..." }`), allowing cross-origin/non-cookie clients to continue refreshing sessions beyond a single rotation.

### Changed

- **Refresh response payload convenience fields**: Refresh responses now also include flat Spotify token fields (`spotifyAccessToken`, `spotifyTokenType`, `spotifyExpiresIn`) in addition to the existing nested `spotify` object for easier frontend consumption.

## [1.9.2] - 2026-03-02

### Added

- **Vercel deployment runbook**: Added a dedicated `VERCEL_DEPLOYMENT.md` with project-linking, environment variable checklist, deploy steps, and post-deploy verification commands.

### Changed

- **Vercel build/install determinism**: Switched Vercel install/build commands to pnpm (`pnpm install --frozen-lockfile`, `pnpm run prisma:generate`) for lockfile-consistent deployments.
- **Vercel function runtime limits**: Added explicit function settings for `api/index.ts` (`memory: 1024`, `maxDuration: 30`) in `vercel.json`.
- **Public URL inference on Vercel**: Config now derives `appUrl` from `VERCEL_PROJECT_PRODUCTION_URL` or `VERCEL_URL` when `APP_URL` is not set, so generated docs/links use a real deployment URL instead of localhost.
- **Node runtime contract**: Added `engines.node` (`>=22 <26`) to make runtime expectations explicit for CI/CD and platform builds.

## [1.9.1] - 2026-03-02

### Fixed

- **Electron loopback OAuth refresh continuity**: Spotify callback handoff now includes `refresh_token` for trusted loopback frontend redirects (`localhost`/`127.0.0.1`/`::1`) in addition to native schemes, enabling desktop clients to refresh sessions without relying on readable CSRF cookies across origins.

### Changed

- **Refresh token handoff documentation**: Clarified `.env.sample` that `AUTH_FRONTEND_NATIVE_INCLUDE_REFRESH_TOKEN` controls refresh-token inclusion for both native and loopback callback targets.

## [1.9.0] - 2026-03-01

### Added

- **Native OAuth Redirect Allowlist**: Added `AUTH_FRONTEND_NATIVE_SCHEMES` to explicitly allow non-HTTP(S) frontend callback schemes (for example Electron deep links such as `darkfloor://...`) during Spotify PKCE login handoff.
- **Native Refresh Token Handoff Toggle**: Added `AUTH_FRONTEND_NATIVE_INCLUDE_REFRESH_TOKEN` to control whether native redirect payloads include `refresh_token` for non-cookie clients.

### Changed

- **Spotify OAuth Redirect Validation**: `frontend_redirect_uri` now validates HTTP(S) targets against `AUTH_FRONTEND_ORIGINS` and native scheme targets against `AUTH_FRONTEND_NATIVE_SCHEMES`.
- **Electron/Desktop OAuth Completion**: Native `frontend_redirect_uri` handoff now includes app refresh tokens by default so desktop clients can call `/api/auth/spotify/refresh` using body token fallback without relying on API-domain cookies.
- **Auth Redirect Log Redaction**: Callback redirect diagnostics now treat `refresh_token` as sensitive and redact it in logs.

## [1.8.3] - 2026-02-25

### Changed

- **Music Metadata Batch Efficiency**: `/music/tracks/batch` now uses the shared metadata cache with request de-duplication to reduce repeated Deezer API calls.
- **Playlist Mutation Throughput**: Playlist add/remove/reorder flows now use indexed bulk order updates and lighter pre-check queries to reduce DB work on large playlists.
- **Listening Stats Aggregation**: `/music/history/stats` now computes totals and top lists via database grouping with targeted track hydration instead of loading full history rows.
- **Playlist Conversion Throughput**: `/music/convert/playlist` now avoids per-track Deezer detail fan-out and batches Spotify track detail lookups via `/v1/tracks?ids=...`.
- **Artist/Album Track Fetching**: Artist/album music routes now fetch per-track Deezer details only when required fields are missing from base results.

### Fixed

- **Favorites Duplicate Handling**: Favorite add/remove now relies on atomic database outcomes (`P2002` conflict handling and delete-count checks) to avoid race-prone pre-check flows.
- **Batch Favorite Input Sanitization**: `POST /music/favorites/batch-check` now safely handles empty `trackIds` input and normalizes repeated/whitespace IDs before querying.

## [1.8.2] - 2026-02-25

### Added

- **Shared Auth Cookie Utility**: Added `parseCookieKeys()` helper used across auth handlers to avoid repeated cookie-header parsing logic.
- **Shared Deezer Metadata Mapper**: Added a reusable Deezer track → `ExtendedTrackMetadata` mapper for music services.

### Changed

- **Auth Debug Logging**: Replaced temporary `console.log` traces in auth callback/guard flows with structured Nest `Logger` calls.
- **Runtime Logging Consistency**: Standardized core logging in bootstrap, startup, auth module fallback warnings, and preview controller diagnostics to use Nest logger APIs.
- **Music Service Type Safety**: Tightened playlist/listening-history/favorites typing by replacing loose `any` usage with Prisma-backed typed structures.
- **Legacy Spotify Import Typing**: Added explicit Deezer response/match interfaces in playlist import flow to remove `Promise<any>` paths.
- **HexMusic Contract Typing**: Added explicit typed return contracts for playlist recommendation/search flows and explicit Prisma JSON persistence boundaries.
- **Crypto Fallback Typing**: Hardened Blowfish fallback module typing in Deezer integration and reduced unsafe dynamic import typing.
- **Base Type Hygiene**: Updated `DeezerTrack` index signature to `unknown` instead of `any`.

### Fixed

- **Duplicate Utility Logic**: Removed duplicated cookie parsing methods from auth controller and Spotify auth guard.
- **Repeated Metadata Mapping**: Removed repeated Deezer metadata object construction across multiple music services.

## [1.8.1] - 2026-02-23

### Added

- **Vercel OIDC Environment Placeholder**: Added `VERCEL_OIDC_TOKEN=<auto_injected_by_vercel>` to `.env.sample` under platform notes for clearer Vercel runtime expectations.

### Changed

- **Root Landing Route Resilience**: `GET /` now serves an inline fallback HTML portal if template rendering fails, avoiding runtime redirects and preserving direct homepage access.
- **Landing Page Error Path**: Updated landing-page controller tests to cover callback-based rendering and fallback HTML behavior.

### Fixed

- **Serverless View Resolution**: Bootstrap now resolves views from multiple candidate directories (`__dirname/views`, `src/views`, `dist/views`) to better support bundled/serverless runtime layouts.
- **Vercel Docs Asset Packaging**: Updated `vercel.json` to include `src/views/**` and `node_modules/swagger-ui-dist/**` in the function bundle so docs/landing assets are available at runtime.

## [1.8.0] - 2026-02-22

### Added

- **Typed Landing Page Template**: Added `src/landing-page.template.ts` and extracted the root-page UI rendering out of `AppService` into a dedicated, testable template module.
- **Runtime URL Utility**: Added `src/common/config/runtime-url.util.ts` to centralize `APP_URL`/port resolution and absolute URL construction.
- **ESLint TSConfig**: Added `tsconfig.eslint.json` to provide type-aware lint coverage for both `src/**/*.ts` and `test/**/*.ts`.

### Changed

- **APP_URL Precedence**: Standardized URL depiction to prioritize `APP_URL` across the landing page, Swagger/OpenAPI server metadata, startup logging, and public config output.
- **Landing Page Rework**: Rebuilt the entire front page with a new layout, clearer docs/spec access, and a route explorer that prefers the absolute OpenAPI URL derived from `APP_URL`.
- **Route Metadata Response**: `GET /routes` now computes totals and module counts dynamically and includes resolved docs/spec URL fields.
- **Swagger Server Listing**: Swagger now marks `APP_URL` as the primary public server and only adds localhost as an extra server in non-production environments.
- **Config Normalization**: `appUrl` config now trims trailing slashes for consistent URL joining.
- **Lint Parser Configuration**: ESLint now uses `tsconfig.eslint.json` via `parserOptions.project`, resolving IDE parser errors for spec files.

### Fixed

- **Strict TypeScript Decorator Imports**: Updated Express request/response imports in the Deezer preview controller to `import type` for strict decorator metadata compatibility.
- **Controller Typing Hygiene**: Tightened root controller typings (explicit return typing and nullish-coalescing cleanup) and refreshed tests to match the new landing page output.

## [1.7.2] - 2026-02-20

### Added

- **Service Token Exchange Endpoint**: Added `POST /auth/token` and `POST /api/auth/token` to exchange `UNIVERSAL_KEY` for a short-lived bearer token.
- **Scoped Service Token Routing**: Added scoped service-token support for `GET /auth/me` and `GET /cache/stats` (and their `/api/*` aliases) via route metadata.
- **Config Option**: Added optional `AUTH_SERVICE_TOKEN_TTL_SECONDS` environment variable for service-token TTL control.
- **Auth Coverage**: Added auth unit tests for service-token issuance and JWT strategy service-token validation.
- **Frontend Handoff**: Added `NEXTJS_AGENT_HANDOFF.md` with exact Next.js integration steps for token exchange and `/auth/me` + `/cache/stats` proxying.

### Changed

- **JWT Guard Behavior**: JWT guard now enforces service-token route allowlisting and scope checks to avoid broad access on unrelated protected routes.
- **Auth Profile Endpoint**: `GET /auth/me` now returns service-token context when authenticated by the new service token flow.
- **V2 Auth/Ops Route Aliases**: Added explicit aliases for `GET /api/v2/auth/me` and `GET /api/v2/cache/stats`.
- **PKCE Token Exchange**: Spotify PKCE token/refresh exchanges now omit `client_secret` and rely on `client_id + code_verifier` flow.
- **Token Logging Hygiene**: Startup Spotify access token logs are now redacted.

## [1.7.1] - 2026-02-19

### Changed

- **Auth Deployment Guidance**: Clarified `.env.sample` notes for frontend/API auth integration, including CSP `connect-src` requirements for cross-origin `/api/auth/me` and refresh calls.
- **Redis PKCE Configuration Note**: Clarified that Spotify PKCE serverless storage reads `REDIS_URL` only and supports TLS Redis URLs (`rediss://...`, including Upstash).

## [1.7.0] - 2026-02-19

### Added

- **Spotify OAuth2 + PKCE Flow**: Added secure authorization code flow endpoints `GET /api/auth/spotify` and `GET /api/auth/spotify/callback` with per-request PKCE verifier/challenge generation and state validation.
- **Session Refresh Endpoint**: Added `POST /api/auth/spotify/refresh` with app JWT reissue, refresh-token rotation, and automatic Spotify access token refresh.
- **Auth Hardening**: Added CSRF validation for refresh requests, auth endpoint rate limiting, and encrypted token utilities for sensitive OAuth secrets.
- **Serverless PKCE Store**: Added Redis-backed temporary PKCE session storage with TTL for multi-instance/serverless compatibility and in-memory fallback for local development.

### Changed

- **Auth Profile Endpoint**: `GET /api/auth/me` now returns current user details together with Spotify connection status metadata.
- **Spotify Token Storage**: Spotify refresh tokens are now stored encrypted, and legacy Spotify token refresh logic can read encrypted tokens.
- **CORS + Auth Config**: Added `X-CSRF-Token` as an allowed CORS header and introduced new auth/Spotify environment variables for scopes, cookie policy, rate limits, token encryption, and frontend redirect allowlisting.

## [1.6.1] - 2026-02-11

### Added

- **Readiness Checks**: `/health/ready` now includes database, cache, and external API reachability with structured diagnostics.

### Changed

- **QoL Route Responses**: Version endpoint now returns `{ name, version, commitSha, buildTime }`.

## [1.6.0] - 2026-02-11

### Added

- **Stream Query DTO Validation**: Added query DTOs for `/music/stream` and `/music/stream/direct` with strict type coercion and range checks.
- **Auth/Profile Redaction Tests**: Added unit coverage to ensure user/profile payloads never include passwords.
- **Stream Validation E2E Tests**: Added request-level tests for `/music/stream` query parsing and error responses.

### Changed

- **JWT Secret Handling**: Production now requires `JWT_SECRET` or `UNIVERSAL_KEY`; non-production uses a dev fallback with a warning.
- **Auth/Profile Payloads**: User/profile responses now return a safe, selected user shape (no password hashes).
- **API Key Enforcement**: Streaming endpoints now reject requests when `UNIVERSAL_KEY` is not configured.

## [1.5.4] - 2026-02-11

### Added

- **Deezer Playlist Tracks Endpoint**: Added `GET /api/music/playlists/:id` to fetch all playlist tracks in playlist order.

## [1.5.3] - 2026-02-09

### Added

- **Deezer Latest Releases Endpoint**: Added `GET /api/music/releases/latest` to fetch the newest editorial releases with optional `limit`.
- **Deezer Popular Playlists Endpoint**: Added `GET /api/music/playlists/popular` to fetch charting playlists with optional `limit`.
- **Deezer Playlists by Genre Endpoint**: Added `GET /api/music/playlists/by-genre` (best-effort search by genre, with fallback).
- **Deezer Genres (English) Endpoint**: Added `GET /api/music/genres` to return the Deezer genre list in English.

### Changed

- **Deezer API Base Path**: Renamed the Deezer API routes from `/api/deezer/*` to `/api/music/*`.

## [1.5.2] - 2026-02-07

### Added

- **Public Changelog Endpoint**: Exposed `GET /changelog` to serve `CHANGELOG.md` in Markdown and linked it from the landing page.

## [1.5.1] - 2026-02-07

### Changed

- **Route Reference Section**: Replaced the playful route cards with a concise route list and expandable request/response examples.
- **OpenAPI Sampling**: Improved sample extraction to include parameters, request bodies, and preferred response examples when available.

## [1.5.0] - 2026-02-02

### Added

- **Fileless Decrypted Streaming Cache**: Added an in-memory decrypted track cache to support serverless streaming without filesystem writes, including Range support for cached buffers.
- **Deezer Download Buffer Path**: Added buffer-based download + decrypt + tagging flow to enable fileless streaming.
- **Blowfish ESM Support**: Switched the Blowfish fallback to dynamic `import()` to work in ESM-only environments like Vercel.
- **Queue Sampling Controls**: Added `maxSeeds`, deterministic `sampling`, `seedStride`, and `queueMode` options for spice-up recommendations.

### Changed

- **Serverless Encrypted Streaming**: Encrypted tracks now stream from the decrypted in-memory cache instead of falling back to filesystem downloads.
- **Spice-up Seeding**: All input songs now influence recommendations by chunking seeds into multiple Spotify requests when needed.

## [1.4.1] - 2026-02-02

### Added

- **Spice-up Request Filters**: Added `excludeTrackIds`, `excludeDeezerIds`, and `excludeExplicit` options for Spotify spice-up requests to skip queued or explicit tracks.
- **Spice-up Response Envelope**: Standardized responses to return a consistent `tracks` array with `requestId`, keeping `recommendations` as a deprecated alias.
- **Recommendation Metadata**: Spice-up recommendations now include `deezerId`, deterministic `source`, and optional `reason`/`score` fields for UI.
- **Spice-up Trace Headers**: Responses now include `X-Request-Id` mirroring the body field for easier tracing.
- **Deezer ID Cache**: Added short-lived caching for Deezer track ID resolution to reduce repeated lookups.

### Changed

- **Spotify Track Fields**: Track payloads now include `explicit` and `isrc` when available.
- **Spice-up Responses**: `warnings` is always an array (may be empty) and spice-up POST endpoints return HTTP 200.
- **Spice-up Validation**: Normalize and validate exclusion filters for safer request handling.
- **Test Runs**: Set a localstorage file for Jest to avoid noisy Node warnings.

## [1.4.0] - 2026-01-29

### Changed

- **CORS Loopback Support**: Allow localhost/127.0.0.1/::1 origins (any port, http/https) to enable local health checks and dev tooling.
- **Music Streaming Decryption Fallback**: Added a JS Blowfish fallback to keep `/music/stream` working when OpenSSL legacy ciphers are unavailable, with `egoroof-blowfish` as a dependency.

## [1.3.1] - 2026-01-28

### Added

- **PM2 Cluster Mode Defaults**: Run 4 clustered instances in production with per-instance DB pool environment defaults (`DB_POOL_MAX`, `DB_POOL_MIN`, `DB_POOL_IDLE_TIMEOUT`, `DB_POOL_CONNECTION_TIMEOUT`).

### Changed

- **Prisma PG Pool Configuration**: `PrismaPg` now reads `DB_POOL_*` environment variables to size and tune the Postgres pool for clustered deployments.
- **Preview Image Inputs**: `/api/track/:id/preview` now accepts Deezer track URLs/URIs and uses shared query decoding for more resilient OG requests.
- **Node OpenSSL Compatibility**: Standardized `NODE_OPTIONS=--openssl-legacy-provider` across all primary runtime entrypoints:
  - Updated `npm` scripts (`start`, `dev`, `debug`, `start:prod`) to always launch Node/Nest with `--openssl-legacy-provider`.
  - Ensured PM2 production and development environments set `NODE_OPTIONS=--openssl-legacy-provider` via `ecosystem.config.cjs`.
  - Updated Docker production image to export `NODE_OPTIONS=--openssl-legacy-provider` so containerized runs use the legacy OpenSSL provider by default.

### Fixed

- **OG Preview Image Reliability**: Cover image selection now tries multiple sources (album/track/artist/Deezer md5) with timeouts and fallbacks, and supports non-Deezer track shapes.
- **Streaming Error Clarity**: Deezer download failures now return specific error messages (missing `DEEZER_ARL`/`d-fi-core`, 320kbps not available) instead of a generic upstream error.

## [1.3.0] - 2026-01-14

### Added

- **Default Preview Image Endpoint**: Added `GET /api/preview/default` route that generates a default darkfloor.art preview image featuring the Emily the Strange logo centered (slightly to the north) with "darkfloor.art" and "- lossless music -" text underneath. Uses the same ethereal dark background as track previews.

### Changed

- **Default Preview Image Layout**: Adjusted the default preview image to use a smaller icon (400px max instead of 500px) with increased top margin (60px offset instead of 40px) for better visual balance.
- **Default Preview Image Footer**: Updated footer text from "- lossless music" to "- lossless music -" with dashes on both sides.

### Fixed

- **Build Errors**: Fixed TypeScript compilation errors for Netlify serverless function by:
  - Excluding `netlify` folder from TypeScript build in `tsconfig.build.json`
  - Adding `@ts-expect-error` suppressions for `serverless-http` (no TypeScript definitions) and `dist/src/bootstrap` import (not available during build, only at runtime)
  - Updated `nest-cli.json` to explicitly use `tsconfig.build.json`
  - The Netlify function now compiles separately during Netlify's build process

## [1.2.2] - 2026-01-22

### Added

- **Netlify Deployment Support**: Full serverless deployment configuration for Netlify
  - Created `netlify/functions/api.ts` serverless function handler using `serverless-http`
  - Added `netlify.toml` configuration with routing rules to route all requests to serverless function
  - Configured function timeout to 30 seconds for longer-running operations
  - Added redirect rule to route all paths (`/*`) to `/.netlify/functions/api`
  - Included necessary files (`dist/**`, `node_modules/**`, `prisma/**`) in function bundle
  - Function uses same `createApp()` bootstrap as Vercel for consistency

- **Automatic Serverless Detection for Music Streaming**: Intelligent environment detection
  - Added `isVercelEnvironment()` function to detect Vercel/serverless environments
  - `/music/stream` endpoint automatically switches to direct streaming on Vercel/Netlify
  - No filesystem operations on serverless platforms (streams directly from Deezer)
  - Traditional servers continue using filesystem caching for better performance
  - Same route works everywhere - no code changes needed based on deployment platform

- **Serverless HTTP Support**: Added `serverless-http` package for Netlify compatibility
  - Wraps Express apps for serverless environments
  - Handles Netlify event format conversion automatically
  - Maintains compatibility with existing Express-based NestJS setup

### Changed

- **Node.js Version Requirements**: Updated to support Node.js 24.x
  - Updated `.nvmrc` from `18` to `24`
  - Updated `package.json` engines from `">=18.0.0 <22.0.0"` to `">=24.0.0"`
  - Required for Prisma 7.3.0 compatibility (requires Node 20.19+, 22.12+, or 24.0+)

- **Build Process**: Moved `prisma generate` from postinstall to build command
  - Changed `"build": "nest build"` to `"build": "prisma generate && nest build"`
  - Changed `"postinstall": "prisma generate"` to `"postinstall": "prisma generate || true"`
  - Prevents build failures when Prisma can't generate during install phase
  - Ensures Prisma generates with proper environment variables during build

- **Dependency Organization**: Moved build-critical packages to dependencies
  - Moved `dotenv` from `devDependencies` → `dependencies` (required for Prisma config)
  - Moved `ts-node` from `devDependencies` → `dependencies` (required for TypeScript config loading)
  - Moved `typescript` from `devDependencies` → `dependencies` (required for Prisma TypeScript config)
  - Ensures packages are available during Netlify production builds (which skip devDependencies)

- **TypeScript Return Types**: Fixed controller method return types for NestJS compatibility
  - Changed `streamMusic()` return type to `Promise<void>` (uses `@Res()` decorator)
  - Changed `streamMusicDirect()` return type to `Promise<void>` (uses `@Res()` decorator)
  - Fixed all `return res.status().json()` calls to use `res.status().json(); return;` pattern
  - Resolves TypeScript compilation errors (TS2322) in strict mode

- **Type Safety Improvements**: Added type guards for stream result handling
  - Added runtime check for `filePath` property before destructuring
  - Prevents TypeScript error (TS2339) when accessing properties on union types
  - Improved error handling for unexpected stream result types

- **Logging**: Replaced `console.log` with NestJS Logger service
  - Changed `console.log()` to `this.logger.log()` in `music.service.ts`
  - Maintains consistent logging format and levels across application

### Fixed

- **TypeScript Compilation Errors**: Fixed all TypeScript errors preventing Netlify builds
  - Fixed TS2339: Property 'filePath' does not exist (added type guard)
  - Fixed TS2322: Type 'Response' not assignable (changed return types to `Promise<void>`)
  - All methods using `@Res()` now properly return `void` instead of Response objects

- **Netlify Build Configuration**: Resolved Prisma and TypeScript loading issues
  - Fixed Prisma config loading by ensuring `ts-node` and `dotenv` are in dependencies
  - Fixed Node version compatibility by updating to Node 24
  - Fixed build command to run Prisma generate before NestJS build

- **Serverless Streaming**: Fixed automatic detection and routing
  - Vercel detection now works correctly using `VERCEL`, `VERCEL_ENV`, and `VERCEL_URL` environment variables
  - Direct streaming mode properly handles encrypted vs non-encrypted tracks
  - Error handling improved for unsupported encrypted tracks in serverless mode

### Technical Details

- Netlify function handler uses `serverless-http` to wrap Express app
- Function caches handler instance for improved cold start performance
- All routes are redirected to single serverless function via Netlify redirects
- Build process ensures Prisma client is generated before TypeScript compilation
- TypeScript strict mode compliance across all controller methods

## [1.1.0] - 2026-01-22

### Added

- **Vercel Deployment Support**: Full serverless deployment configuration
  - Added `api/index.ts` serverless function entrypoint using ExpressAdapter
  - Created `vercel.json` configuration for routing all requests to serverless function
  - Extracted `src/bootstrap.ts` with reusable `createApp()` function for both local and serverless environments
  - Added `postinstall` script to automatically run `prisma generate` during Vercel builds
  - Function configured with 30-second max duration for longer-running operations
  - Cached Express server instance for improved cold start performance

- **Enhanced Preview Image Generation**: Complete redesign of social media preview images
  - **Ethereal Dark Background**: Multi-layered gradient system with purple/cyan glows
    - Base dark background (`#0a0a0f`)
    - Primary radial glow from center (purple → cyan) using `lighter` composite operation
    - Secondary cyan glow from top-left corner
    - Linear overlay gradient for depth using `overlay` composite operation
    - Vignette effect darkening edges (`rgba(0, 0, 0, 0.6)`)
  - **Album Cover Enhancements**:
    - 400x400px album cover on left side with rounded corners (20px radius)
    - Cyan glow border with shadow effects
    - Musical note (♪) placeholder for missing covers
  - **Text Rendering Improvements**:
    - Track title: 64px bold system-ui, white with cyan glow and shadow offsets
    - Artist name: 48px system-ui, light purple with purple glow
    - Album name: 36px system-ui, muted with cyan glow
    - All text uses consistent `textBaseline: 'top'` for proper alignment
    - Shadow offsets (2px horizontal, 4px vertical) for depth
  - **Visual Elements**:
    - Cyan gradient accent line under text area
    - Duration display (MM:SS format) in bottom right
    - Footer: "Listen on darkfloor.one now" with subtle cyan glow

- **Comprehensive ESLint & Prettier Configuration**: Professional code quality setup
  - Enhanced ESLint flat config with TypeScript type-checked rules
  - Type safety rules: consistent type imports, nullish coalescing enforcement
  - Code quality rules: prefer const, arrow functions, template literals
  - NestJS-optimized rules: disabled `class-methods-use-this` and `max-classes-per-file`
  - Prettier integration with auto-formatting on save
  - Comprehensive `.prettierignore` for build outputs and generated files

### Changed

- **Preview Image Service**: Complete refactor with fixed composite operations
  - Fixed invisible gradients by changing `screen` → `lighter` for radial glows
  - Fixed darkening issues by changing `multiply` → `overlay` for depth gradients
  - Improved `roundRect()` helper to use `arcTo()` for more precise rounded corners
  - All fonts changed from `Arial` to `system-ui` for better rendering
  - Enhanced shadow effects with proper offsets for all text elements
  - Improved error handling and placeholder fallbacks

- **Code Quality Improvements**:
  - Replaced logical OR (`||`) with nullish coalescing (`??`) for safer optional chaining
  - Fixed all type assertion issues and unnecessary type casts
  - Improved import organization and consistency
  - Enhanced error handling with proper type guards

- **Bootstrap Architecture**: Refactored application initialization
  - Extracted shared bootstrap logic into `src/bootstrap.ts`
  - `main.ts` now uses `createApp()` for local/server deployment
  - `api/index.ts` uses `createApp()` with ExpressAdapter for serverless
  - Maintains all existing functionality (CORS, Swagger, OpenAPI routes)

### Fixed

- Fixed composite operation issues causing invisible background gradients
- Fixed text rendering with proper shadow offsets and quality settings
- Fixed type safety issues in preview image and controller code
- Fixed formatting inconsistencies across codebase
- Removed unnecessary type assertions that didn't change expression types

### Technical Details

- Preview images now generate 40-60KB PNG files with visible ethereal backgrounds
- Serverless function uses cached Express instance to reduce cold start overhead
- ESLint configuration uses project service for efficient type checking
- All code now follows consistent formatting with Prettier integration
- Type-safe codebase with comprehensive ESLint rules for NestJS patterns

## [1.0.1] - 2026-01-22

### Added

- **Routes Documentation**: Added preview image endpoints to the routes documentation
  - `POST /api/track/preview` - Generate preview image from track query, ID, or object
  - `GET /api/track/:id/preview` - Generate preview image from Deezer track ID
  - Routes now appear in the `/routes` endpoint response

### Changed

- **PM2 Process Name**: Renamed PM2 process from `darkfloor-api` to `darkfloor-api-v2`
  - Updated `ecosystem.config.cjs` with new process name
  - Updated all PM2 npm scripts to use `darkfloor-api-v2`
  - Prevents conflicts with existing `darkfloor-api` process running on the same server
  - All PM2 management commands (`pm2:restart`, `pm2:stop`, `pm2:logs`, etc.) now target the new process name

## [1.0.0] - 2026-01-20

### Added

- **CORS Configuration**: Comprehensive CORS setup for production deployment
  - Configured allowed origins: `starchildmusic.com`, `www.starchildmusic.com`, `darkfloor.art`, `www.darkfloor.art`, and `localhost:3000` for development
  - Proper CORS headers: `Access-Control-Allow-Origin` (validated against whitelist, not wildcard), `Access-Control-Allow-Methods`, `Access-Control-Allow-Headers`, `Access-Control-Allow-Credentials`, `Access-Control-Max-Age` (86400 seconds)
  - Automatic OPTIONS preflight request handling with 200 OK response

- **Health Check Endpoint**: New `/health` endpoint providing critical system status
  - Returns JSON with overall health status (`healthy` or `degraded`)
  - Database connectivity check with latency measurement
  - Process uptime and environment information
  - Timestamp for monitoring and debugging

- **Enhanced Smart Tracks Requests (Spice-Up)**: Major improvements to recommendation generation
  - **Multi-Strategy Search**: Intelligent track search with multiple fallback strategies
    - Full query search (name + artist + album)
    - Artist + track search
    - Track-only search
    - Artist-only search for popular tracks
  - **Fuzzy Matching & Scoring**: Advanced string similarity matching with confidence scoring
    - Confidence scores (0-1) for each search result
    - Weighted matching based on track name (40%), artist (40%), album (20%), and popularity (10%)
    - Minimum confidence threshold (0.3) to ensure quality matches
  - **Intelligent Diversity Modes**: Enhanced recommendation diversity with four modes
    - `strict`: Conservative seeds, tight ranges for similar recommendations
    - `balanced`: Moderate variety with good seed coverage (new default)
    - `diverse`: Maximum seeds and wide ranges for high variety
    - `wild`: Experimental combinations with extreme ranges for maximum exploration
  - **Dynamic Seed Selection**: Adaptive seed counts based on input size
    - Scales seed count with input size using square root scaling
    - Capped at maximum of 5 tracks and 4 artists for optimal recommendations
  - **Performance Optimizations**:
    - **Parallel Processing**: Song searches now run in parallel using `Promise.all()` instead of sequential processing
    - **Smart Caching**: TTL-based in-memory caching for search results (10 minutes) and recommendations (30 minutes)
    - Automatic cache cleanup to prevent memory bloat
  - **Enhanced Error Handling**:
    - Partial success responses when some songs can't be found
    - Detailed error messages with specific failure reasons
    - Confidence reporting for each song search
    - Warning system listing specific issues
  - **Cross-Platform Support**: Unified spice-up endpoint combining multiple platforms
    - New `/api/spotify/recommendations/spice-up/unified` endpoint
    - Supports Spotify, Last.fm, and Deezer (extensible)
    - Intelligent fallback: prefers Spotify, falls back to other platforms if needed
  - **Seed Quality Analysis**: Comprehensive metrics and feedback
    - Overall seed quality score (0-1) with detailed breakdown
    - Artist diversity analysis
    - Popularity range analysis (min, max, average)
    - Audio feature diversity scoring
    - Actionable recommendations for improving seed quality
  - **Enhanced Response Format**:
    - Detailed song results with match confidence, search method, and found track
    - Seed quality metrics with actionable feedback
    - Platform tracking showing which platforms were used
    - Structured warnings and error details

### Changed

- **BREAKING**: Default diversity mode changed from `normal` to `balanced` for better default recommendations
- **BREAKING**: Spice-up response format enhanced with additional fields:
  - `foundSongs`: Number of songs successfully found
  - `songResults`: Detailed results for each input song
  - `seedQuality`: Seed quality analysis metrics
  - `warnings`: Warning messages for partial failures
- CORS configuration updated to use specific origin validation instead of wildcard patterns
- Improved diversity parameter calculation with adaptive ranges based on input size
- Enhanced audio feature ranges including tempo, liveness, speechiness, and acousticness

### Technical Details

- Search strategies now use confidence-based selection with multiple fallback patterns
- Cache keys generated from query parameters to maximize cache hit rates
- Parallel search execution reduces total request time significantly
- Seed quality analysis provides actionable insights for users
- Cross-platform endpoint architecture allows easy extension to additional music services

## [0.4.5] - 2026-01-17

### Changed

- Bumped package version for the January 17, 2026 release

## [0.4.3] - 2025-12-03

### Added

- **OpenAPI JSON Download**: Added `/openapi.json` endpoint to download OpenAPI specification in JSON format
  - Endpoint serves the OpenAPI specification as a downloadable JSON file
  - Follows the same pattern as the existing `/openapi.yaml` endpoint
  - Automatically generates filename based on hostname (e.g., `songbird.starchildmusic.com.json`)
  - JSON is formatted with proper indentation for readability

### Technical Details

- OpenAPI JSON endpoint now serves a properly formatted JSON file
- OpenAPI JSON endpoint now uses the same hostname as the OpenAPI YAML endpoint

## [0.4.2] - 2025-12-02

### Added

- **OpenAPI JSON Download**: Added `/openapi.json` endpoint to download OpenAPI specification in JSON format
  - Endpoint serves the OpenAPI specification as a downloadable JSON file
  - Follows the same pattern as the existing `/openapi.yaml` endpoint
  - Automatically generates filename based on hostname (e.g., `songbird.starchildmusic.com.json`)
  - JSON is formatted with proper indentation for readability

- **Docker Support**: Full Dockerization of the application
  - Multi-stage Dockerfile for optimized production builds
  - `.dockerignore` file to exclude unnecessary files from Docker context
  - Health check endpoint for container monitoring
  - Docker Compose example with PostgreSQL database
  - Comprehensive Docker documentation in README
  - Support for volume mounts for persistent data (output/downloads, logs)
  - Automatic Prisma client generation in Docker build process

### Technical Details

- Dockerfile uses Node.js 20 Alpine for smaller image size
- Multi-stage build separates dependencies, build, and production stages
- Production stage only includes runtime dependencies
- Health check verifies API availability on container startup
- Environment variables can be provided via `.env` file or Docker environment

## [0.4.1] - 2025-12-02

### Changed

- UNIVERSAL_API_KEY is now UNIVERSAL_KEY

## [0.4.0] - 2025-12-02

### Changed

- **BREAKING**: Unified authentication keys into a single `UNIVERSAL_KEY` environment variable
  - Replaced `JWT_SECRET` with `UNIVERSAL_KEY` (JWT secret now uses the same key)
  - Removed unused `DEEZER_API_KEY` from validation schema
  - `UNIVERSAL_KEY` is now used for both API key validation and JWT token signing
  - Updated configuration and documentation to reflect this change
  - Minor fixes, openapi.yaml now reflects the url of the server
  - ecosystem.config.js is now ecosystem.config.cjs
  - fixed file annotation headers, updated tree.txt

### Migration Guide

If you're upgrading from 0.3.0 or earlier:

- Remove `JWT_SECRET` and `DEEZER_API_KEY` from your `.env` file
- Ensure `UNIVERSAL_KEY` is set in your `.env` file
- The same key value can be used for all authentication purposes

## [0.3.0] - 2025-12-02

### Changed

- **BREAKING**: Enabled strict TypeScript compiler options for better type safety
  - Enabled `strictNullChecks`, `noImplicitAny`, `strictBindCallApply`, `forceConsistentCasingInFileNames`, and `noFallthroughCasesInSwitch`
  - This improves type safety across the entire codebase

### Fixed

- Removed all `eslint-disable` comments and replaced with proper TypeScript types
- Fixed type safety issues in `music.service.ts` by adding proper return types and type guards
- Fixed type safety issues in `deezer-integration.service.ts` by:
  - Adding proper interface for `d-fi-core` API
  - Replacing `any` types with `DeezerSearchResponse` and proper type guards
  - Adding null checks for optional API
- Fixed type safety issues in `lastfm.service.ts` by:
  - Adding generic type parameter to `makeRequest` method
  - Replacing `any` return types with proper Last.fm API response types
  - Adding proper type guards for Last.fm track and artist data
- Fixed type safety issues in `playlist-conversion.service.ts` by:
  - Replacing `any[]` with proper `DeezerTrackSearchResult[] | SpotifyTrack[]` types
  - Adding proper type guards for API responses
- Fixed type safety issues in `metadata-cache.service.ts` by:
  - Replacing `any` with `DeezerTrackSearchResult` type
  - Adding proper error type checking
- Removed eslint-disable comments from all controllers:
  - `music.controller.ts`
  - `playlist.controller.ts`
  - `favorites.controller.ts`
  - `listening-history.controller.ts`
- Removed eslint-disable comments from services:
  - `listening-history.service.ts`
  - `playlist.service.ts`

### Technical Details

- All service methods now have explicit return types
- All API responses are properly typed using interfaces from `types.ts`
- Error handling uses proper type guards (`error instanceof Error`)
- Dynamic imports (like `d-fi-core`) are properly typed with interfaces
- All `any` types have been replaced with proper TypeScript types

## [0.2.2] - 2025-12-01

### Fixed

- Fixed TypeScript configuration by removing deprecated `ignoreDeprecations` and `baseUrl` options
- Fixed 90 error handling type errors across all service files by adding proper type narrowing for caught errors
- Fixed 42 DTO property initialization errors by adding definite assignment assertions
- Improved error handling in Deezer, Last.fm, Spotify, and Music services with proper AxiosError type checking
- Enhanced Prisma error handling with explicit type assertions for better type safety

### Changed

- Updated error handling to use `error: unknown` with proper type guards
- Added AxiosError imports to HTTP service files for better type safety
- All DTO classes now use definite assignment assertions (`!`) for required properties

### Technical Details

- Total of 132 TypeScript errors resolved
- Updated files across multiple modules: logging, deezer, lastfm, spotify, music
- All DTOs updated for strict TypeScript compliance

## [0.2.1] - Previous Release

### Added

- Playlist conversion feature in music module
- Deezer track downloading setup
- Enhanced music module with Deezer integration
- User features and playlist management

### Changed

- Enhanced AppController and AppService with new API route functionality
- Updated TypeScript configuration
- Refactored HTML generation in AppService

# Changelog

All notable changes to this project will be documented in this file.

## [1.9.4] - 2026-03-12

### Added

- Added MVP Spotify playlist import backend support via `POST /music/playlists/import/spotify`.
- Added import request validation DTO for Spotify playlist ID or URL input.
- Added deterministic import reporting with matched, unmatched, and skipped counts plus ordered unmatched rows.
- Added focused unit tests for Spotify playlist import behavior and response stability.

### Changed

- Bumped application version from `1.9.3` to `1.9.4`.
