Files
MilkyShots/CHANGELOG.md
T
2026-08-17 13:44:45 +02:00

50 KiB
Raw Blame History

Changelog

[1.0.3.2] - 2026-08-17

🚀 Features

  • Add personOwnerId album filter and opt-in asset IncludeCount

Performance

  • Page cosplayer albums via the album endpoint and skip count queries
  • Cache thumbnails and previews in the browser for 24h
  • Add filtered IX_Assets_VisibleCreatedAt index for the default listing
  • Server-side seeded shuffle, DTO projection, and opt-in count
  • Project album assets to DTO in SQL and slim the Find paths
  • Push album filter/search/sort/pagination to SQL in person FindVisible

🐛 Bug Fixes

  • Add auto-save middleware as a safety net for the Save() pattern
  • Desloppify review fixes: PathFromGuid extraction, RegexHighlighter dedup, port default fix

🚜 Refactor

  • Quality improvements from the desloppify scan

⚙️ Miscellaneous Tasks

  • Update desloppify scorecard and add it to the README

[1.0.3.1] - 2026-07-22

🚀 Features

  • Add sliding-window page buffer to AlbumGrid and CosplayerGrid with scroll-based observer reattach
  • Embed git version in WASM footer via AssemblyInformationalVersion

🐛 Bug Fixes

  • Use status CSS variables for progress bar segment colors
  • Eliminate masonry layout race on infinite scroll and banner double-fetch (#146)
  • Masonry items stacking on infinite scroll — missing @ on ViewMode binding (#146)
  • Prevent infinite scroll cascade by debouncing observer reattach and disabling scroll anchoring

🚜 Refactor

  • Replace IntersectionObserver with input-event-based infinite scroll

⚙️ Miscellaneous Tasks

  • Scripts and run configs to automate version injection
  • Removed outdated agent.md

[1.0.3] - 2026-07-21

🐛 Bug Fixes

  • Cropper handle size constant mismatch (14→18 px)
  • Jobs past tab zero-based pagination
  • Show registration disabled message on 403
  • Hide register form when registration is disabled
  • Allow manual folder scan when scheduled scan is off
  • Prevent masonry layout shift on infinite scroll
  • Order album assets by CreatedAt in album detail (#144)
  • Replace overflow-y with JS masonry for stable album layout (#146)
  • Add aspect-ratio to album cards for stable masonry height (#146)
  • Use per-card aspect-ratio from cover dimensions for stable masonry layout (#146)
  • Restore masonryLayout.dispose that was lost in reset edit
  • Use pre-pagination album count (#143)
  • Sort album assets by OriginalFilename instead of CreatedAt (#144)

[1.0.2] - 2026-07-17

🐛 Bug Fixes

  • Remove redundant AddJsonFile calls that overrode env vars

⚙️ Miscellaneous Tasks

  • Auto-run on tags only, manual dispatch on branches

[1.0.1] - 2026-07-17

🐛 Bug Fixes

  • Use explicit domain git.r3d.codes instead of gitea.server_url
  • Sanitize tag names for Docker compatibility (replace / with -)
  • Lowercase repository name for Docker compatibility
  • Match matrix service names to actual directory case (Lactose/MilkStream)
  • Remove gha cache config (cache server unreachable from builder)

Performance

  • Add BuildKit cache mounts for NuGet packages in Dockerfiles

⚙️ Miscellaneous Tasks

  • Add workflow_dispatch trigger with version input
  • Also run on push to master
  • Also run on develop and hotfix/* branches
  • Pass SixLaborsLicenseKey as build arg for lactose
  • Use REGISTRY_TOKEN (PAT) instead of GITEA_TOKEN for registry push

CI

  • Added sixlabors license key to the docker file for lactose

[1.0] - 2026-07-16

🚀 Features

  • (API) Adds Authentication System (Needs Testing)
  • (API) Adds UserRepository.cs
  • (API) Adds Password hashing
  • (API) Adds Password hashing
  • (API) Implements user delete endpoint
  • (API) Adds stubs for AssetController.cs
  • (API) Adds Album endpoint Stubs
  • (API) Adds TagController class
  • (API) Adds Tag endpoint implementation
  • (API) Adds Repository implementation (not tested yet)
  • (API) Implements TagController With Bulk Requests
  • (API) Adds person stub endpoint
  • (API) Added Resolution, mimetype and extra media data on asset table
  • (API) Adds computed file hash field in Asset
  • (API) Adds Folder and Asset entities in the DB
  • (API) Implemented FolderController and their respective Mappers/DTO/Repository interface and it's own implementation
  • [breaking] Upgraded project to .Net 9.0
  • (API) Implemented Settings Endpoint
  • (API) Implemented Media endpoint and relative Repository and DTO
  • (DB) Switched to PostgreSQL connector
  • (DB) [breaking] Change to use database pgvecto-rs
  • (DB) [breaking] Regenerated migrations for PostgreSQL switch
  • Switched to on the fly connection string generation
  • (DbContext) Adds Initialization for Development environment
  • (API) Adds Authentication Result as DTO for authentication
  • (Lactose) Adds RefreshToken
  • (Lactose) Adds DB Context Snapshot
  • (Lactose) Adds RefreshToken Endpoint
  • (DB) Changed Asset table to have OriginalPath as Unique Index
  • Added a settings enum + it's own extension class to retrieve interpretation type and string name in DB
  • (db) Adds Migration for Settings in LactoseDbContext
  • Added disposability to some repositories, changed the FileSystemScanner service to be a singleton.
  • (API) Added Access level to the data returned from authentication actions
  • (frontend) Upgraded login to new API changes
  • (API) Added get-all endpoint for settings controller.
  • (frontend) Added settings service
  • (API) Added Access level to the data returned from authentication actions
  • (frontend) Added login and JWT token auto-refresh
  • (frontend) Adds ServiceBase and AuthServiceBase abstract classes
  • (frontend) Login and logout now properly work
  • (frontend) Added folders service
  • (frontend) Nav menu restyle
  • (API) Adds method to modify the FileWatcherService: folders, time
  • (API) Edits SettingsRepository to manage FileWatcher Service
  • (frontend) Editing of settings and addition/editing of folder paths
  • (frontend) Added folder removal in settings
  • (API) Added get-all endpoint for settings controller.
  • (frontend) Added settings service
  • (API) Added Access level to the data returned from authentication actions
  • (frontend) Added login and JWT token auto-refresh
  • (frontend) Adds ServiceBase and AuthServiceBase abstract classes
  • (frontend) Login and logout now properly work
  • (frontend) Added folders service
  • (frontend) Nav menu restyle
  • (API) Adds method to modify the FileWatcherService: folders, time
  • (API) Edits SettingsRepository to manage FileWatcher Service
  • (frontend) Editing of settings and addition/editing of folder paths
  • (frontend) Added folder removal in settings
  • Migrate MilkStream frontend from Blazor SSR to Blazor WASM
  • (cors) Support semicolon-separated CorsAllowedOrigins env var
  • Add ParentJobId to JobStatusDto for job hierarchy tracking
  • Add ParentJobId to Job base class
  • Set ParentJobId on child jobs for ThumbnailJob, FileSystemCrawlJob, PHashJob
  • Map ParentJobId in JobMapper
  • Add generic reusable components ProgressBar, CollapsibleSection, PollRateSelector
  • Add JobRow, JobChildrenSummary, JobSection, JobTree components
  • Redesign Jobs page with compact hierarchical layout, poll rate selector, and PHash button; remove JobCard
  • Optimize jobs API with pagination, DB persistence, and cleanup
  • Add GetAssetsMissingMetadata repository method for metadata job
  • Implement MetadataJob for image resolution extraction
  • (docker) Add named volumes for thumbnails and previews
  • Unify settings pages into sidebar + detail panel with auto-save
  • (assets) Add ThumbnailSize column to track generated thumbnail dimensions
  • (repository) Add GetAssetsMissingOrWrongThumbnail to interface
  • (repository) Implement GetAssetsMissingOrWrongThumbnail query
  • (thumbs) Read ThumbnailSize setting, invalidate wrong-sized thumbnails, set size after gen
  • (db) Add migration for ThumbnailSize column on Assets
  • (jobs) Add CompletedWithErrors status for parents with failed sub-jobs
  • (ui) Show CompletedWithErrors as orange and group sub-jobs by status
  • (jobs) Apply batching to PHashJob and MetadataJob
  • (settings) Add JobBatchSize setting for batch job sizing
  • (settings) Add JobBatchSize setting for batch job sizing
  • (settings) Add runtime-configurable Po2W slider limits + split thumbnail/preview ranges
  • (folders) Add regex pattern field with named groups, syntax highlighting, and sample path preview
  • Masonry gallery on homepage with infinite scroll
  • Pass JWT token in media URLs for authenticated thumbnail/preview requests
  • Make navbar sticky during infinite scroll
  • Add PreviewJob and upgrade thumbnails to WebP
  • Add CreatePersons and CreateAlbums jobs
  • Add stacked progress bar for parent jobs with sub-job breakdown
  • Improve logging and progress reporting for album/person jobs
  • Add statistics page with aggregate asset/user/system stats via fast DB queries
  • Add thousands separators to job status numbers
  • Extend AssetPreviewDto with album and cosplayer names
  • Add cosplayer and album name overlays on home page
  • Add full-size view and download buttons in preview overlay
  • Add bidirectional infinite scroll (up and down)
  • Implement seed-based deterministic random ordering for home page
  • Add data completeness indicators to statistics page
  • Add CoverAssetId to albums with resolution data in full DTO
  • Add AlbumService and PersonService to WASM client
  • Add albums list page and album detail page with inline preview
  • Auto-assign album cover from first alphabetically-sorted asset
  • Make album names clickable links in home tile hover and preview
  • Justified gallery layout for album detail page
  • View mode selector for albums page (masonry/grid/list)
  • (admin) Add user management page for admins
  • (admin) Add inline editing for username, email, and password
  • (stats) Add percentage and stale counters to completeness cards
  • (backend) Add ProfileAssetId to Person model + migration
  • (dtos) Update Person DTOs with ProfileAssetId and album previews
  • (backend) Eager-load ProfileAsset and Albums in PersonRepository
  • (backend) Add PersonMapper with ToPersonPreviewDto and ToPersonDetailedDto
  • (backend) Implement person detail, update, and delete endpoints
  • (client) Extract AlbumCard reusable component, update Albums.razor
  • (client) Add PersonService client methods and PersonForm component
  • (client) Add Cosplayers and CosplayerDetail pages, fix NavMenu, add modularity docs
  • (css) Add Cosplayers and CosplayerDetail scoped CSS with banner, grid, and card styles
  • (backend) Add ProfileCropX/Y to Person model for profile picture cropping
  • (ui) Add circular profile picture cropper with drag-to-pan
  • (ui) Redesigned profile cropper with movable circle, dimmed exterior, square boundary, zoom controls; added ProfileCropZoom to model; switched avatars to background-image for zoom support
  • (ui) Add New Cosplayer button on list page with create endpoint and form
  • (ui) Unassigned album selector in PersonForm, Add Albums button in CosplayerDetail
  • (dto) Add RemovePerson flag to AlbumUpdateDto for explicit person unlinking
  • Person hard delete with album cascade, AlbumCard select mode, cosplayer list multi-select
  • Infinite scroll for albums on cosplayer detail page
  • Migrate to UTC timestamps — remove legacy Npgsql timestamp behavior
  • Make album name in image previewer an anchor element for native navigation
  • Allow users to update own albums and curators to update any album
  • Add OldPassword field to UserUpdateDto for self-service password change
  • Enforce old-password verification on own password change, allow admin override
  • Add password change UI with strength bar and validation on user profile page
  • Add server-side password policy validation (admin bypass)
  • (ui) Redesign user profile page with avatar initials and edit profile modal
  • (ui) Rewrite admin users page with sortable table, search, and modal-based editing
  • (ui) Show avatar initial in navbar instead of generic icon
  • (ui) Album detail multi-select edit mode, cosplayer link, move edit button (#63)
  • (api) Add BulkDeleteAlbumsAsync for bulk album deletion
  • (ui) Add album select/edit mode with bulk deletion
  • (ui) Redesign jobs page with tabs, search, filters, and mobile cards
  • Add LastChange tracking to JobStatus
  • Add ModifiedAt to JobRecord with delta query support
  • Implement delta-based children endpoint with ?since parameter
  • Add delta merge logic to job tree components
  • Poll children for all active roots and fix segment progress bar colors
  • Return-url login redirects + keepalive + cosplayers fix
  • Add password strength validation to registration page
  • Hide cosplayers with no visible content from regular users
  • (css) SCSS foundation with Bootstrap 5.3.7 source, new dark navy theme, Inter font
  • (ui) CSS variables for .razor.css, job type colors, interactive states, gradients
  • (jobs) Extract all job-type colors to configurable SCSS variables
  • (ui) CosplayerDetail banner empty gradient uses accent theme
  • (ui) Aggressive gradients on navbar, buttons, modal headers
  • (ui) Page background gradient, status/strength CSS vars, nav/image polish
  • (ui) Replace default favicon with MilkyShot logo SVG
  • (cropper) Circle handles with accent color, black border, drop shadow
  • (gradients) Strengthen all gradients for more aggressive effect
  • (ui) Apply metallic gradient to all buttons and surfaces
  • (ui) Add eye toggle button to show/hide password on all password fields
  • (api) Add sort parameters to pagination DTOs
  • (api) Add sorting and unassigned filter to AlbumRepository.SearchQuery
  • (api) Pass sort and filter params through AlbumController.Search
  • (ui) Add SortFilterBar component and update Albums page with search/sort
  • (ui) Extract AlbumGrid to isolate grid re-renders from SortFilterBar
  • (api) Add SearchQuery to PersonRepository with sort/search/pagination
  • (api) Paginate PersonController.GetAll with sort/search params
  • (ui) Convert Cosplayers page to infinite scroll with sort/search toolbar
  • (ui) Extract CosplayerGrid to isolate grid re-renders from SortFilterBar
  • Add SearchDropdown typeahead component
  • Wire SearchDropdown into NavMenu
  • Make search dropdown headers selectable with keyboard and mouse
  • Parse ?search= query param on Cosplayers and Albums pages
  • (cosplayer-detail) Add SortFilterBar for album search and sort
  • (butter) Add EVisibility enum, Maintainer access level, and SystemUploaderId setting
  • (butter) Update DTOs for visibility, renamed Owner→UploadedBy, removed IsPublic/Owner fields
  • (models) Update models for auth redesign — rename Owner→UploadedBy, drop UserOwnerId/IsPubliclyShared, add EVisibility, PersonMaintainer
  • (infra) Update DbContext and mappers for auth redesign — new relationships, PersonMaintainer, conditional Visibility
  • (repos,controllers) Update repositories, interfaces, controllers for auth redesign — visibility filtering, UploadedBy/Uploader rename, Maintainer support
  • (db) Add migration for auth redesign — drop IsPubliclyShared/UserOwnerId/SharedWith, add Visibility, PersonMaintainer, rename OwnerId→UploadedBy
  • (auth) Complete Maintainer role — add PersonMaintainer checks, update controller authz, pass uploadedBy search param
  • Add MaintainedPersonIds to UserInfoDto with backend plumbing
  • Add Maintainer to admin user dropdowns and role badges
  • Add Visibility dropdown to album and person create/edit forms
  • Add Protected Assets card to stats page
  • Expand UI gating to include Maintainer with scope-aware CanEdit
  • Maintainer cosplayer assignment in admin user edit modal
  • Maintainer assignment UI for cosplayers, maintainer display on user page
  • Expand user page edit modal for admins with access level, maintainer assignment, and danger zone
  • Make usernames clickable on admin users page, linking to /User/{id}
  • Add docker-compose.debug.yml and UseWebAssemblyDebugging for WASM debugging
  • Add role-visible colored borders on albums and assets based on item state (#78)
  • Add bulk delete and visibility change to AlbumDetail select mode
  • Show visibility/deleted breakdown in album header in select mode
  • Add Select All / Deselect All button in album select mode
  • Add album-level bulk actions to CosplayerDetail page
  • Cascade visibility to albums and assets with lower-only rule
  • Add multiselect editing controls to Cosplayers page
  • Wire up SystemUploaderId setting — seed, UI, and crawl job backfill
  • Bulk cosplayer assignment for albums from multiselect mode
  • Add reusable ConfirmDialog component
  • Add visibility-colored borders to cosplayer cards in selection mode
  • Add rate limiting with configurable buckets
  • Apply rate-limit buckets to controllers
  • Add AlbumMergeDto and PersonMergeDto
  • Add MergeAlbums to album repository
  • Add MergePeople to person repository
  • Add merge endpoints to AlbumController and PersonController
  • Add frontend service methods for merge, bulk update, and bulk delete people
  • Add MergeModal shared component for merge destination selection
  • Add Merge button to Albums.razor with AlbumGrid preview access
  • Add Merge button to Cosplayers.razor with CosplayerGrid preview access
  • Add Merge Albums button to CosplayerDetail.razor
  • Add Unlink cosplayer button to AlbumDetail.razor
  • Add UnlinkedAssetGroupDto and extend AssetSearchOptionsDto with unlinked/folder/uploader filters
  • Add trigram GIN index on Asset.OriginalFilename for efficient ILike search
  • Extend AssetRepository with unassigned, folderId, uploadedBy, search filters and GetUnlinkedGroups
  • Extend AssetController with unlinked-groups endpoint and pass new search/unassigned/folder/uploader params
  • Extend AssetService with unassigned/folder/uploader/search params and GetUnlinkedGroupsAsync
  • Add AlbumAssetPicker modal component with drillable folder sidebar, search, and multi-select
  • Integrate AlbumAssetPicker into AlbumDetail with Add Assets button and merge handler
  • Add file-browser BrowseUnlinkedAssets endpoint with directory tree from OriginalPath
  • Redesign AlbumAssetPicker with breadcrumb navigation, directory drill-down, and file browser UX
  • Add collapsible sidebar toggle to AlbumAssetPicker folder browser
  • Add list/grid view toggle, bulk delete in maintenance mode, and /maintenance page
  • Add visibility and create-album actions, fix embedded viewport sizing

🐛 Bug Fixes

  • (API) Split authentication from user endpoint
  • (API) Fix retrieve of user authentication data
  • (API) Split authentication from user endpoint
  • (API) Fixes null exception against anonymous users requests
  • (API) Fix exception for UserRepository.cs
  • (API) Fix Password hasher dependency resolver
  • (API) Adds last login update on login
  • (API) Fixes null exception against anonymous users requests
  • (API) Fix exception for UserRepository.cs
  • (API) Fix Password hasher dependency resolver
  • (API) Adds last login update on login
  • (API) Remove login permission to Banned or Disabled Users
  • (API) User endpoints to be in line with new structure
  • (API) Switches tagSearch method from uint to int
  • (docker) Fixed Dockerfile stuck on old project name and build configs
  • (API) Added support for pagination on Asset GetAll Query
  • (API) Added deleted at field in UserInfo mappers
  • (API) Implements GetAll tags in tag Repository
  • (API) Wrong logger in album controller
  • (API) Standardized DTO namespaces
  • (API) Added required instead of null initialized strings where it didn't make sense to have a null string in Users DTOs
  • (API) Added missing Email field in UserInfoDto
  • (API) Marked as required both fields of BulkDto
  • (API) Marked as required both fields of credentials DTOs
  • (API) Marked as required the tag name in TagCreateDto
  • (API) Marked as required all the various required fields in person related DTOs
  • (API) Added null checking to folderRepository get operations in FolderController
  • (API) Added GetAll method to Folder Repository and controller
  • (API) [breaking] Marked required properties in Asset as required
  • (API) Added FindByPath in AssetRepository
  • (API) Allow Anonymous to use MediaEndpoint
  • (docker) Dockerfiles updated to use Net 8 as base images
  • (docker) Solved mismatch with base folders in both dockerfile and compose file
  • (docker) Applied "Docker" as environment when building the application in a container thus avoiding not getting the correct configuration overloads at run time.
  • (Docker) Removes Env var from where is not needed and add it to teh compose
  • (Docker) Add internal db port in appsettings.Development.json
  • (docker) [breaking] Postgres volume data was not named properly
  • (db) Added postgres switch for Legacy Timestamp behaviour
  • (API) Correct reference to the return type of result
  • (API) Fixes the Db Initializer on Production Environment
  • (DB) Added check for already existing assets on DB entry.
  • (Services) Added FileSystem scan service to the startup of the webserver.
  • (frontend) Adds the new services to the app startup configuration
  • (frontend) Added correct headers and response format to LoginService
  • (frontend) Adjusted SettingsService to work with List instead of SettingsDto object.
  • (API) Added SaveChanges to Settings repository, reflecting changes to he database
  • (API) Solved filesystem scanner not scanning
  • (frontend) Adds the new services to the app startup configuration
  • (frontend) Added correct headers and response format to LoginService
  • (frontend) Adjusted SettingsService to work with List instead of SettingsDto object.
  • (API) Added SaveChanges to Settings repository, reflecting changes to he database
  • (API) Solved filesystem scanner not scanning
  • Address code review findings (blocking .Result, async void handlers, email logging)
  • Handle stale ProtectedLocalStorage value crashing NavMenu deserialization
  • Serve appsettings.json dynamically from MilkStream to fix WASM BaseUrl in Docker
  • Support wildcard CORS origin for self-hosted Docker deployments
  • Replace CORS wildcard with explicit safe origins per environment
  • Add DB healthcheck and service_healthy condition to prevent lactose startup race condition
  • Catch OperationCanceledException from Task.Delay to prevent incorrect Completed status on cancellation
  • Notify auth info changed after token refresh and handle polling errors
  • Change ParentJobId to get/set for WASM compat, remove @key from JobTree, add debug panel
  • Handle 401 responses in JwtTokenRefresher by refreshing token and retrying
  • Redirect to login when token refresh fails in JwtTokenRefresher
  • Handle 401 in JobsService directly with refresh+retry
  • Add missing Butter.Types import in AssetRepository for EAssetType
  • Remove completed sub-jobs from list so master job can finish
  • Prevent master PHashJob from spinning indefinitely on sub-job completion
  • Use oninput for live slider value update and widen range layout
  • Add minutes unit to Folder Scan Interval description in default settings
  • Handle 401 transparently at AuthServiceBase level for all services
  • Redirect unauthenticated users from settings page to /login
  • Redirect unauthenticated users from jobs page to /login
  • (ui) Render child jobs in JobTree by skipping root filter at deeper levels
  • (db) Always override ThumbnailPath/PreviewPath values with local paths on init
  • (docker) Create thumbnails/previews dirs as app user so subdirs can be created at runtime
  • (ui) Restore auth in App.razor before rendering to prevent race redirect to /login
  • (phash) Display child jobs grouped by status
  • (jobs) Prevent silent crash on large thumbnail jobs and auto-refresh child jobs
  • (ui) Apply poll interval to child jobs, add @key for DOM reuse, guard admin pages
  • (ui) Submit login form on Enter key press
  • (jobs) Fix IntegrityCheckJob conditional + use soft-delete
  • (jobs) Add delay to JobManager main loop to prevent CPU spin
  • Add DeletedAt filter to asset batch queries to exclude soft-deleted assets
  • Add AssetUser many-to-many join table for SharedWith
  • Remove AspNetCore.SassCompiler to fix Docker startup crash
  • Proper bidirectional SharedWith many-to-many migration
  • (Lactose) Admin and Curators media visibility
  • Wire MaxConcurrentJobs to database setting on startup and runtime changes
  • Propagate cancellation to sub-jobs in batch processing jobs
  • Cancel past refresh loop when poll rate is set to Off
  • Make job cancellation work for all job states and types
  • Per-batch progress messages and counting bug in album/person jobs
  • Skip existing AlbumAsset relationships in CreateAlbumsJob to prevent duplicate key violations on re-run
  • Add JobBatchSize to DefaultSettings.json to prevent reset on restart
  • Populate LastLogin/BannedAt/UpdatedAt in UserInfoDto mapping
  • Rewrite TopTags query to avoid EF Core collection navigation translation error
  • Remove destructive People soft-delete in IntegrityCheckJob and drop duplicate hash stats
  • Move preview info text below image instead of overlaying on bottom border
  • Download button now fetches blob and triggers actual file download
  • Remove scroll position correction from LoadPreviousPage for smoother scroll-up
  • Propagate cancellation tokens through linked child job CTS
  • Album controller Save calls, person list endpoint, media empty path guard
  • Scoped CSS deep selectors for preview info text and filename binding
  • Switch album detail page to row-based flexbox masonry
  • Remove preventDefault from album links so they actually navigate
  • Remove content-visibility and contain-intrinsic-size from album detail tiles
  • Switch album detail grid from flexbox to CSS Grid
  • Use flexbox with align-items:flex-start for album detail grid
  • Unlock body scroll on navigation, reorder masonry for left-to-right flow
  • JS-based masonry for left-to-right item flow with varying heights
  • Faulty migration that could cause lactose crash on migration apply
  • Use CSS columns for albums page, keep JS masonry only for album detail
  • Override masonry inline styles with !important for grid mode
  • Force square aspect-ratio in grid mode over inline style
  • (controllers) Tighten asset visibility and media access checks
  • (AssetController) Correct search visibility filter for #11
  • (AlbumController) Exclude deleted assets from search visibility for #11
  • (admin) Add confirm/cancel for role change and prevent admin self-demotion
  • (user) Hash password in Create endpoint instead of storing raw
  • (ui) Remove broken onfocusout handler from role edit dropdown
  • (admin) Show inline errors instead of replacing entire page
  • (auth) Show ban/disabled message on login and force-logout on refresh
  • (auth) Detect banned/deleted user on page load via InitializeAsync
  • (frontend) Sorts setting by alphabetical
  • (Lactose) Change to use UtcNow, even if alredy working without timeline
  • (backend) Add [FromQuery] to person list endpoint to fix 415 error
  • (css) Move card styles to AlbumCard.razor.css, use ::deep for grid-to-card selectors
  • (ui) Larger cosplayer cards with profile pics, move edit buttons top-right, add masonry/grid toggle
  • (auth) Force logout on any refresh failure, redirect to login
  • (ui) Add scoped modal CSS to PersonForm for proper overlay rendering
  • (ui) Cosplayer cards now match album card style — image fills square, text overlay at bottom
  • (js) Set onload before src to handle cached images
  • (ui) Remove empty filler cells from banner mosaic, let overlay cover gaps naturally
  • (ui) Always render ProfileCropper in tree, use OnParametersSet to trigger JS init
  • (ui) Random 3 album covers max in banner, redesigned cropper with drag-to-move and drag-handle resize, image stays static
  • (ui) 4 corner handles on square boundary for resizing instead of single circular handle
  • (js) Handle positions relative to square, not viewport
  • (js) Corner-drag resize with fixed opposite corner, proper visual rate matching
  • (css) Show full image in cropper viewport (contain instead of cover)
  • (ui) Correct geometry — square outer, circle inscribed inside; image-relative crop coords with background-image viewport; correct display formula for background-position
  • (js) Adjust stored cropZoom by image aspect ratio factor so background-size formula matches circle
  • (js) Store cropZoom as image-relative fraction (square_side / image_displayed_width), no adjustment needed on save
  • (ui) Use pixel-exact transform positioning for avatar display instead of background-size formula
  • (js) Use correct opposite corners for TL/TR/BL resize handles
  • (js) Skip resize on first mousemove if mouse hasn't moved from mousedown position
  • (js) Resize calculations now in viewport pixels to avoid image-relative X/Y scale mismatch on non-square images
  • (api) Allow unlinking person from album by directly assigning null PersonOwnerId
  • (build) Remove stray semicolon in onclick lambda
  • Prevent album title from being overwritten when only setting Person in update DTO
  • (pr) Implement BulkUpdate, BulkDelete, revert docker-compose, explain [FromQuery]
  • (tests) Fix pre-existing auth route tests and handle empty unassigned albums gracefully
  • (test) Use response.body directly instead of JSON.parse (already parsed object)
  • (test) Update name assertion to match renamed person
  • Create AlbumSearchParametersDto, add album pagination to person detail, fix duplicate XML param
  • Cache random banner covers in field, not computed on every render
  • (ui) Responsive layout fixes for mobile portrait mode (closes #48)
  • (ui) Collapse AdminUsers table columns and actions on mobile (#48)
  • (frontend) Removed faulty d-flex tag on main object
  • (milkystream) Fix sorted masonry for albums
  • (ui) Prevent JobRow horizontal overflow on mobile portrait
  • (ui) Change AdminUsers mobile actions dropdown from dropup to dropdown
  • (ui) Reduce password input width on AdminUsers to prevent cell overflow
  • (ui) Stack setting card description and control vertically on mobile
  • (ui) Prevent layout shift from save indicator width change
  • (ui) Prevent save indicator from shifting adjacent controls
  • (ui) Stack setting card body vertically — description above, control + indicator below
  • (ui) Right-align number inputs, let them grow to fill card width
  • (ui) Replace inline save indicator with Bootstrap toast notification
  • (ui) Restore progress bar visibility on job rows
  • Resolve UI issues #61, #62, #66
  • (#62) Move mobile modal fix to global MilkyShot.css — scoped ::deep cannot pierce PersonForm root element
  • (#62) Use explicit top/left/right/bottom instead of inset, add !important to ensure position:fixed takes effect on mobile
  • (#62) Lock body scroll when modal forms open to prevent position:fixed breakage on mobile
  • Propagate server-side error messages from UpdateUserAsync to UI
  • Auto-close modal on password change success, add page-level success message
  • Center profile card on page
  • Wire profile icon in navbar to user profile page
  • Default sort users table by role descending (admin on top)
  • Use bold (700) instead of semi-bold for reliable font rendering
  • (mobile) Keep back button inline with title, collapse admin actions into dropdown
  • Batch-processing subjobs report correct status on asset failures
  • Remove double-count of failed assets in master Done handler
  • Metadata icon in dropdown uses text-light for visibility
  • Metadata icon visible in job list rows
  • Pass null since on first child fetch instead of DateTime.MinValue
  • Eagerly fetch children on load and hide sub-jobs placeholder
  • Re-render after eager child fetch so icons appear immediately
  • Eager-fetch children for all roots including past jobs
  • Update home logged-out message to match cosplayers wording
  • Update albums logged-out message to match home/cosplayers
  • Translate GetAllVisible to client-side eval for SharedWith navigation
  • Suppress nullable warnings on Include chain in GetAllVisible
  • Remove soft-delete from Person model
  • (jobs) Add hover/active variants for all job types via darken()
  • (ui) Modal icon order, fill all outline buttons
  • (favicon) Render MilkyShot logo as PNG favicon
  • (ui) Page bg radial gradient, navbar radial glow, favicon cache
  • (cropper) Revert ProfileCropper to inline modal
  • (cropper) Restore missing cropper CSS styles
  • (cropper) Add pointer-events:auto on handles, fix cursors
  • (ui) Fix float values in the cosplayer thumbnail and cosplayer card
  • (ui) Fix remaining float culture issues in CSS style attributes
  • (ui) Prevent infinite loading loop on cosplayers page with no data
  • (ui) Keep header and toolbar visible when albums search returns empty
  • (ui) Debounce search input and prevent backspace navigation
  • (ui) Refocus search input after debounce triggers reload
  • (ui) Move album grid CSS to AlbumGrid.razor.css for scoped isolation
  • (ui) Add height:100% to album-card-fallback so icon centers vertically in grid mode
  • (ui) Add margin-bottom to SortFilterBar for spacing from grid
  • (ui) Add ActionButtons slot to SortFilterBar, move album actions into bar
  • (ui) Push ActionButtons to right with ms-auto wrapper
  • (ui) Keep header and toolbar visible when cosplayers search returns empty
  • (ui) Move cosplayer grid CSS to CosplayerGrid.razor.css for scoped isolation
  • (ui) Move cosplayer actions into SortFilterBar, fix sortAsc always sending
  • Close outer div and remove invalid @{} blocks in SearchDropdown
  • Pressing enter with nothing selected does nothing
  • Move query param parsing to OnParametersSet
  • Parse search query before await in Albums OnInitializedAsync
  • Use case-insensitive ILike search for persons and albums
  • Override Bootstrap dropdown-menu display:none
  • Return 401 Unauthorized when user data is null in PersonController
  • Allow anonymous search for persons and albums
  • Materialize person search query before client-side visibility filter
  • Restrict user list to admin only
  • Add [FromQuery] to TagController.GetAll parameter
  • Use zero-based page numbers in AssetController to match API convention
  • Guard ILIKE filter in AlbumRepository.SearchQuery against null/empty query
  • Restore Include(p => p.Albums) in PersonRepository queries
  • Paginate PersonRepository.SearchQuery by ID before loading albums
  • Prevent duplicate @key errors across all list renderings
  • Filter album count by user visibility in person search
  • Restore ToAlbumPreviewDto mapper method per review feedback #91
  • Standardize pagination to zero-based across all layers
  • Move SharedWith visibility check to client side for translatable queries
  • Only reject Page < 0, keep original PageSize validation
  • Restore PageSize < 1 validation with upper limit of 250
  • (cosplayer-detail) Prevent banner image shuffle on album search/sort
  • (cosplayer-detail) Debounce search, keep page intact on filter changes
  • (cosplayer-detail) Remove search debounce, instant inline reload
  • Replace untranslatable Album navigation in stats queries with direct join table queries
  • Replace untranslatable Tags navigation in TopTags stats query with direct join table query
  • (albums) Use MaxPageSize constant for unassigned album fetch
  • Implement CosplayersMissingProfile stat
  • Make card components middle-clickable
  • Remove underline from album card person link
  • (album-form) Searchable person combobox with modal-safe positioning
  • (jobs) Use grey for queued segments in layered progress bar
  • (repo) Scope Maintainer to only maintained persons in GetAllVisible and SearchQuery
  • (controller) Scope Maintainer album visibility to only maintained persons
  • (controller) Scope Maintainer asset access to only maintained cosplayers in Get
  • (controller) Add Maintainer scope to Album BulkUpdate, Delete, BulkDelete
  • (mapper) Allow Maintainer to see Visibility field in DTO responses
  • (media) Replace bool parameter with EAccessLevel, add deleted asset check
  • (stats) Add ProtectedAssets count, fix PrivateAssets to count only Private
  • (dto) Default AssetCreateDto.Visibility to Private instead of Protected
  • (repo) Use PagedParametersDto.MaxPageSize const instead of hardcoded 150
  • (migration) Remap existing EAccessLevel values to prevent data corruption
  • (migration) Default Visibility to Protected instead of Public, preserve old IsPubliclyShared mapping
  • (dto) Make AssetCreateDto.UploadedBy nullable for scanner-created assets
  • (model) Add [PrimaryKey] annotation to PersonMaintainer for clarity
  • (repo) Scope AlbumRepository.SearchQuery maintainer visibility to maintained persons
  • (controller) Scope AssetController maintainer permissions via album→person chain
  • (mapper) Replace null-forgiving operator with null-conditional in AlbumMapper
  • (controller) Split Maintainer from User in AssetController.GetAll visibility filter
  • (media) Allow Maintainer to access media files for cosplayers they maintain
  • (mapper) Scope asset counts in album/ person previews to visible assets
  • Add missing app.css link to index.html
  • Null reference in User page maintainer display
  • Remove underline from user links, hide email from non-admin viewers
  • Remove underline from maintainer links, load assigned person names in user edit modal
  • NRE on user page when user data not yet loaded
  • Show email to self-viewing users on user page
  • Enforce data visibility per access level with test coverage
  • Replace jsonPath with response.body for null-value checks in visibility tests
  • Replace remaining jsonPath calls in asset visibility tests
  • Allow maintainer assignment for all user roles in UI
  • Address PR #127 review issues — fallback, eager load, indentation, Maintainer tests
  • Show maintained cosplayers section for all user types in admin edit modal
  • Show maintained cosplayers section for all user types in user profile edit modal
  • Add entity-level visibility gating for albums and persons
  • Update border colors and browse-mode visibility in AlbumDetail
  • Show borders for maintainers in select mode
  • Prevent jagged wrapping of toolbar and action buttons
  • Album-card-select and cosplayer-card-select only on selected cards
  • Wrap CosplayerDetail action buttons into mobile dropdown
  • Add cascade checkbox to CosplayerDetail album visibility modal
  • Cosplayers page bugs
  • Prevent private assets with null UploadedBy leaking to anonymous users
  • Homepage preview navigation, grid observer crash, and cascade labels
  • Label Delete button and cropper modal overlay
  • Album detail back button uses history.back() with fallback to /albums
  • Soft-delete users in UserController.Delete instead of hard-delete
  • Add ConfirmDialog to AdminUsers delete user flow
  • Add ConfirmDialog to User delete user flow
  • Add ConfirmDialog to AlbumDetail delete flows
  • Add ConfirmDialog to CosplayerDetail delete flows
  • Add ConfirmDialog to Albums bulk delete flow
  • Add ConfirmDialog to Cosplayers bulk delete flow
  • Add ConfirmDialog to Settings folder deletion flow
  • (UI) Make the delete cosplayer button in cosplayer detail page be just an icon to conform with albums detail page
  • Apply Visibility and MaintainerUserIds in PersonController.BulkUpdate
  • Split multi-request test blocks into single-request blocks
  • Guard against null PersonOwnerId in MergePeople albums query
  • Gate registration behind UserRegistrationEnabled setting
  • Handle 204/empty responses in AssetService and always reset isLoading in AlbumAssetPicker
  • Use Albums.Count==0 instead of !Any() for unlinked filter, add trace logging
  • Use OnParametersSetAsync instead of fire-and-forget to ensure Blazor re-renders after init
  • Use parameterized SqlQueryRaw instead of unquoted string.Format to prevent SQL error
  • Filter directory names to only paths containing a slash after prefix, excluding filenames
  • Restrict maintenance page and nav link to admin only
  • Add scoped CSS for maintenance page to make embedded picker fill viewport
  • Inline all markup in .razor template to restore CSS isolation
  • Change LoginService from Singleton to Scoped to match Blazored.LocalStorage lifetime
  • Simplify maintenance page CSS to flex-fill container without vh calc
  • Adjust embedded picker viewport height offset
  • Address PR #142 review issues

🚜 Refactor

  • (API) Switch to repository pattern
  • (API) Switch to use UserRepository AuthController.cs
  • (API) Switch to repository pattern
  • (API) Switch to use UserRepository AuthController.cs
  • (API) Cleans the code
  • (API) Cleans the code
  • (API) Extract BulkDtoinseparate file
  • (API) Switch to use a class for paged search
  • (API) Adds Bulk capabilities
  • (API) Move classes and Standardlize
  • (API) Rename Asset Dtos
  • (API) AlbumController explicitly marked all of the x in lambdas as they were accidentally hiding previous stage, also improved null checking
  • Reformatted AssetController and AssetCreateDto files
  • (API) Asset controller reformatted params
  • Improve readability of CorsAllowedOrigins parsing block
  • (jobs) Flatten ThumbnailJob to batch-based sub-jobs
  • (jobs) Flatten PHashJob to batch-based sub-jobs
  • (jobs) Flatten MetadataJob to batch-based sub-jobs
  • Make LoginService singleton, centralize auth state and persistence
  • Extract ImagePreview shared component from Home and AlbumDetail
  • Remove list view, add grid/masonry toggle to album detail
  • (css) Move shared modal styles to global MilkyShot.css/SCSS, remove duplicated scoped CSS
  • (css) Remove SCSS, switch to plain CSS with Bootstrap custom properties
  • (api) Fold unassigned album filter into search endpoint via query param
  • (dto) Move Unassigned filter into PagedSearchParametersDto
  • Replace individual albumPage/albumSize params with PagedParametersDto in person detail endpoint
  • Replace custom masonry JS with Bootstrap grid + Masonry.js approach
  • (auth) Extract AuthServiceBase, replace retry with re-auth on 401
  • (auth) Remove SendWithRefreshAsync, rely solely on JwtTokenRefresher
  • (ui) Replace inline password form with modal
  • (ui) Complete user profile page redesign with card layout
  • Move cosplayer link to same line as album name
  • Center-align header, album name on top, cosplayer smaller below
  • Extract password strength UI into shared PasswordField component
  • Replace tuple + custom header with ChildrenResponse DTO
  • (ui) ModalFrame + EmptyState components, remove duplicate CSS, remove main border
  • (jobs) Use darken() for phash and create-albums hover/active too
  • Project PersonPreviewDto directly in repository instead of [NotMapped] entity property
  • Project AlbumPreviewDto directly in repository with visibility-aware asset count
  • Clean up imports, simplify checks, and add SearchDropdown component
  • (albums) Extract visibility-aware AssetCount into AlbumMapper overload
  • Replace hardcoded 250 page size limit with PagedParametersDto.MaxPageSize
  • Use MaxPageSize constant as default pageSize across all frontend services
  • Reuse AlbumGrid in CosplayerDetail via FetchAlbums delegate
  • Move all visibility filtering from mappers and controllers to repositories
  • Rename AlbumSearchParametersDto.UploadedBy to AssetUploadedBy
  • Extract role badge colors to SCSS theme layer
  • Generate access level dropdown from enum values
  • Extract role checks to LoginService, update all consumers
  • Move CanEdit logic to LoginService, remove local page properties
  • Extract person search/assign UI into shared SearchAssignBadges component
  • Extract VisibilityModal shared component, add editing controls to Albums page
  • Centralize cascade visibility logic in AlbumService.CascadeVisibilityToAssetsAsync
  • Replace inline visibility modal with shared VisibilityModal in Cosplayers.razor
  • Move Unlink cosplayer button from album header to album edit form
  • Add Embedded mode, UnlinkedOnly param, rename methods from Unlinked to generic names
  • Rename UnlinkedAssetGroupDto to AssetGroupDto
  • Replace individual [FromQuery] params with AssetBrowseOptionsDto

📚 Documentation

  • Update agents.md for Blazor WASM architecture
  • Add CORS configuration section to README
  • (readme) Add wildcard CORS warning and MilkStream CORS setup guide
  • Add XML documentation to all public APIs across all projects
  • Update AGENTS.md with XML doc enforcement and CORS guidance
  • Update AGENTS.md with verified infrastructure gotchas
  • Add API reuse convention to AGENTS.md — prefer optional query params over new endpoints
  • Add Gitea repo owner note to AGENTS.md
  • Add granular commit convention to AGENTS.md
  • Document REST Client tests in AGENTS.md
  • Update AGENTS.md with missing conventions and project info
  • Add use case catalog for new auth/permissions model
  • Add Gitea label levels note to AGENTS.md
  • Add PR workflow section to AGENTS.md
  • Reconcile AGENTS.md with current codebase
  • (repo) Fix stale pageSize default in IAlbumRepository XML doc
  • Add data size estimates to AGENTS.md
  • Clarify Curators and Admins can be maintainers for credited attribution
  • Fix stale column references and tooling versions in AGENTS.md
  • Add visibility rules (R1R7) to AGENTS.md

Performance

  • Push visibility filter into SQL for PersonRepository queries
  • Add partial index on Assets for visibility-aware search queries
  • Simplify ORDER BY to total count and add trigram GIN indexes
  • Add AsSplitQuery to repository queries with multiple Include calls
  • Replace in-memory path parsing with SQL SPLIT_PART aggregation and double-LIKE filter
  • Replace in-memory path parsing with SELECT DISTINCT SQL, remove dir count badges

🎨 Styling

  • Style cosplayer link with inherited color and person icon
  • Match cosplayer link font size to h3, remove icon, keep regular weight
  • Consistent inline typography for album title and cosplayer name with dash separator
  • Borderless edit pencil with hover reveal on header
  • Cosplayer link dims on hover instead of blue/underline
  • Replace badge backgrounds with colored icons + matching launch buttons
  • Custom job color palette based on purpose, avoid red
  • Mobile launch button cyan for better contrast
  • Soften accent gradient stops (5%/10% instead of 15%/30%)
  • Use rounded-square thumbnails for album results
  • Add chevron-right indicator to search dropdown headers
  • Use Bootstrap dropdown-menu and dropdown-item classes
  • (repo) Convert visibility filters to switch expressions for readability
  • (repo) Expand switch expression arms for readability
  • (repo) Use explicit named enum cases in PersonRepository switch expressions
  • Standardize access level comparison to switch expressions

🧪 Testing

  • More unit testing on HTTP client
  • (api) Add person endpoint tests to WepApiTest.http
  • (api) Add comprehensive http tests for all person and album endpoints
  • Add album update test without removePerson field
  • Use real album from search for update test, not zero-GUID fallback
  • All tests create their own data — create album returns ID, all mutations use self-created resources
  • Add endpoint tests for refresh token, albums, curator auth levels
  • Add anonymous search tests for persons and albums
  • Handle empty person search results gracefully
  • Set personId from admin search to ensure it's always populated
  • Add user id to profile update request body
  • Fix curator user access level from Admin (2) to Curator (1)
  • Restructure WepApiTest.http with three clearly separated users
  • Add cleanup of regular test user in REST Client suite
  • Add page=0&pageSize=5 to paginated list endpoints
  • Add merge and bulk visibility tests to WepApiTest.http
  • Flatten test numbering to sequential 1137
  • Added rate limiting stress test

⚙️ Miscellaneous Tasks

  • Removes auto generated docker-compose file for deployment
  • (docker) Removes auto generated docker-compose file for deployment
  • (API) Changes the category name of the logger
  • Added datagrip files
  • (config) Separates connection string defaults for docker and local webserver run
  • Removed unused using in Program.cs
  • Swapped empty array initializer with empty collection initializer in Asset hash
  • Commented out unused logger in Album controller and added a TODO: about adding logging capabilities
  • Marked navigation property in folder as nullable
  • Commented out logger in FolderController and added a TODO regarding logging
  • Removed redundant type cast in tag search
  • Removed useless using declarations in TagMapper
  • Commented out the logger in tagController and added a TODO regarding logging
  • Removed more unused using directives
  • (docker) Added NoCache build option for lactose
  • (docker) Updated dockerfile to build using dotnet 9.0
  • (NuGet) [breaking] Added dependency to Magick.NET-Q16-HDRI-OpenMP-x64
  • Updated nuget packages to latest releases supporting Net 8.0, removed ImageMagick package.
  • Removed MySql package from required nuget packages
  • Refined db connector params
  • (API) Removes Redundant Check
  • Split TokenGeneratorProvider file in their respective classes
  • Moved milkstream services under a services namespace
  • (frontend) Switched to a more recent session storage implementation which doesn't have a security vulnerability.
  • Updated run profiles
  • Moved milkstream services under a services namespace
  • (frontend) Switched to a more recent session storage implementation which doesn't have a security vulnerability.
  • Updated run profiles
  • Remove temporary debug panel from Jobs page
  • Remove redundant XML doc comments from ServiceBase
  • Upgrade target framework to net10.0
  • Add dotnet-tools.json for ef tool
  • (dev) Fix ovveride PM Compose deploy
  • Remove debug auth logging middleware from Program.cs
  • Remove unused banner-cell-empty CSS class
  • (test) Remove Swagger test — disabled in container environments
  • Added the test images folder to the dockerignore avoiding them being sent every time a docker build starts
  • Revert docker-compose.yml to match develop
  • Updated packages, removed unused packages. ImageSharp now requires a license
  • Commit compiled CSS for role badge classes
  • Fix Dockerfiles, add debug compose to solution
  • Use record for config classes
  • Adjusted rate-limits of thumbs, preview and jobs to avoid triggering them during normal usage
  • Add Gitea Actions workflow to build and push containers on version tags

🛡️ Security

  • Upgrade to .NET 10 — packages, Docker images, and Swagger fix

◀️ Revert

  • Switch album detail back to masonry layout
  • Restore docker-compose.yml — testing-only CORS/baseUrl changes committed by accident
  • Restore docker-compose.yml LactoseBaseUrl to 192.168.50.100
  • Remove AllowAnonymous from AlbumController.Search and PersonController.GetAll
  • Change LoginService back to Singleton (DI error was from docker fast mode)

CI

  • Added build + push to internal registry action

Fix

  • (API) Disables Asset Create
  • (API) Refresh token being changed the last 10 minutes instead of every moment
  • (API) Refresh token being changed the last 10 minutes instead of every moment