๐๐ป 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”