Skip to content

refactor(artists): extract ArtistSuggestionService from route handler - #980

Merged
LucasSantana-Dev merged 5 commits into
mainfrom
refactor/artist-suggestion-service
May 23, 2026
Merged

LucasSantana-Dev merged 5 commits into
mainfrom
refactor/artist-suggestion-service

Conversation

@LucasSantana-Dev

@LucasSantana-Dev LucasSantana-Dev commented May 23, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Extracts all business logic from packages/backend/src/routes/artists.ts (586 LOC → 54 LOC) into a new ArtistSuggestionService
  • Three-tier lookup: preferred artists via Prisma → Spotify top artists → popular fallback list
  • Moves 30 hardcoded popular artist names to packages/backend/src/constants/popularArtists.ts
  • Adds Redis caching (configurable TTLs) inside the service
  • New service has 33 unit tests covering all tiers, cache hit/miss, and error fallthrough

Test plan

  • npm run test:ci --workspace=packages/backend — 856 tests pass
  • artists.ts route handler is 54 LOC (≤100 requirement)
  • ArtistSuggestionService unit tests mock only Prisma + Spotify (no Express)
  • Statement coverage on artistSuggestion.ts: 91.87% (≥80% requirement)

Summary by CodeRabbit

Release Notes

  • New Features

    • Curated popular artists list added as fallback source for personalized artist suggestions and recommendations
  • Refactor

    • Artist-related endpoints refactored to use a dedicated service layer that improves suggestion accuracy and caching efficiency with multi-tier prioritization: saved preferences, user's top artists, and popular artist recommendations
  • Tests

    • Comprehensive unit tests added for artist suggestion service covering cache behavior, input validation, error handling, and fallback scenarios

Review Change Stack

…vice

- Create ArtistSuggestionService with three-tier lookup strategy:
  1. User's saved preferred artists (database)
  2. User's Spotify top artists (if linked)
  3. Popular artists fallback (static list)
- Move 80+ popular artist names to constants/popularArtists.ts
- Add Redis caching for fallback and user top artists
- Reduce artists.ts route handler from 586 to 298 LOC
- Update existing tests to match new behavior
- All 823 backend tests passing
Move all business logic from routes/artists.ts into services/artistSuggestion.ts:
- Add handler methods: handleGetSuggestions, handleSearchArtists, etc.
- Validate inputs and return errors in service layer
- Trim routes file from 319 to 46 LOC (meets <100 requirement)
- Create unit test suite with 33 tests (89.84% coverage, exceeds 80%)
- All tests passing (856 tests in backend package)
@vercel

vercel Bot commented May 23, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
lucky Ready Ready Preview, Comment May 23, 2026 9:14pm

Request Review

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@github-actions github-actions Bot added dependencies Pull requests that update a dependency file backend size/xl labels May 23, 2026
@github-actions

Copy link
Copy Markdown

Failed to generate code suggestions for PR

Comment thread packages/backend/tests/unit/services/artistSuggestion.test.ts Fixed

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai

coderabbitai Bot commented May 23, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

@LucasSantana-Dev, we couldn't start this review because you've used your available PR reviews for now.

Your plan currently allows 1 review/hour. Refill in 39 minutes and 12 seconds.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more review capacity refills, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than trial, open-source, and free plans. In all cases, review capacity refills continuously over time.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f160f009-53bc-4e5b-9536-54fcd13c74e1

📥 Commits

Reviewing files that changed from the base of the PR and between e50ed3c and a8b806c.

📒 Files selected for processing (4)
  • packages/backend/src/routes/artists.ts
  • packages/backend/src/services/artistSuggestion.ts
  • packages/backend/src/utils/routeUtils.ts
  • packages/backend/tests/unit/services/artistSuggestion.test.ts
📝 Walkthrough

Walkthrough

A new ArtistSuggestionService consolidates artist suggestion logic with three-tier caching: user preferences, Spotify top artists, and popular fallback. Artists routes are refactored to delegate all logic to the service, replacing inline Spotify/Redis/Prisma code. Popular artists constants, comprehensive tests, and a centralized error-handling wrapper are added.

Changes

Artist Suggestion Service Refactoring

Layer / File(s) Summary
Popular artists data model and type contracts
packages/backend/src/constants/popularArtists.ts
POPULAR_ARTISTS is a curated immutable list of artist names, and PopularArtist type is derived from its elements.
Service architecture and core suggestion orchestration with caching
packages/backend/src/services/artistSuggestion.ts
ArtistSuggestionService implements a three-tier lookup (Prisma user preferences, Spotify top artists with Redis cache, popular fallback with Redis cache), deduplicates by artist ID, and caps results. prewarmCache() preloads the popular-artists cache on startup to reduce first-request rate limiting.
HTTP request handler methods and input validation
packages/backend/src/services/artistSuggestion.ts
Handler methods (handleGetSuggestions, handleSearchArtists, handleGetRelatedArtists, handleGet/Save/BatchSave/DeletePreferredArtist) validate inputs, enforce auth and Spotify configuration, call service logic, and map errors to HTTP status/error objects.
Routes refactoring and service integration
packages/backend/src/routes/artists.ts
Routes instantiate ArtistSuggestionService, prewarm cache on startup, and introduce a wrap() helper for async error-to-HTTP translation. All seven route handlers delegate to corresponding service methods, removing ~450 lines of inline implementation.
Route integration tests
packages/backend/tests/unit/routes/artists.test.ts
Route tests reflect delegated behavior: GET /api/artists/suggestions expects unified 503 errors; POST /api/users/me/preferred-artists asserts both status and JSON payload; other routes are updated for new service-based mocking.
Service unit tests
packages/backend/tests/unit/services/artistSuggestion.test.ts
New test suite validates three-tier suggestion loading with caching, auth/input validation (401/400/503 responses), preference CRUD with correct Prisma queries, cache prewarming skip conditions, and Redis cache hit behavior.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • LucasSantana-Dev/Lucky#630: Added the initial /api/artists/suggestions endpoint with Spotify top-artists and popular fallback logic; this PR refactors that behavior into a reusable service.
  • LucasSantana-Dev/Lucky#707: Introduced Redis caching for popular-artists fallback in the routes module; this PR migrates that caching strategy into the new service.

Suggested labels

backend, enhancement, size/l

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main refactoring: extracting ArtistSuggestionService from the route handler, which is the primary change reducing routes/artists.ts from 586 to 54 LOC.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/artist-suggestion-service

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (1)
packages/backend/tests/unit/routes/artists.test.ts (1)

53-56: ⚡ Quick win

Assert the registered middleware chain, not just the terminal handler.

getRouteHandler() drops everything except the last arg, so these tests still pass if a route loses requireAuth or swaps apiLimiter/writeLimiter. After this refactor, that wiring is most of what the route layer still owns.

Possible direction
-function getRouteHandler(mockMethod: any, index = 0): any {
+function getRouteRegistration(mockMethod: jest.Mock, index = 0) {
     const call = mockMethod.mock.calls[index]
-    return call[call.length - 1]
+    return {
+        path: call[0],
+        middlewares: call.slice(1, -1),
+        handler: call[call.length - 1],
+    }
 }

Then assert path and middlewares for each route before invoking handler.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/backend/tests/unit/routes/artists.test.ts` around lines 53 - 56,
getRouteHandler currently returns only the last argument (handler) so tests miss
verifying registered middleware and path; change getRouteHandler(mockMethod,
index=0) to inspect the full call (const call = mockMethod.mock.calls[index])
and return an object with path = call[0], middlewares = call.slice(1,
call.length - 1) and handler = call[call.length - 1]; update tests to assert the
path and the ordered middlewares (e.g., requireAuth, apiLimiter/writeLimiter)
before invoking/inspecting handler.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/backend/src/routes/artists.ts`:
- Around line 54-57: The route currently passes r.params.artistId (type string |
string[]) directly to ArtistSuggestionService.handleGetRelatedArtists (expects
string | undefined); normalize it to a single string or undefined first — e.g.
compute artistId = Array.isArray(r.params.artistId) ? r.params.artistId[0] :
r.params.artistId and pass that to svc.handleGetRelatedArtists — and update the
wrap error handling to use catch (e: unknown) and narrow (e.g. instanceof Error
or checking 'status'/'error' props) instead of catch (e: any) to remove unsafe
any usage.
- Around line 10-19: The wrap helper currently uses Promise<any> and catch (e:
any); change the handler signature to (h: (r: AuthenticatedRequest) =>
Promise<unknown>) and catch (e: unknown), then introduce a small type guard
(e.g., isHttpError) that narrows unknown to { status?: number; error?: string }
and use it to safely read status and error (falling back to 500 and the provided
err message); update uses of e to go through the type guard and keep errorLog({
message: `${ctx} error`, error: e }) only when appropriate.

In `@packages/backend/src/services/artistSuggestion.ts`:
- Around line 2-8: There are two imports from '`@lucky/shared/utils`' in
artistSuggestion.ts (a separate type-only import for SpotifyArtist and a value
import for errorLog, getPrismaClient, searchSpotifyArtists,
getSpotifyRelatedArtists); consolidate them into a single import by adding "type
SpotifyArtist" into the existing named import (e.g. import { type SpotifyArtist,
errorLog, getPrismaClient, searchSpotifyArtists, getSpotifyRelatedArtists } from
'`@lucky/shared/utils`') and remove the separate import line.
- Around line 195-205: fetchSpotifyTopArtists issues parallel fetches for
timeRanges without any timeout/abort protection; update the code that builds
promises (where timeRanges is mapped and Promise.all is awaited) to use an
AbortController per request and a setTimeout to call controller.abort() after a
configurable timeout (e.g., 5–10s), ensure you clear the timeout on successful
response to avoid leaks, and handle abort errors so Promise.all rejects/handles
them cleanly; reference the mapping that creates promises and the Promise.all
that assigns responses to add this AbortController+timeout logic.
- Around line 451-457: The single-save Zod schema for preferred artists rejects
explicit null for imageUrl and spotifyId; update the schema in the object
defined around the validation used by handleSavePreferredArtist so both imageUrl
and spotifyId accept null as well as undefined by changing their types from
z.string().optional() to z.string().nullable().optional() (or
z.string().nullable() if you prefer to require presence but allow null),
ensuring parity with the DB nullable columns and the batch-save behavior for
imageUrl; keep the field names artistSuggestion schema: imageUrl and spotifyId
so the change is localized.
- Around line 521-550: handleBatchSavePreferences is doing await
db.userArtistPreference.upsert(...) inside a loop which can leave partial writes
if one upsert fails; wrap the whole loop in a single database transaction so all
upserts commit or all rollback. Modify handleBatchSavePreferences to call
db.$transaction(...) (or the equivalent transaction API your DB client exposes)
and perform the normalized artistKey computation and userArtistPreference.upsert
calls inside that transaction callback (referencing normalizeArtistKey and
userArtistPreference.upsert), collect results and return them; ensure any thrown
error propagates to abort the transaction so no partial updates persist.

In `@packages/backend/tests/unit/services/artistSuggestion.test.ts`:
- Line 1: In the "should cache user top artists after fetch" test in
artistSuggestion.test.ts you stubbed global.fetch but never restore it; save the
original (e.g. const originalFetch = global.fetch) before mocking or use
jest.spyOn(global, 'fetch') to create the mock, then restore global.fetch in an
afterEach/cleanup block (or a finally within the test) by reassigning
global.fetch = originalFetch or calling mockRestore()/jest.restoreAllMocks();
update the test to reference the specific test name and ensure the original
fetch is always restored to avoid leaking state to subsequent tests.

---

Nitpick comments:
In `@packages/backend/tests/unit/routes/artists.test.ts`:
- Around line 53-56: getRouteHandler currently returns only the last argument
(handler) so tests miss verifying registered middleware and path; change
getRouteHandler(mockMethod, index=0) to inspect the full call (const call =
mockMethod.mock.calls[index]) and return an object with path = call[0],
middlewares = call.slice(1, call.length - 1) and handler = call[call.length -
1]; update tests to assert the path and the ordered middlewares (e.g.,
requireAuth, apiLimiter/writeLimiter) before invoking/inspecting handler.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ecff51cd-ad33-4263-8141-3cf2592cc631

📥 Commits

Reviewing files that changed from the base of the PR and between 6b6f8a3 and e50ed3c.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json, !**/package-lock.json
📒 Files selected for processing (5)
  • packages/backend/src/constants/popularArtists.ts
  • packages/backend/src/routes/artists.ts
  • packages/backend/src/services/artistSuggestion.ts
  • packages/backend/tests/unit/routes/artists.test.ts
  • packages/backend/tests/unit/services/artistSuggestion.test.ts

Comment thread packages/backend/src/routes/artists.ts Outdated
Comment thread packages/backend/src/routes/artists.ts Outdated
Comment thread packages/backend/src/services/artistSuggestion.ts Outdated
Comment thread packages/backend/src/services/artistSuggestion.ts
Comment thread packages/backend/src/services/artistSuggestion.ts
Comment thread packages/backend/src/services/artistSuggestion.ts
Comment thread packages/backend/tests/unit/services/artistSuggestion.test.ts
@github-actions

github-actions Bot commented May 23, 2026 •

Copy link
Copy Markdown

Size Change: 0 B

Total Size: 423 kB

ℹ️ View Unchanged
Filename Size
packages/frontend/dist/assets/Admin-DtH3tPSJ.js 2.31 kB
packages/frontend/dist/assets/api-DLTCUUu6.js 3.37 kB
packages/frontend/dist/assets/AutoMessages-D4bmTCiO.js 2.66 kB
packages/frontend/dist/assets/AutoMod-dEV7bVdF.js 4.08 kB
packages/frontend/dist/assets/badge-DkL_64S8.js 502 B
packages/frontend/dist/assets/Card-C0OrfZA_.js 503 B
packages/frontend/dist/assets/Changelog-DG0GrFHf.js 29.1 kB
packages/frontend/dist/assets/CommandsConfig-jjX61VVV.js 1.46 kB
packages/frontend/dist/assets/Config-Df7vMGLj.js 1.93 kB
packages/frontend/dist/assets/CustomCommands-CT5HLfQ1.js 2.11 kB
packages/frontend/dist/assets/DashboardOverview-CRraDu7w.js 3.9 kB
packages/frontend/dist/assets/dialog-DEJzUXlB.js 948 B
packages/frontend/dist/assets/Docs-yBv9WUP0.js 17.6 kB
packages/frontend/dist/assets/DocsShell-meGZxluk.js 1.42 kB
packages/frontend/dist/assets/EmbedBuilder-C-iv9KkV.js 3.33 kB
packages/frontend/dist/assets/Features-_TZbYQzA.js 759 B
packages/frontend/dist/assets/GuildAutomation-tr8t8vkV.js 2.86 kB
packages/frontend/dist/assets/index-i6ZlzslN.js 54.8 kB
packages/frontend/dist/assets/index-lylX54iU.css 17.7 kB
packages/frontend/dist/assets/input-CpDrPZ7L.js 464 B
packages/frontend/dist/assets/label-Jdi8Nphv.js 476 B
packages/frontend/dist/assets/Landing-BiUaGgOu.js 5.05 kB
packages/frontend/dist/assets/LastFm-D6Qu-Qy5.js 1.94 kB
packages/frontend/dist/assets/legalNav-B6k3CWsW.js 274 B
packages/frontend/dist/assets/Levels-BGtvOpVc.js 2.62 kB
packages/frontend/dist/assets/Login-CTBuQ1SC.js 2.49 kB
packages/frontend/dist/assets/Lyrics-BYSEw4zY.js 1.33 kB
packages/frontend/dist/assets/Moderation-CQqahuaj.js 3.82 kB
packages/frontend/dist/assets/Music-Dt7C1XPJ.js 7.09 kB
packages/frontend/dist/assets/MusicConfig-s-hf_meN.js 1.6 kB
packages/frontend/dist/assets/PreferredArtists-vc5HIrPD.js 3.75 kB
packages/frontend/dist/assets/PrivacyPolicy-B9d_uomC.js 1.77 kB
packages/frontend/dist/assets/ReactionRoles-Dr9Regwt.js 1.87 kB
packages/frontend/dist/assets/rolldown-runtime-Cyuzqnbw.js 471 B
packages/frontend/dist/assets/SectionHeader-v5DrDPcP.js 892 B
packages/frontend/dist/assets/select-e5b6M0L7.js 1.23 kB
packages/frontend/dist/assets/ServerLogs-BZRJTMDv.js 2.88 kB
packages/frontend/dist/assets/ServerSettings-Bgp5jfzz.js 4.19 kB
packages/frontend/dist/assets/ServersPage-qsUzhWjh.js 2.99 kB
packages/frontend/dist/assets/Skeleton-DJBwVosU.js 235 B
packages/frontend/dist/assets/Spotify-CGMTZ35P.js 1.94 kB
packages/frontend/dist/assets/Starboard-koyFMsA6.js 2.06 kB
packages/frontend/dist/assets/StatTile-BaweEc9i.js 635 B
packages/frontend/dist/assets/switch-TmDW9vMq.js 540 B
packages/frontend/dist/assets/TermsOfService-D1APhrGs.js 1.61 kB
packages/frontend/dist/assets/TrackHistory-BJa_-HPC.js 2.16 kB
packages/frontend/dist/assets/TwitchNotifications-kxEof1Br.js 2.44 kB
packages/frontend/dist/assets/useActiveHeading-DTLh9dCa.js 1.35 kB
packages/frontend/dist/assets/useFeatures-ptFKdW19.js 2.03 kB
packages/frontend/dist/assets/usePageMetadata-CarOGTBf.js 325 B
packages/frontend/dist/assets/vendor-forms-Byie8cSi.js 25.6 kB
packages/frontend/dist/assets/vendor-radix-B5ens4Er.js 38.9 kB
packages/frontend/dist/assets/vendor-react-DutrFyFe.js 55.7 kB
packages/frontend/dist/assets/vendor-state-BeWQCQr5.js 24.1 kB
packages/frontend/dist/assets/vendor-ui-jUuHT_XY.js 65.3 kB

compressed-size-action

…utes

Move wrapHandler and ApiError interface to src/utils/routeUtils.ts.
Redefine route handlers as module-level consts; setupArtistsRoutes
becomes a compact registration block (≤100 LOC spec met).

Also fix Zod schema nullable fields and test cleanup:
- spotifyId/imageUrl: add .nullable() to match DB columns
- Remove unused `suggestions` variable in cache test
- Save/restore global.fetch around mock assignment

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@sonarqubecloud

Copy link
Copy Markdown

@LucasSantana-Dev
LucasSantana-Dev merged commit e1c0cc0 into main May 23, 2026
31 of 33 checks passed
@LucasSantana-Dev
LucasSantana-Dev deleted the refactor/artist-suggestion-service branch May 23, 2026 21:16
LucasSantana-Dev added a commit that referenced this pull request May 24, 2026
## Summary

Replaces the 15+ positional arguments passed through the autoplay
collector pipeline with a single `AutoplayContext` value object,
improving call-site clarity and making the pipeline easier to extend.

### Changes
- Introduce `AutoplayContext` interface in `autoplayContext.ts`
- Update `candidateCollector`, `lastFmSeeder`, `spotifyRecommender`,
`replenisher`, and `candidateFallback` to accept `AutoplayContext`
instead of positional args
- Fix missing `beforeEach` mock setup in `candidateCollector` tests
- Remove leftover `.bak` file from refactor

### Why
Positional argument lists of 15+ items are hard to read, easy to
misorder, and brittle to extend. A named value object surfaces intent at
every call site and isolates future additions to one interface
definition.

Part of the architecture refactor series (T1–T5):
- T1 #979 ✅ — extract `MessagePipeline`
- T2 #980 ✅ — introduce `IGuildAutomationRepository`
- T3 #981 ✅ — `AutomationPlan` result type
- T4 #982 ✅ — `GuildAutomationRepository` / `Orchestrator` split
- T5 (this PR) — `AutoplayContext` value object
@LucasSantana-Dev
LucasSantana-Dev restored the refactor/artist-suggestion-service branch May 24, 2026 15:18
LucasSantana-Dev added a commit that referenced this pull request May 24, 2026
ADRs for the 5 refactors merged in PRs #979–#983 and the Phase 4 test
reduction strategy.

## Decision records added

- `2026-05-23-artist-suggestion-service.md` — ArtistSuggestionService
extraction (#980)
- `2026-05-23-autoplay-context-value-object.md` — AutoplayContext value
object (#983)
- `2026-05-23-bot-test-reduction-phase4-replacement-strategy.md` — Phase
4 test replacement strategy
- `2026-05-23-guild-automation-orchestrator-repository-split.md` —
GuildAutomationService split (#982)
- `2026-05-23-message-pipeline-handler-chain.md` — MessagePipeline
handler chain (#981)
- `2026-05-23-recommendation-engine-single-entrypoint.md` —
recommendTracks() single entrypoint (#979)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Added architecture decision records documenting planned service
refactoring, test optimization strategies, and API consolidation
initiatives to improve system maintainability.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/LucasSantana-Dev/Lucky/pull/1040?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
LucasSantana-Dev added a commit that referenced this pull request May 25, 2026
## Summary

- Bumps all package.json files from `2.14.1` → `2.15.0`
- Populates `CHANGELOG.md` with everything since v2.14.1
- Adds ADR `docs/decisions/2026-05-24-ci-runtime-baseline-accepted.md`
(CI runtime baseline: 3–4 min accepted, Jest sharding deferred)

### Changes included in this release

**Added**
- ServerLogs + ServerSettings UI pages (#965)
- AutoMessages executor wiring into execution service (#950)

**Changed**
- 4 UI redesigns: Admin, Config, Login, ServersPage, CustomCommands,
GuildAutomation, Spotify, LastFm (#967–#970)
- 5 refactors: AutoplayContext VO (#983),
GuildAutomationOrchestrator/Repository split (#982), MessagePipeline
chain (#981), ArtistSuggestionService (#980), recommendTracks entrypoint
(#979)

**Fixed** — deploy CI gap sweep (A–F)
- Gap A: hard-fail on OAuth 429 (#1045)
- Gap B: surface async deploy via commit statuses (#1046)
- Gap C: bot healthcheck polls Discord gateway, not Redis TCP (#1047)
- Gap D: post error status on lock contention (#1052)
- Gap E: add bot to required containers, remove dead unhealthy grep
(#1054)
- Gap F: wait for homelab-deploy completion on docker_rebuilt=true path
(#1056)
- lockfile-hash BuildKit cache key (#1016)
- squash-merged release branch archive (#946)

**Internal**
- Phase 4 test cleanup — 93 tests removed (#956–#1035)
- Pre-commit hooks: husky + lint-staged + tsc (#1007)
- madge gate promoted to blocking
- Dependabot routine bumps (#971–#977, #1042)

> **Note:** #1054 (Gap E) may still be in CI — merge this PR after #1054
lands.

This branch was successfully deployed

1 active deployment
Preview — a8b806ca Deployed May 23, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend dependencies Pull requests that update a dependency file size/xl

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants