clean up
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,116 +0,0 @@
|
||||
# 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<RemoteActor>` or `()`).
|
||||
|
||||
```
|
||||
list_pending_requests(federation, user_id) → Result<Vec<RemoteActor>, 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<Vec<RemoteActor>, DomainError>
|
||||
remove_remote_follower(federation, user_id, actor_url: &str) → Result<(), DomainError>
|
||||
list_remote_following(federation, user_id) → Result<Vec<RemoteActor>, 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 `<FederationPanel />`
|
||||
- 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 `<FederationPanel />` as its content
|
||||
- Tab is only visible when `isOwnProfile === true`
|
||||
|
||||
**Notifications page** (modify)
|
||||
- Render `<PendingRequests compact />` 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)
|
||||
Reference in New Issue
Block a user