feat: migrate k-ap 0.1.10→0.3.1, fix AP gaps

- split FederationRepository into FollowRepository, ActorRepository, BlocklistRepository, ActivityRepository
- RemoteActor: 5 new fields (bio, banner_url, followers_url, following_url, also_known_as)
- ApObjectHandler split: get_local_objects_page/count_local_posts → ApContentReader trait
- builder API: positional args → named setters
- broadcast_create_note/update_note: add ApVisibility + mentioned_inboxes params
- backfill_outbox → import_remote_outbox
- ApUser: also_known_as Option<String> → Vec<String>, new fields

AP gaps fixed:
- add GET /users/{id}/followers + /following with content negotiation
- wire EventPublisher into builder via FederationEventBridge adapter
- add display_name field full stack (domain→DB→API→AP)
- DB-side outbox pagination (get_local_reviews_page)
- set featured_url on ApUser
This commit is contained in:
2026-05-29 10:42:53 +02:00
parent bace54c552
commit 624cfe5799
32 changed files with 1016 additions and 957 deletions

View File

@@ -0,0 +1,45 @@
use std::sync::Arc;
use domain::events::DomainEvent;
use domain::value_objects::UserId;
use k_ap::FederationEvent;
pub struct FederationEventBridge {
domain_publisher: Arc<dyn domain::ports::EventPublisher>,
}
impl FederationEventBridge {
pub fn new(domain_publisher: Arc<dyn domain::ports::EventPublisher>) -> Self {
Self { domain_publisher }
}
}
#[async_trait::async_trait]
impl k_ap::EventPublisher for FederationEventBridge {
async fn publish(&self, event: FederationEvent) -> anyhow::Result<()> {
match event {
FederationEvent::BackfillRequested {
owner_user_id,
follower_inbox_url,
} => {
tracing::info!(
owner = %owner_user_id,
inbox = %follower_inbox_url,
"federation BackfillRequested → FollowAccepted"
);
self.domain_publisher
.publish(&DomainEvent::FollowAccepted {
local_user_id: UserId::from_uuid(owner_user_id),
remote_actor_url: follower_inbox_url.clone(),
outbox_url: follower_inbox_url,
})
.await
.map_err(|e| anyhow::anyhow!(e.to_string()))
}
_ => {
tracing::debug!("ignoring federation event: {:?}", event);
Ok(())
}
}
}
}