👉🏻 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.

— 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.


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”