feat: add subscription groups server contract - #76
Conversation
Introduce account-scoped named groups without changing the existing flat subscription record or global feed contract. Filtered feeds project from one shared snapshot and bind cursors to the selected group view, keeping refresh and cache behavior focused while preserving ungrouped subscriptions. Constraint: Start from dev and keep the first contribution Server-only Constraint: Preserve the existing global feed and ungrouped subscriptions Rejected: Per-group feed snapshots | adds cache invalidation and refresh fanout Confidence: high Scope-risk: moderate Directive: Keep filtered cursors bound to their subscription selection Tested: ./gradlew check shadowJar (997 tests, OpenAPI, coverage, fat JAR) Not-tested: Live frontend integration, deferred to the follow-up Frontend PR
Prune only memberships whose channels disappear from a replacement import or restore. This avoids orphaned rows without discarding assignments for channels that remain subscribed. Constraint: Existing backup formats do not carry subscription-group metadata Rejected: Clear every membership during restore | loses still-valid assignments Confidence: high Scope-risk: narrow Directive: Canonicalize restored URLs before pruning group memberships Tested: ./gradlew check shadowJar (998 tests, OpenAPI, coverage, fat JAR) Not-tested: Restoring group definitions into a different account
Priveetee
left a comment
There was a problem hiding this comment.
Hey, first thx a lot for taking the time to work on this!
I went through the database changes, routes, account isolation, feed filtering, restore behavior, OpenAPI and tests.
Honestly the base is really good. Groups are correctly isolated per account, one channel can be in multiple groups, the ungrouped feed is handled properly, and reusing the existing subscription feed snapshot makes sense.
I found a few things that need to be fixed before merge:
-
The important one is backups. Groups and their channel memberships are not exported right now. Restoring on a fresh instance would restore the subscriptions, but all the organization created by the user would be lost. Both the groups and their memberships need to be included in TypeType backups.
-
There is also an edge case with pagination. The cursor only remembers the group ID and filter, while the group membership is loaded again for every page. If someone edits the group between two pages, the next page can skip or repeat videos. The cursor needs to keep the same group membership snapshot for the full pagination session.
-
Small OpenAPI mismatch:
subscribedAtis required in the subscription creation schema, but Server actually generates it and ignores the submitted value. It would be cleaner to have a separate request schema where this field is not required.
Could u also split the first commit please? It currently contains 1,174 insertions, and I try to keep commits below 290 insertions so it stays easy to understand later why each part changed. Separating the database/model work, group API, feed filtering, backup support and tests would make the history much easier to follow.
I ran the full validation: 998 tests passed, including OpenAPI validation, coverage and the production jar build. I also checked it together with the current Server changes and all 1,036 tests passed there.
So yeah, no need to rebuild everything from scratch at all. The base is good, it just needs these points fixed and I will gladly review it again :)
Thx again, and have a great day!
Summary
Adds the backend contract for named subscription groups as the first Server-only part of TypeType-Video/TypeType#172.
GET /subscriptionsandGET /subscriptions/feedbygroupIdorungrouped=true;API changes
GET/POST /subscriptions/groupsPUT/DELETE /subscriptions/groups/{groupId}PUT/DELETE /subscriptions/groups/{groupId}/channelsGET /subscriptions?groupId=...GET /subscriptions?ungrouped=trueGET /subscriptions/feed?groupId=...GET /subscriptions/feed?ungrouped=trueThe handwritten OpenAPI contract now also documents the pre-existing
/subscriptionsoperations.Data and isolation
Adds
subscription_groupsandsubscription_group_memberships. Every group and membership lookup is scoped to the authenticated account. Group names are trimmed, limited to 100 characters, and case-insensitively unique per account. Membership creation requires both the group and subscription to belong to that account.Verification
Using the required JDK 25 toolchain:
This includes OpenAPI validation, coverage verification, focused route/service regressions, cursor/filter isolation, and the shadow JAR build.
Component follow-up
A separate TypeType-Frontend PR is required to add group management, channel assignment, and filtering UI. No Token, Downloader, or Player change is required.