- Add CoverAssetId FK and CoverAsset navigation to Album model
- Add AlbumAssetPreviewDto with resolution/thumbnail info
- Extend AlbumPreviewDto/FullDto with PersonName, CoverAssetId, AssetCount
- Add CoverAssetId to AlbumCreateDto and AlbumUpdateDto
- Update AlbumMapper to populate new fields from eager-loaded relations
- Add EF migration for CoverAssetId column
Replace the fixed GUID-based ordering (OrderBy(a => a.Id)) with a
client-generated seed that produces a truly different random order on
each page refresh. The seed is passed to the server and used to
deterministically shuffle all asset IDs via a hash function, ensuring
consistent pagination with no duplicates across pages within a session.
Also fix LoadPreviousPage showing a spinner when already at page 1 by
adding loadedMinPage <= 1 to the guard clause.
- Add AlbumNames and CosplayerNames fields to AssetPreviewDto
- Include Albums and PersonOwner in AssetRepository.GetAssets() query
- Populate new fields in AssetsMapper.ToAssetPreviewDto()
- Add PreviewJob (WebP) — same master/sub-job pattern as ThumbnailJob
- Convert ThumbnailJob from JPEG to WebP with configurable quality
- Add ThumbnailQuality/PreviewQuality settings (configurable in settings UI)
- Add PreviewSize, ThumbnailFormat, PreviewFormat fields to Asset model
- Add format-aware repo queries for auto-regeneration of stale JPEGs
- Fix MIME types in MediaRepository/MediaController to return image/webp
- Wire PreviewJob into JobScheduler, JobMapper, JobsController
- Expose quality settings on Settings page (Jobs group, range sliders)
- Add 'Make Previews' button on Jobs page, reorder to scan/metadata/thumb/preview/phash/integrity
Achieves 100% XML doc coverage on non-trivial types with CS1591
enforcement via Directory.Build.props.
Coverage by project:
- Butter: from 6.5% to 100% (DTOs, enums, MIME types)
- Lactose: from ~28% to 100% (controllers, services, repos, jobs, models)
- MilkStream.Client: from ~29% to 100% (all frontend services)
Uses <inheritdoc /> on repository implementations (interfaces
already documented) and full <summary>/<param>/<returns> tags
elsewhere. Enums include member-level docs.
- Split /api/jobs into three endpoints: active roots, paginated past,
children fetched on expand — reduces response from ~1MB to ~5KB
- Persist completed jobs to PostgreSQL via JobRecord entity + migration
- Add configurable job retention cleanup (hourly timer, default 30 days)
- Fix PHashJob master not persisting (missing Complete() call)
- Add PastJobsResponse DTO to fix case-sensitive JsonElement deserialization
- Refactor JobTree/JobRow for lazy-loaded children via FetchChildren callback
- Handle 401 responses in JwtTokenRefresher with token refresh + retry
- Remove JobChildrenSummary component (replaced by inline parent summary)
feat(db): extended amount of settings informations stored on the database
feat(frontend): added support for updating the refreshToken after a refresh request.
feat(backend): added a defaultSettings.json file that defines how the settings are initialized.