- Update Actors table: Curator and Admin entries mention maintainer assignment - Update Role Design Philosophy: same clarification - Update Curator section: note about PersonMaintainer as credit/attribution - Update Admin section: same note
14 KiB
MilkyShots Use Cases
Target architecture for the new auth/permissions system. Replaces the current
EAccessLevel(User/Curator/Admin) with 5 actors,Album.UserOwnerIdis removed,Asset.OwnerId→UploadedBy(attribution only), and a Maintainer role bridges User ↔ Curator.
Actors
| Actor | Description | Notes |
|---|---|---|
| Anonymous | Unauthenticated visitor | Can only see Public content (per #93 visibility levels) |
| User | Registered, authenticated account | Sees Public + Protected content |
| Maintainer | Assigned to zero or more cosplayers | Two-dimensional role: scoped cosplayer management (CRUD on albums/assets/profiles for assigned cosplayers only) plus unscoped tag management (create/edit any tag, assign tags anywhere, conditional delete). Sees Private content for assigned cosplayers. Cannot create people or view stats |
| Curator | Full content editor | Full CRUD on all people, albums, assets, tags. Can view stats. Cannot manage users/settings/folders/jobs. May also be assigned as a maintainer of specific cosplayers for credited attribution |
| Admin | System administrator | Everything Curator can do + user management, settings, folders, jobs. May also be assigned as a maintainer of specific cosplayers for credited attribution |
Role Design Philosophy
The role hierarchy is strictly cumulative — each level inherits everything from the level below it.
| Role | What it adds | Key constraint |
|---|---|---|
| Anonymous | Browse public content | Cannot see anything above Public visibility |
| User | See Protected content, self-profile management |
Cannot mutate any content |
| Maintainer | Two capabilities: (A) cosplayer-scoped curator powers (albums, assets, profiles for assigned cosplayers), (B) global tag management (create, edit, assign, conditional delete) | Cannot create/delete people. Cosplayer management is gated by PersonMaintainer assignment. A Maintainer may have zero cosplayer assignments — in that case only tag management applies |
| Curator | Unscoped content CRUD on people, albums, assets, tags; view stats | Cannot manage users, settings, folders, or jobs. May be assigned as a maintainer of specific cosplayers (credited attribution, not access gating) |
| Admin | User management, maintainer assignment, settings, folders, jobs | No restrictions. May be assigned as a maintainer of specific cosplayers (credited attribution, not access gating) |
Visibility & #93 Integration
Per #93, EVisibility has three tiers: Public, Protected, Private. The actor visibility rules are:
| Actor | Public | Protected | Private |
|---|---|---|---|
| Anonymous | ✓ | ✗ | ✗ |
| User | ✓ | ✓ | ✗ |
| Maintainer (unassigned) | ✓ | ✓ | ✗ |
| Maintainer (assigned cosplayer) | ✓ | ✓ | ✓ |
| Curator | ✓ | ✓ | ✓ (non-deleted) |
| Admin | ✓ | ✓ | ✓ (all) |
Maintainer sees
Privatecontent only for cosplayers they're assigned to. For unassigned cosplayers they fall back to User-level visibility (Public+Protected).
Use Cases
Anonymous
| ID | Use Case | Endpoint | Visibility |
|---|---|---|---|
| UC-01 | Browse albums | GET /api/album |
Public only |
| UC-02 | View album details with assets | GET /api/album/{id} |
Public only |
| UC-03 | Search albums by title | GET /api/album?search= |
Public only |
| UC-04 | Browse people (cosplayers) | GET /api/person |
Public only |
| UC-05 | View person detail with albums | GET /api/person/{id} |
Public only |
| UC-06 | Search people by name | GET /api/person?search= |
Public only |
| UC-07 | Browse assets | GET /api/asset |
Public only |
| UC-08 | View asset details | GET /api/asset/{id} |
Public only |
| UC-09 | Search assets by type/date/random | GET /api/asset?type=&startDate=&endDate= |
Public only |
| UC-10 | View media files (original/thumb/preview) | GET /api/media/* |
Public only |
| UC-11 | Browse tags | GET /api/tag |
All |
| UC-12 | View tag hierarchy (children/ancestors) | GET /api/tag/{id} |
All |
| UC-13 | Register a new account | POST /api/auth/register |
— |
| UC-14 | Login | POST /api/auth/login |
— |
User (all Anonymous +)
| ID | Use Case | Endpoint | Scope |
|---|---|---|---|
| UC-15 | View protected albums | GET /api/album (with auth) |
Public + Protected |
| UC-16 | View protected album details | GET /api/album/{id} (with auth) |
Public + Protected |
| UC-17 | View protected assets | GET /api/asset (with auth) |
Public + Protected |
| UC-18 | View protected asset details | GET /api/asset/{id} (with auth) |
Public + Protected |
| UC-19 | View protected media files | GET /api/media/* (with auth) |
Public + Protected |
| UC-20 | View protected people with their albums | GET /api/person/{id} (with auth) |
Public + Protected |
| UC-21 | View own user profile | GET /api/user/{id} |
Self |
| UC-22 | Update own profile (username, email, password) | POST /api/user/update |
Self |
| UC-23 | Logout (invalidate refresh token) | POST /api/auth/logout |
— |
| UC-24 | Refresh access token | POST /api/auth/refresh |
— |
Protected =
Visibility == Protectedper #93. Private content requires assignment (Maintainer) or elevation (Curator+).
Maintainer (all User +)
Assigned to zero or more cosplayers (Person) via the PersonMaintainer table.
Scoped powers: full CRUD on albums and assets for assigned cosplayers. Sees Private content for assigned cosplayers.
Unscoped powers: create, edit, and assign tags to any content. Conditional tag deletion.
A Maintainer with no cosplayer assignments still retains full tag management capabilities.
| ID | Use Case | Endpoint | Scope |
|---|---|---|---|
| UC-25 | Create album for assigned cosplayer | PUT /api/album |
Assigned cosplayers only |
| UC-26 | Update assigned cosplayer's albums | POST /api/album/{id} |
Assigned cosplayers only |
| UC-27 | Bulk update assigned albums | POST /api/album |
Assigned cosplayers only |
| UC-28 | Delete assigned cosplayer's albums | DELETE /api/album/{id} |
Assigned cosplayers only |
| UC-29 | Bulk delete assigned albums | DELETE /api/album |
Assigned cosplayers only |
| UC-30 | Update assigned cosplayer's profile | POST /api/person/{id} |
Assigned cosplayers only |
| UC-31 | Upload asset (attributed as uploader) | PUT /api/asset |
Assigned cosplayers' albums |
| UC-32 | Update asset metadata in assigned albums | POST /api/asset/{id} |
Assigned cosplayers only |
| UC-33 | Bulk update assets in assigned albums | POST /api/asset |
Assigned cosplayers only |
| UC-34 | Soft-delete asset in assigned albums | DELETE /api/asset/{id} |
Assigned cosplayers only |
| UC-35 | Bulk soft-delete assets in assigned albums | DELETE /api/asset |
Assigned cosplayers only |
| UC-36 | Create tag | PUT /api/tag |
— |
| UC-37 | Assign/unassign tags to any content | POST /api/album/{id} / POST /api/asset/{id} |
Unscoped (any content) |
Maintainers cannot create people or view stats. They can create and edit any tag, and assign tags to any content. Tag deletion is allowed only if all content using that tag is maintained by them. Moving a Maintainer's last cosplayer assignment (or setting them to zero assignments) leaves them with only tag management powers.
Curator (all User + Maintainer +)
Full content management — no assignment boundaries.
Note: Curators may also be assigned as maintainers of specific cosplayers via the PersonMaintainer table, serving as credited attribution (specifically credited to work on assets from that cosplayer). This does not gate their access — they already have full CRUD on all content — but signals a direct contributor relationship.
| ID | Use Case | Endpoint |
|---|---|---|
| UC-38 | Create cosplayer | PUT /api/person |
| UC-39 | Update any cosplayer | POST /api/person/{id} |
| UC-40 | Bulk update any cosplayer | POST /api/person |
| UC-41 | Delete any cosplayer | DELETE /api/person/{id} |
| UC-42 | Bulk delete cosplayers | DELETE /api/person |
| UC-43 | Create album (for any cosplayer) | PUT /api/album |
| UC-44 | Update any album | POST /api/album/{id} |
| UC-45 | Bulk update any albums | POST /api/album |
| UC-46 | Delete any album | DELETE /api/album/{id} |
| UC-47 | Bulk delete any albums | DELETE /api/album |
| UC-48 | Upload asset (for any cosplayer) | PUT /api/asset |
| UC-49 | Update any asset | POST /api/asset/{id} |
| UC-50 | Bulk update any assets | POST /api/asset |
| UC-51 | Soft-delete any asset | DELETE /api/asset/{id} |
| UC-52 | Bulk soft-delete any assets | DELETE /api/asset |
| UC-53 | Create tag | PUT /api/tag |
| UC-54 | Update tag | POST /api/tag/{id} |
| UC-55 | Bulk update tags | POST /api/tag |
| UC-56 | Delete tag | DELETE /api/tag/{id} |
| UC-57 | Bulk delete tags | DELETE /api/tag |
| UC-58 | View instance statistics | GET /api/stats |
Admin (all Curator +)
Admins may also be assigned as maintainers of specific cosplayers via the PersonMaintainer table, serving as credited attribution (specifically credited to work on assets from that cosplayer). Like Curators, this is a signalling mechanism rather than a gating one — Admins already have unrestricted access.
| ID | Use Case | Endpoint |
|---|---|---|
| UC-59 | List all users | GET /api/user |
| UC-60 | Create user with any role | PUT /api/user |
| UC-61 | Update any user (ban, role change, soft-delete) | POST /api/user/update |
| UC-62 | Soft-delete user | DELETE /api/user/{id} |
| UC-63 | Assign/revoke maintainer-to-cosplayer links | TBD |
| UC-64 | Manage application settings (CRUD + delete-all) | GET/PUT/POST/DELETE /api/settings |
| UC-65 | List tracked folders | GET /api/folder |
| UC-66 | Create folder | PUT /api/folder |
| UC-67 | Update folder | POST /api/folder/{id} |
| UC-68 | Get folder detail | GET /api/folder/{id} |
| UC-69 | Get random sample paths from folder | GET /api/folder/{id}/sample-paths |
| UC-70 | Delete folder | DELETE /api/folder/{id} |
| UC-71 | List active root jobs | GET /api/jobs |
| UC-72 | List past root jobs (paginated) | GET /api/jobs/past |
| UC-73 | Get job children (delta sync) | GET /api/jobs/{parentId}/children |
| UC-74 | Get job status by ID | GET /api/jobs/{jobId} |
| UC-75 | Cancel job | DELETE /api/jobs/{jobId} |
| UC-76 | Enqueue background job | PUT /api/jobs |
| UC-77 | View any content regardless of visibility/deletion | All GET endpoints |
Permission Matrix
| Capability | Anon | User | Maint | Curator | Admin |
|---|---|---|---|---|---|
| Browse/search public content | ✓ | ✓ | ✓ | ✓ | ✓ |
| Register / Login | ✓ | — | — | — | — |
| View protected content | ✗ | ✓ | ✓ | ✓ | ✓ |
| Profile self-management | ✗ | ✓ | ✓ | ✓ | ✓ |
| Edit assigned cosplayer's profile | ✗ | ✗ | ✓ | ✓ | ✓ |
| CRUD albums for assigned cosplayer | ✗ | ✗ | ✓ | ✓ | ✓ |
| Upload/update/delete assets (assigned) | ✗ | ✗ | ✓ | ✓ | ✓ |
| Create cosplayers | ✗ | ✗ | ✗ | ✓ | ✓ |
| Create tags | ✗ | ✗ | ✓ | ✓ | ✓ |
| Assign tags to content | ✗ | ✗ | ✓ (any) | ✓ (any) | ✓ (any) |
| Edit any tag | ✗ | ✗ | ✓ | ✓ | ✓ |
| Delete tag | ✗ | ✗ | ✓* | ✓ | ✓ |
| View statistics | ✗ | ✗ | ✗ | ✓ | ✓ |
| Manage users (CRUD, roles, bans) | ✗ | ✗ | ✗ | ✗ | ✓ |
| Assign maintainers to cosplayers | ✗ | ✗ | ✗ | ✗ | ✓ |
| Settings / Folders / Jobs | ✗ | ✗ | ✗ | ✗ | ✓ |
| View private content | ✗ | ✗ | ✓ (assigned only) | ✓ (any) | ✓ (any) |
| View deleted content | ✗ | ✗ | ✗ | ✗ | ✓ |
* Maintainer can delete a tag only if all content using it is content they maintain.
DB Schema Changes
| Change | Detail |
|---|---|
Album.UserOwnerId |
Remove — albums belong to cosplayer only (PersonOwnerId). Existing albums with no PersonOwnerId are orphaned until a Curator/Admin assigns them. The UI will show a list of all contributors (uploaders) to an album rather than a single owner |
Asset.OwnerId → Asset.UploadedBy |
Rename — attribution only, no permission gating. Scanner-created assets (no uploading user) default to the admin account (first user) or a configurable system uploader stored in Settings |
PersonMaintainer join table |
New M:N — PersonId, UserId. Cascade-deleted when the cosplayer is removed. If that was a maintainer's only assignment, they retain their tag management powers but lose cosplayer-scoped access |
EAccessLevel enum |
Add Maintainer value. If preceded by the CurrentUser scoped service refactor: Anonymous=0, User=1, Maintainer=2, Curator=3, Admin=4. Otherwise: User=0, Maintainer=1, Curator=2, Admin=3. Migration must remap existing int values. Important: do not risk a privilege de-escalation — validate that at least one Admin exists post-migration |
EVisibility enum |
New per #93 — Public / Protected / Private on Person, Album, Asset |
| System uploader setting | New Setting entry — configurable user ID that scanner-created assets are attributed to. Defaults to the first-created (admin) user |
API Conventions (TBD)
| Decision | Options | Status |
|---|---|---|
| Maintainer assignment endpoint | Reuse POST /api/user/update with a maintainerOf field, or dedicated endpoints |
Deferred to implementation |
CurrentUser scoped service |
Replace inline authService.GetUserData(User) calls |
Separate issue |
| Controller refactoring | Replace [Authorize(Roles)] with policy-based auth |
Separate follow-up |
See also: #93 Visibility Levels, #94 Curation Mode, #79 Maintainer Role (superseded)