Commit Graph

8 Commits

Author SHA1 Message Date
7b5bb66b37 feat: frontend-ready backend — pagination, auto-derivatives, list endpoints, bulk ops, OpenAPI
Pagination: count_by_owner + count_search on AssetRepository,
timeline/search return real total count (not page len).

Auto-derivatives: worker enqueues GenerateDerivative when
ExtractMetadata job completes, closing the upload→thumbnail gap.

List endpoints: GET /albums, GET /stacks with user scoping.
ListAlbumsHandler, ListStacksHandler, find_by_owner on AssetStackRepository.

Tag filtering: tag_name field on AssetFilters, JOIN asset_tags+tags
in postgres search/count queries.

Bulk operations: POST /assets/bulk-delete, POST /assets/bulk-tag.

Album update: PUT /albums/{id} with UpdateAlbumHandler (title, description).

OpenAPI: utoipa annotations on all 47 endpoints + all request/response
schemas registered. Scalar UI at /scalar covers full API.
2026-05-31 23:06:25 +02:00
bcaf49cc81 perf: scale fixes for 1M+ photo libraries
Indexes: share_targets.target_id, duplicate_groups.status,
GIN on stacks members + duplicate candidates JSONB,
composite (owner_user_id, created_at DESC) on assets.

N+1 elimination: batch metadata loading via find_by_assets(ids)
using WHERE asset_id = ANY($1), used in timeline + sidecar export.

Visibility: cache find_targets_for_user per request via OnceCell,
extract filter_visible helper to reduce duplication.

Streaming: FileStoragePort.open_file() returns (DataStream, u64),
LocalFileStorage uses ReaderStream instead of loading full file.
serve_file/serve_derivative use Body::from_stream().

Unbounded queries: sidecar full_export/import batched in 500-row
chunks instead of u32::MAX. find_unresolved paginated with
limit/offset. list_duplicates API accepts pagination params.
2026-05-31 22:40:25 +02:00
c6f82090d2 feat: auth hardening + codebase quality sweep
Refresh tokens: RefreshToken entity, PostgresRefreshTokenRepository,
login returns refresh token, POST /auth/refresh (rotation), POST /auth/logout,
JWT expiry 24h→1h, configurable via with_expiry().

Route protection: require_auth middleware on protected routes,
public routes split (register, login, refresh, sharing/access).

Authorization: caller_id added to ReadAssetFileQuery, ReadDerivativeQuery,
GetStackQuery, DeleteStackCommand with ownership checks. Admin-only gates
on processing, storage, sidecar, duplicates handlers.

Quality fixes: visibility filtering bypass in search(), unwrap panics in
date parsing, DRY auth header parsing, centralized parsers module,
email validation via email_address crate, value objects (Username, MimeType,
RelativePath), domain events (UserCreated, UserDeleted, AlbumCreated,
TagCreated, DuplicateDetected), postgres error mapping for constraint
violations, OptionExt::or_not_found helper, in_memory_repo! macro,
GetStackQuery moved to queries, album add_entry 200→201.
2026-05-31 22:26:02 +02:00
b5cda3afeb feat: add VisibilityFilteredAssetRepository decorator for automatic access control on asset queries 2026-05-31 19:06:49 +02:00
2d9dd2c2d0 refactor: clean up presentation layer — AppState grouping, multipart extractor, thin handlers 2026-05-31 06:14:19 +02:00
34b231a8f6 refactor: move business logic out of presentation — ReadAssetFile, checksum, auth checks, MetadataValue conversions 2026-05-31 06:10:07 +02:00
c2ebca0da0 style: cargo fmt --all 2026-05-31 05:31:42 +02:00
536bf3463a app: add catalog commands/queries (RegisterAsset, UpdateMetadata, GetTimeline, GetAsset) 2026-05-31 05:13:47 +02:00