# Federation Management Design ## Goal Allow users to manage their ActivityPub federation: accept/reject incoming remote follow requests, remove accepted remote followers, and unfollow remote actors they're following. Surface this in three places via a shared component set. ## Architecture Hexagonal layers respected throughout: - **Application layer**: new use cases in `federation_management.rs` — all business routing lives here - **Presentation layer**: handlers call use cases only, no direct port access - **Frontend**: four components under `components/federation/`, used in three locations --- ## Backend ### New use cases — `crates/application/src/use_cases/federation_management.rs` Six functions, each taking `&dyn FederationActionPort` and `&UserId`. Return domain types (`Vec` or `()`). ``` list_pending_requests(federation, user_id) → Result, DomainError> accept_follow_request(federation, user_id, actor_url: &str) → Result<(), DomainError> reject_follow_request(federation, user_id, actor_url: &str) → Result<(), DomainError> list_remote_followers(federation, user_id) → Result, DomainError> remove_remote_follower(federation, user_id, actor_url: &str) → Result<(), DomainError> list_remote_following(federation, user_id) → Result, DomainError> ``` Unfollow remote reuses the existing `unfollow_actor` use case in `social.rs` (already routes `@handle` to `federation.unfollow_remote`). ### New HTTP endpoints — `crates/presentation/src/handlers/federation_management.rs` All routes require authentication (`AuthUser` extractor). Actor URLs go in the JSON request body to avoid percent-encoding issues. | Method | Path | Body | Action | |--------|------|------|--------| | `GET` | `/federation/me/followers/pending` | — | List pending follow requests | | `POST` | `/federation/me/followers/accept` | `{ actor_url: String }` | Accept a follow request | | `DELETE` | `/federation/me/followers` | `{ actor_url: String }` | Remove/reject a follower | | `GET` | `/federation/me/followers` | — | List accepted remote followers | | `GET` | `/federation/me/following` | — | List remote actors being followed | | `DELETE` | `/federation/me/following` | `{ handle: String }` | Unfollow a remote actor (delegates to `unfollow_actor`) | Handlers are thin: extract auth, call use case, return JSON. No logic. --- ## Frontend ### API client additions — `thoughts-frontend/lib/api.ts` Six new functions mirroring the six endpoints. All take `token: string`. ```typescript getPendingFollowRequests(token) acceptFollowRequest(actorUrl: string, token) rejectFollowRequest(actorUrl: string, token) getRemoteFollowers(token) removeRemoteFollower(actorUrl: string, token) getRemoteFollowing(token) // unfollowRemote reuses existing unfollowUser or a new call to DELETE /federation/me/following ``` Response schema: `RemoteActorSchema` (already defined — handle, display_name, avatar_url, url). ### Components — `thoughts-frontend/components/federation/` **`pending-requests.tsx`** - Client component - Fetches `getPendingFollowRequests` on mount - Renders list of remote actors with Accept and Reject buttons - On action: optimistic removal from list, then API call - Prop: `compact?: boolean` — when true, renders as a flat list without card chrome (for notifications embed) **`remote-followers.tsx`** - Client component - Fetches `getRemoteFollowers` on mount - Renders list of accepted remote followers with a Remove button - On remove: optimistic removal, then API call **`remote-following.tsx`** - Client component - Fetches `getRemoteFollowing` on mount - Renders list of remote actors being followed with an Unfollow button - On unfollow: optimistic removal, then API call **`federation-panel.tsx`** - Composes the three above inside a shadcn `Tabs` component - Tabs: "Requests", "Followers", "Following" - Shows a numeric badge on "Requests" tab when pending count > 0 - No data fetching of its own — delegates entirely to sub-components ### Usage locations **`app/settings/federation/page.tsx`** (new) - Server component shell, renders `` - Add "Federation" link to the settings sidebar alongside "Profile" and "API Keys" **`app/users/[username]/page.tsx`** (modify) - Add a "Federation" tab to the profile tabs row - Render `` as its content - Tab is only visible when `isOwnProfile === true` **Notifications page** (modify) - Render `` as a card section above the notification feed - Only shown when the user is authenticated --- ## Out of scope - Local follow request management (local follows are auto-accepted) - Blocking remote actors (separate feature, already partially implemented) - Notification count badge in the nav for pending requests (can be added later)