[nextjs]SNS Server-5(myapp15)

👉🏻 이번에는 @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"
    ]
  }
}
API

요한복음 8장 32절 / John 8:32

“그리고 너희는 진리를 알게 될 것이며, 진리가 너희를 자유롭게 할 것이다.”

“Then you will know the truth ,and the truth will set you free”

Leave a Reply