feat: image storage generalization, user profile, and federation polish

- Replace PosterStorage with generic ImageStorage port (IMAGE_STORAGE_BACKEND/PATH env vars)
- Rename poster-storage crate to image-storage; serve at /images/{*key}
- Add bio and avatar_path to User model (migration 0009_user_profile)
- update_profile use case with avatar upload, mime validation, old avatar cleanup
- GET/PUT /api/v1/profile and GET/POST /settings/profile HTML page
- Enrich AP Person actor with summary, icon, url, discoverable fields
- Store remote actor avatar_url (migration 0010_ap_remote_actor_avatar)
- Shared inbox delivery via collect_inboxes deduplication
- Broadcast Update(Person) to followers on UserUpdated event
- Paginated outbox: OrderedCollection + OrderedCollectionPage with cursor
- Announce/boost tracking in ap_announces table (migration 0011_ap_announces)
This commit is contained in:
2026-05-11 22:59:52 +02:00
parent 8a254346f4
commit 80f620c840
89 changed files with 2231 additions and 499 deletions

View File

@@ -23,7 +23,7 @@ async fn main() -> anyhow::Result<()> {
let (auth_service, password_hasher) = auth::create()?;
let metadata_client = metadata::create()?;
let poster_fetcher = poster_fetcher::create()?;
let poster_storage = poster_storage::create()?;
let image_storage = image_storage::create()?;
let (movie_repository, review_repository, diary_repository, stats_repository, user_repository, import_session_repository, import_profile_repository, db_pool) =
match backend.as_str() {
@@ -82,7 +82,7 @@ async fn main() -> anyhow::Result<()> {
stats_repository,
metadata_client,
poster_fetcher,
poster_storage,
image_storage,
event_publisher: event_publisher_arc,
auth_service,
password_hasher,
@@ -112,12 +112,12 @@ async fn main() -> anyhow::Result<()> {
Arc::clone(&ctx.movie_repository),
Arc::clone(&ctx.metadata_client),
Arc::clone(&ctx.poster_fetcher),
Arc::clone(&ctx.poster_storage),
Arc::clone(&ctx.image_storage),
3,
)) as Arc<dyn EventHandler>;
let cleanup = Arc::new(poster_storage::PosterCleanupHandler::new(
Arc::clone(&ctx.poster_storage),
let cleanup = Arc::new(image_storage::ImageCleanupHandler::new(
Arc::clone(&ctx.image_storage),
)) as Arc<dyn EventHandler>;
#[cfg(not(feature = "federation"))]