[nextjs]SNS Server-20(myapp30)

👉🏻 myapp30에서는 내가 작성한 글 삭제시 내 글을 받은 서버의 글도 삭제하는 기능을 추가했습니다.
In myapp30, I added a feature that deletes the post on the server that received it whenever I delete my own post.

👉🏻 전체 코드는 깃허브에서 확인 할 수 있습니다.
You can find the full code on GitHub.

https://github.com/gideonslife01/flm-nextjs

📁 전체 프로젝트 구조 / Overall Project Structure

myapp project/  
├── app/  (Next.js App Router)
│   ├── .well-known/webfinger/route.ts  -> webfinger
│   ├── api/follow/route.ts    -> Follow API(temporary)
│   ├── api/announce/route.ts  -> Boost(Announcement)
│   ├── api/like/route.ts.     -> Like API
│   ├── api/posts/route.ts     -> Writing API
│   ├── api/timeline/route.ts  -> Timeline API
│   ├── users/[username]/
│   │   ├── statuses/[id]/route.ts -> Indivisual Post
│   │   ├── route.ts               -> Acotr Information
│   │   ├── followers/route.ts     -> Followers List
│   │   ├── following/route.ts     -> Following List
│   │   ├── inbox/route.ts         -> Inbox
│   │   └── outbox/route.ts        -> outbox
│   ├── usersui/[username]/
│   │   ├── page.tsx               -> Timeline UI
│   │   └── _components/themes/
│   │       ├── themeex/ThemeexTheme.tsx   -> Example Theme
│   │       ├── pinafore/PinaforeTheme.tsx -> Theme 1
│   │       ├── mastodon/MastodonTheme.tsx -> Theme 2
│   │       └── minimal/MinimaltTheme.tsx  -> Theme 3
│   ├── layout.tsx, page.tsx, globals.css
│   └── favicon.ico
├── lib/
│   ├── theme.tsx              -> Theme Provider
│   ├── watchThemes.ts         -> Check real-time theme changes
│   ├── ap.ts                  -> Follow Accept
│   └── db.ts                  -> DB connection
├── data/
│   └── keys/                  -> private.pem, public.pem
├── data.sqlite                -> Database
├── Caddyfile                  -> https 
├── instrumentation.ts         -> Background Server
└── package.json

📁 프로젝스 시작 / Project Start

— 프로젝트 설치,모듈설치,도메인 설정,함수,라우트,프로젝트 구조 설명은 아래의 포스트를 참조하세요
Please refer to the post below for information on project and module installation, domain configuration, functions, routes, and the project structure.


📁 코드수정 / Code Modification

 ✔️app/api/posts/route.ts

-- posts만 삭제하고 연방에 Delete 안 보내는 문제 수정
Fixed an issue where only 'posts' were deleted without sending a 'Delete' request to the federation.

1) inbox_posts는 안 지움 + likes, announces 카운트도 안 지움
`inbox_posts` are not deleted, and `likes` and `announces` counts are not cleared either.

2) import { sendDelete } 맨 위에 추가 - 서명 포함된 함수 사용
Add `import { sendDelete }` at the top – use the function that includes the signature.

3) DELETE에서 fetch 직접 호출 -> sendDelete(f.inbox, id, username)로 교체
Replaced direct `fetch` call in `DELETE` with `sendDelete(f.inbox, id, username)`.

4) POST도 for...of await -> Promise.allSettled 병렬로 변경 (속도 향상)
Changed POST requests from `for...of await` to `Promise.allSettled` for parallel execution (improved speed).

✔️app/lib/ap.ts

— 전체 코드 리팩토링 , sendDelete함수 추가
Refactored the entire codebase and added the sendDelete function.

export async function sendDelete(toInbox: string, postId: string, username: string) {
  const actorId = `https://${DOMAIN}/users/${username}`;

  // postId가 이미 전체 URL이면 그대로, UUID면 만들어주기 
  // If postId is already a full URL, use it; if it's a UUID, construct it! 
  const objectId = postId.startsWith('http') 
    ? postId 
    : `${actorId}/statuses/${postId}`; 

  const doc = {
    '@context': 'https://www.w3.org/ns/activitystreams',
    id: `${actorId}#delete/${crypto.randomUUID()}`,
    type: 'Delete',
    actor: actorId,
    object: objectId,
    published: new Date().toISOString(),
    to: ['https://www.w3.org/ns/activitystreams#Public']
  };
  console.log(`🗑 [${username}] Delete -> ${toInbox} (${postId})`);
  const { res, text } = await signAndSend(toInbox, doc, username);
  console.log(`📬 Delete: ${res.status}`, text);
  return { ok: res.ok, status: res.status, text, deleteDoc: doc };
}

📁 테스트 / Test

✔️ 마스토돈에서 글쓰고 내서버로 글 배달되는지 확인하기
Writing a post on Mastodon and checking if it gets delivered to my server.

mastodon

— inbox_posts에 글배달 확인
Check for post deliveries in inbox_posts

sqlite> select id,content from inbox_posts;
https://freelifemakers.com/users/user1/statuses/01M0EJPP57WC47FAK0N395S7MB|<p>inbox_posts table test</p>
https://freelifemakers.com/users/user1/statuses/01M0KMS8K1XRFW703S32MX6V25|<p>actor test</p>
01M0XT1VBF23F8Y5EXAPK1VY56|<p>likes test</p>
01M12X859S7WNSJJD42NWZS8T7|<p>boost delivery test!!</p>
01M1AWST9S00BRBDC0AAEEN6VA|<p>Boots Button Test</p>
01M1DCBVDYTGB7W4CK3RVHN121|<p>Favorite TEst</p>
117193471582999448|<p>Hello Mastodon!!!</p>
117194002682623887|<p>mastodon boost test</p>
117194002682623887_boost_1788238635654|<p>mastodon boost test</p>
117194002682623887_boost_1788239235922|<p>mastodon boost test</p>
9b2ead85-4b15-4df9-9de4-04c4a7fbcab4_boost_1788239544485|Hello! Mastodon!!
117204066261760455|<p>mastodon ,ally,user1 posts delete test</p>
sqlite> 

✔️ 글 삭제 / Delete Post

— 내가 쓴글과 서버로 배달된 글도 삭제(POST,GET 모두 지원)
Deletes both the posts I wrote and the posts delivered to the server (supports both POST and GET).

# 기존 POST 방식과 GET방식을 모두 지원합니다. 
# Supports both existing POST and GET methods.
# POST
curl -X DELETE https://aloy-horizon.duckdns.org/api/posts \
 -H "Content-Type: application/json" \
 -d '{"username":"user1","id":"117204066261760455"}'

# GET
curl -X DELETE "https://aloy-horizon.duckdns.org/api/posts?id=117204066261760455&username=user1"

— 내 받은 글 삭제해보기( 내가 작성한 글 아니면 삭제 금지,정상적으로 에러 발생 여부 확인하기 )
Try deleting a received post (ensure posts not written by me cannot be deleted and verify that errors occur as expected).

# SQLITE
sqlite> select id,content from inbox_posts;
https://freelifemakers.com/users/user1/statuses/01M0EJPP57WC47FAK0N395S7MB|<p>inbox_posts table test</p>
https://freelifemakers.com/users/user1/statuses/01M0KMS8K1XRFW703S32MX6V25|<p>actor test</p>
01M0XT1VBF23F8Y5EXAPK1VY56|<p>likes test</p>
01M12X859S7WNSJJD42NWZS8T7|<p>boost delivery test!!</p>
01M1AWST9S00BRBDC0AAEEN6VA|<p>Boots Button Test</p>
01M1DCBVDYTGB7W4CK3RVHN121|<p>Favorite TEst</p>
117193471582999448|<p>Hello Mastodon!!!</p>
117194002682623887|<p>mastodon boost test</p>
117194002682623887_boost_1788238635654|<p>mastodon boost test</p>
117194002682623887_boost_1788239235922|<p>mastodon boost test</p>
9b2ead85-4b15-4df9-9de4-04c4a7fbcab4_boost_1788239544485|Hello! Mastodon!!
117204066261760455|<p>mastodon ,ally,user1 posts delete test</p>
sqlite> 

# Terminal
myapp30 % curl -X DELETE "https://aloy-horizon.duckdns.org/api/posts?id=117204066261760455&username=user1"
{"error":"내 글 아님 / Not your post"}%                                                                                                                   
myapp30 % curl -X DELETE https://aloy-horizon.duckdns.org/api/posts \
 -H "Content-Type: application/json" \
 -d '{"username":"user1","id":"117204066261760455"}'
{"error":"내 글 아님 / Not your post"}%   

— 내가 작성한 글 삭제하기 / Delete my post

1)터미널에서 글쓰기 / Writing in the Terminal

# 터미널에서 글쓰기
# Writing in the Terminal

myapp30 % curl -X POST https://aloy-horizon.duckdns.org/api/posts \
  -H "Content-Type: application/json" \
  -d '{"username":"user1","content":"<p>연방 삭제 테스트 / Federated Deletion Test!!!</p>"}'
{"id":"fe9d75bb-8fb4-4ec3-9cff-76e5de8a4261","content":"<p>연방 삭제 테스트 / Federated Deletion Test!!!</p>","created_at":"2026-09-03 00:33:22","username":"user1"}%  

2) 마스토돈 및 고투소셜 서버에 글 배달확인
Verify post delivery to Mastodon and GoToSocial servers.

mastodon(mastodon.social/@freelifemakers)
gotosocial(freelifemakers.com/@user1)

3) 내 데이터베이스와 다른 서버로 배달된 글도 삭제 확인
Check for deletion of posts delivered to servers other than my database as well.

                                                                                                                                             
# SQLITE에 글 저장 확인
# Verify post storage in SQLite

myapp30 % sqlite3 data.sqlite
SQLite version 3.51.0 2025-06-12 13:14:41
Enter ".help" for usage hints.
sqlite> select id,content from posts;
e6c99652-572f-491a-9e61-05e67b0d58fc|Hello! my SNS!!
dcece9ee-8d4a-4f63-91e1-22fc60513f62|Hello! my SNS!!
cc30330e-7040-4a1b-9e60-731066b8817e|Hello! my SNS3!!
e6d532c8-974b-4a01-89f6-6e1b2c4cff32|Hello Fediverse! #test
aea0ec89-a368-44a9-8493-b2bd82a797a8|post test! #test
9b2ead85-4b15-4df9-9de4-04c4a7fbcab4|Hello! Mastodon!!
fe9d75bb-8fb4-4ec3-9cff-76e5de8a4261|<p>연방 삭제 테스트 / Federated Deletion Test!!!</p>
sqlite> 

# 내가 작성한 글 삭제 (GET)
# Delete My Post (GET)

curl -X DELETE "https://aloy-horizon.duckdns.org/api/posts?id=fe9d75bb-8fb4-4ec3-9cff-76e5de8a4261&username=user1"

# Terminal

myapp30 % curl -X DELETE "https://aloy-horizon.duckdns.org/api/posts?id=fe9d75bb-8fb4-4ec3-9cff-76e5de8a4261&username=user1"
{"ok":true,"deletedId":"fe9d75bb-8fb4-4ec3-9cff-76e5de8a4261"}%                                                                                           
gimdaegyeong@gimdaegyeong-ui-MacBookAir myapp30 % 

# SQLITE
myapp30 % sqlite3 data.sqlite
SQLite version 3.51.0 2025-06-12 13:14:41
Enter ".help" for usage hints.
sqlite> select id,content from posts;
e6c99652-572f-491a-9e61-05e67b0d58fc|Hello! my SNS!!
dcece9ee-8d4a-4f63-91e1-22fc60513f62|Hello! my SNS!!
cc30330e-7040-4a1b-9e60-731066b8817e|Hello! my SNS3!!
e6d532c8-974b-4a01-89f6-6e1b2c4cff32|Hello Fediverse! #test
aea0ec89-a368-44a9-8493-b2bd82a797a8|post test! #test
9b2ead85-4b15-4df9-9de4-04c4a7fbcab4|Hello! Mastodon!!
sqlite> 

# 내가 작성한 글 삭제(POST)
# Delete Post I Wrote (POST)

myapp30 % curl -X DELETE https://aloy-horizon.duckdns.org/api/posts \
 -H "Content-Type: application/json" \
 -d '{"username":"user1","id":"73f8e331-fdcd-48a4-bb03-c3c010bceba5"}'
{"ok":true,"deletedId":"73f8e331-fdcd-48a4-bb03-c3c010bceba5"}%   

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

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

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

Leave a Reply