Favorites API#
Per-user report favorites. Scope is always the caller (JWT sub) — there is no admin route for viewing / editing another user’s favorites.
- Endpoints:
GET /api/v1/users/me/favoritesPOST /api/v1/users/me/favorites{ reportId }DELETE /api/v1/users/me/favorites/{reportId}
- Auth:
[Authorize] - Feature flag:
FeatureFlags:EnableFavoritesWrites(default false) - Jira: BFC-23
- Legacy source:
wmReportsUserFavorites(composite PKFkRptId + FkUserId)
Flow — add favorite#
flowchart TD
Req[POST /users/me/favorites] --> Flag{EnableFavoritesWrites?}
Flag -->|false| R404[404]
Flag -->|true| JWT[Extract sub claim as userId]
JWT --> Svc[FavoritesService.Add]
Svc --> Chk{Row exists?}
Chk -->|yes| R204[204 No Content — idempotent]
Chk -->|no| Ins[INSERT wmReportsUserFavorites]
Ins --> R201[201 Created]Rules#
- Own-scope enforcement: caller identity comes from JWT
sub, never from URL. A malicious client cannot construct a route to touch someone else’s favorites — the route shape doesn’t allow it. - Idempotent add: re-adding an existing favorite returns 204, not 409. Simpler client logic.
- Composite PK prevents duplicates at the DB layer regardless of race conditions.
- Follow-up: module pinning (
wmFavoritetable) is a separate scope if needed later — not shipped in Phase 1.