Auto reviews are disabled on base/target branches other than the default branch.
Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: de3090ad-c1ad-432e-82f1-ec1bb7fcbee7
You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.
Use the checkbox below for a quick retry:
🔍 Trigger review
✨ Finishing Touches🧪 Generate unit tests (beta)
Create PR with unit tests
Commit unit tests in branch feat/extend-data-structures-48
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.
Comment @coderabbitai help to get the list of available commands and usage tips.
<!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- This is an auto-generated comment: skip review by coderabbit.ai -->
> [!IMPORTANT]
> ## Review skipped
>
> Auto reviews are disabled on base/target branches other than the default branch.
>
>
>
> Please check the settings in the CodeRabbit UI or the `.coderabbit.yaml` file in this repository. To trigger a single review, invoke the `@coderabbitai review` command.
>
> <details>
> <summary>⚙️ Run configuration</summary>
>
> **Configuration used**: Organization UI
>
> **Review profile**: ASSERTIVE
>
> **Plan**: Pro
>
> **Run ID**: `de3090ad-c1ad-432e-82f1-ec1bb7fcbee7`
>
> </details>
>
> You can disable this status message by setting the `reviews.review_status` to `false` in the CodeRabbit configuration file.
>
> Use the checkbox below for a quick retry:
> - [ ] <!-- {"checkboxId": "e9bb8d72-00e8-4f67-9cb2-caf3b22574fe"} --> 🔍 Trigger review
<!-- end of auto-generated comment: skip review by coderabbit.ai -->
<!-- finishing_touch_checkbox_start -->
<details>
<summary>✨ Finishing Touches</summary>
<details>
<summary>🧪 Generate unit tests (beta)</summary>
- [ ] <!-- {"checkboxId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} --> Create PR with unit tests
- [ ] <!-- {"checkboxId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} --> Commit unit tests in branch `feat/extend-data-structures-48`
</details>
</details>
<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->
---
Thanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=devitq/movienight-backend&utm_content=50)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
<details>
<summary>❤️ Share</summary>
- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)
</details>
<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>
<!-- tips_end -->
copilot-pull-request-reviewer[bot]
(Migrated from github.com)
reviewed 2026-05-20 16:51:56 +00:00
copilot-pull-request-reviewer[bot]
(Migrated from github.com)
left a comment
Copy Link
Copy Source
Pull request overview
This PR expands the backend data model and APIs to support richer film metadata, user preferences/ratings, recommendations, and a Jellyfin integration (sync + event ingestion), along with persistence and metrics support.
Changes:
Extend core domain + DB schema for films, library entries (watchedAt), user preferences, film ratings, and Jellyfin sync/event state.
Add new application services and REST controllers for preferences, ratings, recommendations, and Jellyfin sync/events.
Add Micrometer business metrics and supporting JDBC repositories/entities.
Reviewed changes
Copilot reviewed 70 out of 70 changed files in this pull request and generated 6 comments.
findByUserId / findByUserAndFilmId load all favorites and then filter in memory. Since FilmLibraryRepositoryPort now exposes findByUserIdAndFilmId, FilmLibraryService should call that (and ideally add a findByUserId query) to avoid full-table scans and reduce memory/latency as favorites grow.
The HTTP status check is inverted: check(response.statusCode() !in 200..299) will throw on successful (2xx) responses and silently accept failures. This makes all Jellyfin calls fail in normal operation. Flip the condition (or use require(response.statusCode() in 200..299)) so non-2xx responses raise an error.
The HTTP status check is inverted: `check(response.statusCode() !in 200..299)` will throw on successful (2xx) responses and silently accept failures. This makes all Jellyfin calls fail in normal operation. Flip the condition (or use `require(response.statusCode() in 200..299)`) so non-2xx responses raise an error.
This endpoint processes Jellyfin events even when the integration is disabled. Consider rejecting with 404/409/503 (or simply no-op) when integrations.jellyfin.enabled is false to avoid unexpected writes when Jellyfin integration is turned off.
This endpoint processes Jellyfin events even when the integration is disabled. Consider rejecting with 404/409/503 (or simply no-op) when `integrations.jellyfin.enabled` is false to avoid unexpected writes when Jellyfin integration is turned off.
create() persists a FilmLibrary row with filmId = libraryId, but favorites.film_id has an FK to films(id) (V1__init.sql). This will insert a non-existent film id and fail at runtime. Consider making library creation a no-op (create only when adding films), or introduce a separate libraries table; in any case, don’t write a placeholder entry with a fake filmId.
This issue also appears on line 133 of the same file.
`create()` persists a FilmLibrary row with `filmId = libraryId`, but `favorites.film_id` has an FK to `films(id)` (V1__init.sql). This will insert a non-existent film id and fail at runtime. Consider making library creation a no-op (create only when adding films), or introduce a separate `libraries` table; in any case, don’t write a placeholder entry with a fake `filmId`.
This issue also appears on line 133 of the same file.
Logging format string has a stray trailing quote: descriptionLength={}'. This will produce confusing log output and can break log parsing. Remove the extra ' so the message template matches the arguments.
Logging format string has a stray trailing quote: `descriptionLength={}'`. This will produce confusing log output and can break log parsing. Remove the extra `'` so the message template matches the arguments.
Idempotency handling is unsafe: the event is inserted before processing, so if processing fails (exception or early return), retries will be skipped forever because exists(eventId) becomes true. Also, the exists + save sequence is race-prone and can still double-process concurrent requests. Prefer a single insert with ON CONFLICT DO NOTHING and only proceed when the insert actually happened (updatedRows==1), and/or store a processed status so failed events can be retried.
Idempotency handling is unsafe: the event is inserted before processing, so if processing fails (exception or early return), retries will be skipped forever because `exists(eventId)` becomes true. Also, the `exists` + `save` sequence is race-prone and can still double-process concurrent requests. Prefer a single insert with `ON CONFLICT DO NOTHING` and only proceed when the insert actually happened (updatedRows==1), and/or store a processed status so failed events can be retried.
Avoid modifying an existing Flyway migration (V1). Changing previously-applied migration files will cause Flyway checksum validation failures on any environment that has already run V1, blocking startup/migrate. Add a new migration (e.g., V4__extend_schema.sql) with ALTER TABLE statements instead.
Avoid modifying an existing Flyway migration (V1). Changing previously-applied migration files will cause Flyway checksum validation failures on any environment that has already run V1, blocking startup/migrate. Add a new migration (e.g., V4__extend_schema.sql) with ALTER TABLE statements instead.
copilot-swe-agent[bot]
(Migrated from github.com)
reviewed 2026-05-20 18:33:50 +00:00
Fixed in 50923e2. I restored V1__init.sql to baseline and moved the schema extensions into a new migration V6__extend_schema.sql so V1 is no longer modified. UI screenshot: N/A (backend-only change).
Fixed in 50923e2. I restored `V1__init.sql` to baseline and moved the schema extensions into a new migration `V6__extend_schema.sql` so V1 is no longer modified. UI screenshot: N/A (backend-only change).
copilot-swe-agent[bot]
(Migrated from github.com)
reviewed 2026-05-20 18:33:53 +00:00
Fixed in 50923e2. create() no longer persists a placeholder row with filmId = libraryId; it now avoids creating fake library entries. UI screenshot: N/A (backend-only change).
Fixed in 50923e2. `create()` no longer persists a placeholder row with `filmId = libraryId`; it now avoids creating fake library entries. UI screenshot: N/A (backend-only change).
copilot-swe-agent[bot]
(Migrated from github.com)
reviewed 2026-05-20 18:33:56 +00:00
Fixed in 50923e2. I corrected the status check to require response.statusCode() in 200..299 so non-2xx responses now fail as intended. UI screenshot: N/A (backend-only change).
Fixed in 50923e2. I corrected the status check to require `response.statusCode() in 200..299` so non-2xx responses now fail as intended. UI screenshot: N/A (backend-only change).
copilot-swe-agent[bot]
(Migrated from github.com)
reviewed 2026-05-20 18:33:58 +00:00
Fixed in 50923e2. I removed the exists + save flow and now gate processing on a single insert (ON CONFLICT DO NOTHING via affected rows). For failures/early-return cases, the inserted event is deleted so retries remain possible. UI screenshot: N/A (backend-only change).
Fixed in 50923e2. I removed the `exists + save` flow and now gate processing on a single insert (`ON CONFLICT DO NOTHING` via affected rows). For failures/early-return cases, the inserted event is deleted so retries remain possible. UI screenshot: N/A (backend-only change).
copilot-swe-agent[bot]
(Migrated from github.com)
reviewed 2026-05-20 18:34:01 +00:00
Fixed in 50923e2. The events endpoint now rejects requests with 503 Service Unavailable when integrations.jellyfin.enabled is false. UI screenshot: N/A (backend-only change).
Fixed in 50923e2. The events endpoint now rejects requests with `503 Service Unavailable` when `integrations.jellyfin.enabled` is false. UI screenshot: N/A (backend-only change).
copilot-swe-agent[bot]
(Migrated from github.com)
reviewed 2026-05-20 18:34:05 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
✨ Finishing Touches
🧪 Generate unit tests (beta)
feat/extend-data-structures-48Thanks 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 helpto get the list of available commands and usage tips.Pull request overview
This PR expands the backend data model and APIs to support richer film metadata, user preferences/ratings, recommendations, and a Jellyfin integration (sync + event ingestion), along with persistence and metrics support.
Changes:
Reviewed changes
Copilot reviewed 70 out of 70 changed files in this pull request and generated 6 comments.
Show a summary per file
Comments suppressed due to low confidence (1)
src/main/kotlin/com/project/movienight/application/services/FilmLibraryService.kt:141
findByUserId/findByUserAndFilmIdload all favorites and then filter in memory. SinceFilmLibraryRepositoryPortnow exposesfindByUserIdAndFilmId,FilmLibraryServiceshould call that (and ideally add afindByUserIdquery) to avoid full-table scans and reduce memory/latency as favorites grow.💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
@@ -0,0 +1,143 @@package com.project.movienight.adapters.jellyfinThe HTTP status check is inverted:
check(response.statusCode() !in 200..299)will throw on successful (2xx) responses and silently accept failures. This makes all Jellyfin calls fail in normal operation. Flip the condition (or userequire(response.statusCode() in 200..299)) so non-2xx responses raise an error.@@ -0,0 +36,4 @@throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "Invalid plugin token")}}This endpoint processes Jellyfin events even when the integration is disabled. Consider rejecting with 404/409/503 (or simply no-op) when
integrations.jellyfin.enabledis false to avoid unexpected writes when Jellyfin integration is turned off.@@ -20,70 +24,105 @@ import java.util.UUIDclass FilmLibraryService(create()persists a FilmLibrary row withfilmId = libraryId, butfavorites.film_idhas an FK tofilms(id)(V1__init.sql). This will insert a non-existent film id and fail at runtime. Consider making library creation a no-op (create only when adding films), or introduce a separatelibrariestable; in any case, don’t write a placeholder entry with a fakefilmId.This issue also appears on line 133 of the same file.
Logging format string has a stray trailing quote:
descriptionLength={}'. This will produce confusing log output and can break log parsing. Remove the extra'so the message template matches the arguments.@@ -0,0 +1,81 @@package com.project.movienight.application.servicesIdempotency handling is unsafe: the event is inserted before processing, so if processing fails (exception or early return), retries will be skipped forever because
exists(eventId)becomes true. Also, theexists+savesequence is race-prone and can still double-process concurrent requests. Prefer a single insert withON CONFLICT DO NOTHINGand only proceed when the insert actually happened (updatedRows==1), and/or store a processed status so failed events can be retried.Avoid modifying an existing Flyway migration (V1). Changing previously-applied migration files will cause Flyway checksum validation failures on any environment that has already run V1, blocking startup/migrate. Add a new migration (e.g., V4__extend_schema.sql) with ALTER TABLE statements instead.
Fixed in
50923e2. I restoredV1__init.sqlto baseline and moved the schema extensions into a new migrationV6__extend_schema.sqlso V1 is no longer modified. UI screenshot: N/A (backend-only change).@@ -20,70 +24,105 @@ import java.util.UUIDclass FilmLibraryService(Fixed in
50923e2.create()no longer persists a placeholder row withfilmId = libraryId; it now avoids creating fake library entries. UI screenshot: N/A (backend-only change).@@ -0,0 +1,143 @@package com.project.movienight.adapters.jellyfinFixed in
50923e2. I corrected the status check to requireresponse.statusCode() in 200..299so non-2xx responses now fail as intended. UI screenshot: N/A (backend-only change).@@ -0,0 +1,81 @@package com.project.movienight.application.servicesFixed in
50923e2. I removed theexists + saveflow and now gate processing on a single insert (ON CONFLICT DO NOTHINGvia affected rows). For failures/early-return cases, the inserted event is deleted so retries remain possible. UI screenshot: N/A (backend-only change).@@ -0,0 +36,4 @@throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "Invalid plugin token")}}Fixed in
50923e2. The events endpoint now rejects requests with503 Service Unavailablewhenintegrations.jellyfin.enabledis false. UI screenshot: N/A (backend-only change).Fixed in
50923e2. I removed the stray trailing quote from the log template string. UI screenshot: N/A (backend-only change).