👉🏻 이번에는 @user1@yourhost.domain.org의 팔로워 목록을 만듭니다.
Next, create a list of followers for @user1@yourhost.domain.org.
👉🏻 pinafore.social프로필의 FOLLOWERS 1을 클릭할경우 목록에 보여주는 기능입니다.
This feature displays a list when you click “FOLLOWERS 1” on the pinafore.social profile.
👉🏻 gotosocial은 정책상 remote 계정(다른 서버 계정의 팔로워) 정보는 보여주지 않습니다.
Due to its policy, GoToSocial does not display information about remote accounts (followers from other servers).
👉🏻 그래서 라우터를 만들고 API 확인만 할 예정입니다.
So, I plan to create the router and just verify the API.
📁 프로젝트 설치,라이브러리 설치,HTTPS설정
Project setup, library installation, HTTPS configuration
✔️ 아래의 이전 포스트를 참조하세요
Please refer to the previous post below.
📁 전체 프로젝트 구조 / Overall Project Structure
myapp15/
├── app/ (Next.js App Router)
│ ├── api/posts/route.ts -> 글 쓰기 API / Writing API
│ ├── api/follow/route.ts -> 팔로우 API(임시) / Follow API(temporary)
│ ├── users/[username]/
│ │ ├── route.ts -> Actor정보 / Acotr Information
│ │ ├── followers/route.ts -> Followers List
│ │ ├── inbox/route.ts -> Inbox
│ │ └── outbox/route.ts -> outbox
│ ├── layout.tsx, page.tsx, globals.css
│ └── favicon.ico
├── lib/
│ ├── ap.ts -> Follow Accept
│ └── db.ts -> DB connection
├── data/
│ └── keys/ -> private.pem, public.pem
├── data.sqlite -> Database
├── Caddyfile -> https
└── package.json
📁 followers 라우터 만들기
Creating a followers router
✔️ followers를 보여주기하기 위한 목록을 만듭니다.
Create a list to display followers.
✔️ myapp15/app/users/[username]/followers/route.ts
// myapp14/app/api/follow/route.ts
import { sendFollow, signedFetch } from '@/lib/ap';
//const DOMAIN = process.env.DOMAIN || 'aloy-horizon.duckdns.org';
// myapp14 ✅ - Follow 보내기 API / Send Follow API
// POST /api/follow
export async function POST(req: Request) {
try {
const { username = 'user1', target } = await req.json();
if (!target) return Response.json({ error: 'target 필요' }, { status: 400 });
console.log(`➡️ 팔로우 시도 / Follow attempt: ${username} -> ${target}`);
// 1. 상대방 inbox 찾기 - 서명된 GET으로! / Find the inbox with a signed GET request
const actorRes = await signedFetch(target, username);
if (!actorRes.ok) {
const t = await actorRes.text();
return Response.json({ error: `상대방 조회 실패 / Failed to look up the other party. ${actorRes.status}`, body: t }, { status: 400 });
}
const actor = await actorRes.json();
const inbox = actor.inbox;
console.log(`📬 inbox 찾음 / Found inbox: ${inbox}`);
// 2. Follow 전송 / Send Follow
const result = await sendFollow(inbox, target, username);
return Response.json({
ok: result.ok,
inbox,
target,
result: result.text,
follow: result.followDoc
});
} catch (e: any) {
console.error('follow 에러 / Follow error:', e);
return Response.json({ error: e.message }, { status: 500 });
}
}
📁 코드 수정 / Code modification
✔️ pinafore에서 팔로우 신청을 하면 aloy-horizon.duckdns.org로 팔로우 요청이 옵니다.
When you send a follow request from Pinafore, the request is sent to aloy-horizon.duckdns.org.
✔️ 이떄 팔로우 요청한 사용자의 이름을 aloy-horizon.duckdns.org에 저장해야합니다.
At this point, you need to save the name of the user who sent the follow request to aloy-horizon.duckdns.org.
✔️ 이전에 데이터베이스에 username컬럼이 없다면 추가 합니다.
If the username column does not already exist in the database, add it.
ALTER TABLE followers ADD COLUMN username TEXT;
✔️ username에 사용자 아이디를 입력하는 부분의 코드를 수정합니다.
Modify the code for the section where the user ID is entered into ‘username’.
— myapp15/app/users/[username]/followers/route.ts
if (body.type === 'Undo') {
db.prepare('DELETE FROM followers WHERE actor = ? AND username = ?').run(unfollowActorId, username);
}
if (body.type === 'Follow') {
db.prepare('INSERT OR IGNORE INTO followers (id, actor, inbox, username) VALUES (?,?,?,?)').run(body.id, actorId, inboxUrl, username);
}
📁 팔로워 데이터 확인하기
Check follower data
✔️ pinafore.social에서 새로 팔로우를 해봅니다. 그래서 데이터베이스와 API에 정상적으로 유저가 확인 가능한지 체크해봅니다.
I’m trying out a new follow on pinafore.social, so I’m checking to see if the user is correctly recognized by the database and API.
✔️ 데이터 베이스 저장확인하기
Verify database storage
sqlite> select * from followers;
https://freelifemakers.com/users/user1/follow/01S310S4A222J6FN8QDQXJR2221|https://freelifemakers.com/users/user1|https://freelifemakers.com/users/user1/inbox|user1
sqlite>
✔️ API 출력확인하기
Check API Output
— https://aloy-horizon.duckdns.org/users/user1/followers
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://aloy-horizon.duckdns.org/users/user1/followers",
"type": "OrderedCollection",
"totalItems": 1,
"orderedItems": [
"https://freelifemakers.com/users/user1"
],
"first": {
"id": "https://aloy-horizon.duckdns.org/users/user1/followers?page=1",
"type": "OrderedCollectionPage",
"totalItems": 1,
"orderedItems": [
"https://freelifemakers.com/users/user1"
]
}
}

요한복음 8장 32절 / John 8:32
“그리고 너희는 진리를 알게 될 것이며, 진리가 너희를 자유롭게 할 것이다.”
“Then you will know the truth ,and the truth will set you free”