{"id":10890,"date":"2026-09-24T07:44:54","date_gmt":"2026-09-23T22:44:54","guid":{"rendered":"https:\/\/www.freelifemakers.org\/wordpress\/?p=10890"},"modified":"2026-09-24T12:36:03","modified_gmt":"2026-09-24T03:36:03","slug":"nextjs-sns-server-37","status":"publish","type":"post","link":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2026\/09\/24\/nextjs-sns-server-37\/","title":{"rendered":"[nextjs]SNS Server-37(myapp47)\u00a0"},"content":{"rendered":"\n<p>\ud83d\udc49\ud83c\udffb myapp47\uc5d0\uc11c  \ucd94\uac00\ub41c \uc0ac\ud56d \uc785\ub2c8\ub2e4.<br>These are the additions made in myapp47.<\/p>\n\n\n\n<p>\u2714\ufe0f api\/clenaup-orphan \ub77c\uc6b0\ud2b8\ub85c \ud574\ub2f9\uae00\uc744 \uc9c1\uc811 \uc0ad\uc81c \ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<br>You can delete the post directly using the <code>api\/cleanup-orphan<\/code> route.<\/p>\n\n\n\n<p>\u2714\ufe0f app\/users\/[username]\/statuses\/[id]\/route.ts \uc774 \ub77c\uc6b0\ud2b8\uc5d0 tombstone\uc774 \ucd94\uac00\ub418\uc5c8\uc2b5\ub2c8\ub2e4.<br>A tombstone has been added to the <code>app\/users\/[username]\/statuses\/[id]\/route.ts<\/code> route.<\/p>\n\n\n\n<p>\u2714\ufe0f app\/api\/v1\/statuses\/[id]\/route.ts \ub77c\uc6b0\ud2b8\uac00 \ucd94\uac00\ub418\uc5c8\uc2b5\ub2c8\ub2e4.(pinafore\uc5d0\uc11c \uae00 \uc0ad\uc81c \ud560 \ub54c \uc0ac\uc6a9 )<br>The <code>app\/api\/v1\/statuses\/[id]\/route.ts<\/code> route has been added (used for deleting posts in Pinafore).<\/p>\n\n\n\n<p>\u2714\ufe0f \uc544\ub798\uc758 \uae30\ub2a5 \ud14c\uc2a4\ud2b8\ub97c \uc644\ub8cc\ud588\uc2b5\ub2c8\ub2e4.<br>I have completed the functional tests below.<\/p>\n\n\n\n<p>&#8212; \ud14c\uc2a4\ud2b8\ub294 \uace0\ud22c\uc18c\uc15c \uc11c\ubc84(freelifemakers.com)\ub97c \uae30\uc900\uc73c\ub85c \ud14c\uc2a4\ud2b8\ud569\ub2c8\ub2e4.<br>Testing is conducted based on the GoToSocial server (freelifemakers.com).<\/p>\n\n\n\n<p>&#8212; \ub85c\uceec\uc11c\ubc84\uc5d0 \uae00\uc4f0\uace0 \ub9ac\ubaa8\ud2b8\uc11c\ubc84\uc5d0 \ubc30\ub2ec\ud655\uc778<br>Write a post on the local server and verify delivery to the remote server.<\/p>\n\n\n\n<p>&#8212; \ub85c\uceec\uc11c\ubc84\uc758 \uae00 \uc0ad\uc81c\uc2dc \ub9ac\ubaa8\ud2b8 \uc11c\ubc84 \uc0ad\uc81c \ud655\uc778<br>Verify deletion on the remote server when deleting a post on the local server.<\/p>\n\n\n\n<p>&#8212; \ub9ac\ubaa8\ud2b8 \uc11c\ubc84\uc5d0 \uae00 \uc4f0\uace0 \ub85c\uceec\uc11c\ubc84\ub85c \ubc30\ub2ec\ub418\ub294\uc9c0 \ud655\uc778<br>Write a post on the remote server and verify if it is delivered to the local server.<\/p>\n\n\n\n<p>&#8212; \ub9ac\ubaa8\ud2b8 \uc11c\ubc84\uc758 \uae00 \uc0ad\uc81c\uc2dc \ub85c\uceec\uc11c\ubc84 \uae00\ub3c4 \uc0ad\uc81c\ub418\ub294\uc9c0 \ud655\uc778<br>Check whether the local server post is also deleted when the remote server post is deleted.<\/p>\n\n\n\n<p>&#8212; pinafore\uc5d0\uc11c \uae00 \uc0ad\uc81c\uc2dc \ub85c\uceec\uc11c\ubc84 \uae00 \uc0ad\uc81c\ub418\ub294\uc9c0 \ud655\uc778<br>Check if the post is deleted from the local server when deleted in Pinafore.<\/p>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb \uc804\uccb4 \ucf54\ub4dc\ub294 \uae43\ud5c8\ube0c\uc5d0\uc11c \ud655\uc778 \ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<br>You can find the full code on GitHub.<\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/gideonslife01\/flm-nextjs\">https:\/\/github.com\/gideonslife01\/flm-nextjs<\/a><\/p>\n\n\n\n<p>\ud83d\udcc1 \uc804\uccb4 \ud504\ub85c\uc81d\ud2b8 \uad6c\uc870 \/ Overall Project Structure<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>myapp project\/  \n\u251c\u2500\u2500 app\/  (Next.js App Router)\n\u2502   \u251c\u2500\u2500 .well-known\/webfinger\/route.ts  -> webfinger\n\u2502   \u251c\u2500\u2500 api\/follow\/route.ts    -> Follow API(temporary)\n\u2502   \u251c\u2500\u2500 api\/announce\/route.ts  -> Boost(Announcement)\n\u2502   \u251c\u2500\u2500 api\/like\/route.ts.     -> Like API\n\u2502   \u251c\u2500\u2500 api\/posts\/route.ts     -> Writing API\n\u2502   \u251c\u2500\u2500 api\/timeline\/route.ts  -> Timeline API\n\u2502   \u251c\u2500\u2500 api\/followinglist\/route.ts  -> followinglist API\n\u2502   \u251c\u2500\u2500 api\/followerslist\/route.ts  -> followerslist API\n\u2502   \u251c\u2500\u2500 <span style=\"background-color: initial; font-size: inherit; text-align: initial; color: initial;\">api\/v1\/instance<\/span>\/route.ts -> auth\n\u2502   \u251c\u2500\u2500 api\/v1\/apps\/route.ts.    -> auth\n\u2502   \u251c\u2500\u2500 api\/v1\/accounts\/verify_credentials\/route.ts -> auth\n\u2502   \u251c\u2500\u2500 api\/v1\/statuses\/route.ts -> Write Post\n\u2502   \u251c\u2500\u2500 <span style=\"background-color: initial; font-size: inherit; text-align: initial; color: initial;\">api\/v1\/timelines\/home\/route.ts<\/span> -> timeline\n\u2502   \u251c\u2500\u2500 <span style=\"background-color: initial; font-size: inherit; text-align: initial; color: initial;\">oauth\/authorize\/route.ts<\/span> -> auth\n\u2502   \u251c\u2500\u2500 <span style=\"background-color: initial; font-size: inherit; text-align: initial; color: initial;\">oauth\/token\/route.ts<\/span> -> auth\n\u2502   \u251c\u2500\u2500 <span style=\"background-color: initial; font-size: inherit; text-align: initial; color: initial;\">api\/v1\/search\/home\/route.ts<\/span> -> search\n\u2502   \u251c\u2500\u2500 <span style=\"background-color: initial; font-size: inherit; text-align: initial; color: initial;\">api\/v2\/search\/home\/route.ts<\/span> -> search\n\u2502   \u251c\u2500\u2500 api\/v1\/accounts\/&#91;id]\/followers\/route.ts -> followers\n\u2502   \u251c\u2500\u2500 api\/v1\/accounts\/&#91;id]\/following\/route.ts -> following\n\u2502   \u251c\u2500\u2500 <strong>api\/v1\/statuses\/&#91;id]\/route.ts -> -> Post delete(pinafore)<\/strong>\n\u2502   \u251c\u2500\u2500 api\/auth\/signup\/route.ts        -> Signup\n\u2502   \u251c\u2500\u2500 api\/auth\/login\/route.ts         -> Login\n\u2502   \u251c\u2500\u2500<strong> <\/strong>api\/auth\/logout\/route.ts        -> Logout\n\u2502   \u251c\u2500\u2500<strong> <\/strong>api\/auth\/refresh\/route.ts       -> Refresh Token\n\u2502   \u251c\u2500\u2500<strong> <\/strong>api\/cleanup-orphan\/route.ts     -> post,outbox clean up\n\u2502   \u251c\u2500\u2500<strong> <\/strong>api\/auth\/me\/route.tsx           -> Login Check<strong>\n<\/strong>\u2502   \u251c\u2500\u2500 auth\/signup\/page.tsx            -> Signup UI\n\u2502   \u251c\u2500\u2500 auth\/signup\/page.tsx            -> Login UI\n\u2502   \u251c\u2500\u2500 users\/&#91;username]\/\n\u2502   \u2502   \u251c\u2500\u2500 statuses\/&#91;id]\/route.ts -> Indivisual Post\n\u2502   \u2502   \u251c\u2500\u2500 route.ts               -> Acotr Information\n\u2502   \u2502   \u251c\u2500\u2500 followers\/route.ts     -> Followers List\n\u2502   \u2502   \u251c\u2500\u2500 following\/route.ts     -> Following List\n\u2502   \u2502   \u251c\u2500\u2500 inbox\/route.ts         -> Inbox\n\u2502   \u2502   \u2514\u2500\u2500 outbox\/route.ts        -> outbox\n\u2502   \u251c\u2500\u2500 usersui\/&#91;username]\/\n\u2502   \u2502   \u251c\u2500\u2500 page.tsx               -> Timeline UI(Server, 404)\n\u2502   \u2502   \u251c\u2500\u2500 ClientPage.tsx.        -> Timeline UI(Client,Call Active Themes)\n\u2502   \u2502   \u2514\u2500\u2500 _components\/themes\/\n\u2502   \u2502       \u251c\u2500\u2500 themeex\/ThemeexTheme.tsx   -> Example Theme\n\u2502   \u2502       \u251c\u2500\u2500 pinafore\/PinaforeTheme.tsx -> Theme 1\n\u2502   \u2502       \u251c\u2500\u2500 pinafore\/FollowersList.tsx -> Theme 1, FollowersList\n\u2502   \u2502       \u251c\u2500\u2500 pinafore\/FollowingList.tsx -> Theme 1, FollowingList\n\u2502   \u2502       \u251c\u2500\u2500 pinafore\/NotificationsList.tsx -> Theme 1, NotificationsList\n\u2502   \u2502       \u251c\u2500\u2500 mastodon\/MastodonTheme.tsx -> Theme 2\n\u2502   \u2502       \u2514\u2500\u2500 minimal\/MinimaltTheme.tsx  -> Theme 3\n\u2502   \u251c\u2500\u2500 layout.tsx, page.tsx, globals.css\n\u2502   \u2514\u2500\u2500 favicon.ico\n\u251c\u2500\u2500 lib\/\n\u2502   \u251c\u2500\u2500 theme.tsx              -> Theme Provider\n\u2502   \u251c\u2500\u2500 watchThemes.ts         -> Check real-time theme changes\n\u2502   \u251c\u2500\u2500 auth.ts                -> Authentication, User Management\n\u2502   \u251c\u2500\u2500 ap.ts                  -> Follow,Undo,Create,Likes,Announce\n\u2502   \u2514\u2500\u2500 db.ts                  -> DB connection\n\u251c\u2500\u2500 data\/\n\u2502   \u251c\u2500\u2500 keys\/userIDs\/          -> private.pem, public.pem(New)\n\u2502   \u2514\u2500\u2500 keys\/                  -> private.pem, public.pem(legacy)\n\u251c\u2500\u2500 data.sqlite                -> Database(1\/3)\n\u251c\u2500\u2500 data.sqlite-wal            -> Database(2\/3)\n\u251c\u2500\u2500 data.sqlite-shm            -> Database(3\/3)\n\u251c\u2500\u2500 Caddyfile                  -> https \n\u251c\u2500\u2500 instrumentation.ts         -> Background Server\n\u2514\u2500\u2500 package.json<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 \ud504\ub85c\uc81d\ud2b8 \uc2dc\uc791 \/ Project Start<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-wp-embed is-provider-freelifemakers-org wp-block-embed-freelifemakers-org\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"wp-embedded-content\" data-secret=\"506EgaVcrr\"><a href=\"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2026\/09\/03\/nextjs-project-summary\/\">[nextjs]\ud504\ub85c\uc81d\ud2b8\uc694\uc57d\/project summary(myapp30+)<\/a><\/blockquote><iframe loading=\"lazy\" class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; visibility: hidden;\" title=\"&#8220;[nextjs]\ud504\ub85c\uc81d\ud2b8\uc694\uc57d\/project summary(myapp30+)&#8221; &#8212; freelifemakers.org\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2026\/09\/03\/nextjs-project-summary\/embed\/#?secret=feeaAXtjl2#?secret=506EgaVcrr\" data-secret=\"506EgaVcrr\" width=\"560\" height=\"315\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe>\n<\/div><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>\ud83d\udcc1 cleanup-orphan \ub77c\uc6b0\ud2b8 \uc0ac\uc6a9\ubc29\ubc95<br>How to use the cleanup-orphan route<\/p>\n\n\n\n<p>\u2714\ufe0f \uc0ac\uc6a9\ubc29\ubc95 \/ How to Use<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code># 1. \uc804\uccb4 \uc0ad\uc81c \uc815\ubcf4\ud655\uc778 (GET)\n# Check Bulk Deletion Information (GET)\nCheck Bulk Deletion Information (GET)\n\ncurl \"https:\/\/aloy-horizon.duckdns.org\/api\/cleanup-orphan?username=user1\"\n\n# \ud130\ubbf8\ub110\uc5d0\uc11c \uc2e4\ud589 \uc608 \/ Example run in terminal\ncurl \"https:\/\/aloy-horizon.duckdns.org\/api\/cleanup-orphan?id=5a24536b-06ec-400c-8539-4c1350dd1d19&amp;username=user1\"\n\n# 2. \uc720\ub839\uae00\ub9cc \uc0ad\uc81c (posts\uc640 outbox \ubd88\uc77c\uce58 \ud558\ub294 \uacbd\uc6b0)\n# Delete only \"ghost posts\" (cases where there is a mismatch between `posts` and `outbox`)\n\ncurl -X POST https:\/\/aloy-horizon.duckdns.org\/api\/cleanup-orphan \\\n  -H \"Content-Type: application\/json\" \n  -d '{\"username\":\"user1\"}'\n\n# 3. \ub9ac\ubaa8\ud2b8(GoToSocial, Mastodon) + \ub85c\uceec \uc804\uccb4 \uc0ad\uc81c \n# Delete all remote (GoToSocial, Mastodon) + local data\n\ncurl -X DELETE \"https:\/\/aloy-horizon.duckdns.org\/api\/cleanup-orphan?username=user1&amp;all=true\"\n\n# \ub9ac\ubaa8\ud2b8 + \ub85c\uceec \uae00 \uc9c1\uc811\uc0ad\uc81c \/ Directly delete remote + local posts\ncurl -X DELETE \"https:\/\/aloy-horizon.duckdns.org\/api\/cleanup-orphan?id=5a24536b-06ec-400c-8539-4c1350dd1d19&amp;username=user1\"\n\n# - \ud130\ubbf8\ub110\uc5d0\uc11c \uc2e4\ud589 \/ Run in the terminal\ncurl -X DELETE \"https:\/\/aloy-horizon.duckdns.org\/api\/cleanup-orphan?id=5a24536b-06ec-400c-8539-4c1350dd1d19&amp;username=user1\"\n\n# - \uc751\ub2f5 \/ Response\n{\"message\":\"\u2705 5a24536b-06ec-400c-8539-4c1350dd1d19 \ub9ac\ubaa8\ud2b8+\ub85c\uceec \uc0ad\uc81c \uc644\ub8cc! \uc774\uc81c 410 Tombstone!\",\"deletedId\":\"5a24536b-06ec-400c-8539-4c1350dd1d19\",\"tombstoneUrl\":\"https:\/\/aloy-horizon.duckdns.org\/users\/user1\/statuses\/5a24536b-06ec-400c-8539-4c1350dd1d19\",\"followersCount\":2}                             \n\n<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 \ucf54\ub4dc \uc218\uc815 \/ Code Modification<\/p>\n\n\n\n<p>\u2714\ufe0f app\/users\/[username]\/inbox\/route.ts<\/p>\n\n\n\n<p>&#8212; \ub9ac\ubaa8\ud2b8 \uc11c\ubc84(\uace0\ud22c\uc18c\uc15c)\uc5d0\uc11c \uae00\uc744 \uc4f0\uba74 \ub0b4 \uc11c\ubc84\uc5d0 \ubc30\ub2ec\ub429\ub2c8\ub2e4.<br>When you write a post on a remote server (GoToSocial), it is delivered to your server.<\/p>\n\n\n\n<p>&#8212; \ub9ac\ubaa8\ud2b8 \uc11c\ubc84\uc5d0\uc11c \uae00 \uc0ad\uc81c\uc2dc \ub0b4 \uc11c\ubc84\uc5d0 \ubc30\ub2ec\ub41c \uae00\ub3c4 \uc0ad\uc81c\ud558\ub294 \uae30\ub2a5\uc744 \ucd94\uac00\ud569\ub2c8\ub2e4.<br>Adds a feature to delete posts delivered to your server when they are deleted on the remote server.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>   ... ...     \n   \/\/ \u2705 myapp47 - \ubc30\ub2ec\ub41c \uae00 \uc0ad\uc81c \/ Delete delivered message\n         try {\n            \/\/ GoToSocial Delete\ub294 object\uac00 string \ub610\ub294 object\n            \/\/ In GoToSocial Delete, the object is either a string or an object.\n            \/\/ object: \"https:\/\/freelifemakers.com\/users\/user1\/statuses\/xxx\"\n            let objectId = typeof body.object === 'string'? body.object : body.object?.id;\n\n            \/\/ Tombstone\uc778 \uacbd\uc6b0\n            if (!objectId &amp;&amp; typeof body.object === 'object') {\n              objectId = body.object?.id || body.object;\n            }\n\n            console.log(`\ud83d\uddd1 &#91;${username}] Delete \ub3c4\ucc29! \uc0ad\uc81c\ud560 \uae00: ${objectId}`);\n\n            if (objectId) {\n              const shortId = objectId.split('\/').pop()?.split('#')&#91;0]?.split('?')&#91;0];\n              \/\/ \u2705 myapp47\n              \/\/ 1. original_id \uc815\ud655\ud788 \uc77c\uce58 \/ Exact match for original_id\n              let result = db.prepare('DELETE FROM inbox_posts WHERE original_id=?').run(objectId);\n\n              \/\/ 2. \uc9e7\uc740 ID\ub85c LIKE \uac80\uc0c9 (posts\/ vs statuses\/ \ud638\ud658 + \uc61b\ub0a0 ID \ud638\ud658)\n              \/\/ LIKE search using short IDs (compatible with posts\/ vs. statuses\/ and legacy IDs)\n              if (result.changes === 0 &amp;&amp; shortId) {\n                result = db.prepare('DELETE FROM inbox_posts WHERE original_id LIKE?').run(`%${shortId}%`);\n              }\n\n              \/\/ 3. id \uceec\ub7fc\uc5d0 shortId\ub85c \uc800\uc7a5\ub41c \uacbd\uc6b0\n              \/\/ When stored as a shortId in the id column\n              if (result.changes === 0 &amp;&amp; shortId) {\n                result = db.prepare('DELETE FROM inbox_posts WHERE id=? OR id LIKE?').run(shortId, `%${shortId}%`);\n              }\n\n              \/\/ 4. content \uc548\uc5d0 ID\uac00 \uc788\ub294 \uacbd\uc6b0 (GoToSocial\uc774 content\uc5d0 URL \ub123\uc5b4\ub450\ub294 \uacbd\uc6b0)\n              \/\/ When there is an ID within the content (e.g., when GoToSocial embeds a URL in the content)\n              if (result.changes === 0 &amp;&amp; shortId) {\n                try {\n                  result = db.prepare('DELETE FROM inbox_posts WHERE content LIKE?').run(`%${shortId}%`);\n                } catch {}\n              }\n\n              console.log(`\u2705 &#91;${username}] inbox_posts \uc0ad\uc81c \uc644\ub8cc! changes=${result.changes} id=${shortId} objectId=${objectId}`);\n            }\n        } catch (e) {\n          console.error(`\u274c Delete \ucc98\ub9ac \uc2e4\ud328 \/ Delete failed `, e);\n        }\n        return new Response('', { status: 202 });\n... ...<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f app\/users\/[username]\/statuses\/[id]\/route.ts<\/p>\n\n\n\n<p>&#8212;  Tombstone\uc744 \ucd94\uac00 \ud569\ub2c8\ub2e4.(\uc694\uccad\uc774 \uc788\ub294 \uc11c\ubc84\ub97c \uc704\ud574\uc11c \uad6c\ud604)<br>Adds a tombstone (implemented for servers that requested it).<\/p>\n\n\n\n<p>&#8212; \ub0b4 \uc11c\ubc84 \uc6d0\ubcf8 \uae00 \uc0ad\uc81c\uc2dc \uae00\uc774 \ubc30\ub2ec\ub41c \uc11c\ubc84\uc5d0  \ub0b4 \uae00 \uc0ad\uc81c \ud574\ub2ec\ub77c\ub294 DELETE\uc694\uccad\uc744 \ubcf4\ub0c5\ub2c8\ub2e4.<br>When the original post is deleted from my server, a DELETE request is sent to the servers where the post was delivered, asking them to delete it.<\/p>\n\n\n\n<p>&#8212; \ub9ac\ubaa8\ud2b8\uc11c\ubc84\uac00 DELETE \uc694\uccad\uc744 \ubc1b\uc73c\uba74 \ub0b4 \uc11c\ubc84\uc5d0\uc11c app\/users\/[username]\/statuses\/[id]  \uc774 \ub77c\uc6b0\ud2b8\ub97c \uc2e4\ud589\ud569\ub2c8\ub2e4.<br>When the remote server receives a DELETE request, it executes the <code>app\/users\/[username]\/statuses\/[id]<\/code> route on my server.<\/p>\n\n\n\n<p>&#8212; \uc774 \ub77c\uc6b0\ud2b8\ub294 \uc6d0\ubcf8\uae00\uc744 \ub0b4 \ub370\uc774\ud130\ubca0\uc774\uc2a4\uc5d0\uc11c \uac80\uc0c9\ud6c4 \uae00\uc774 \uc5c6\ub294\uac8c \ud655\uc778\ub418\uba74 tombstone \uc73c\ub85c \uc751\ub2f5\ud569\ub2c8\ub2e4.<br>This route searches my database for the original post and responds with a tombstone if it confirms the post does not exist.<\/p>\n\n\n\n<p>&#8212; tombstone\uc744 \ub9ac\ubaa8\ud2b8 \uc11c\ubc84\uac00 \ud655\uc778\ud558\uba74 \uae00\uc744 \uc2e4\uc81c\ub85c \uc0ad\uc81c\ud569\ub2c8\ub2e4.<br>When the remote server verifies the tombstone, it actually deletes the post.<\/p>\n\n\n\n<p>&#8212; tombstone\uc744 \ud655\uc778 \ud558\ub294 \uc774\uc720\ub294 \ud5c8\uc704 delete\uc694\uccad\uc73c\ub85c \uae00 \uc0ad\uc81c\ub418\ub294\uac78 \ubc29\uc9c0 \ud558\uae30 \uc704\ud568\uc785\ub2c8\ub2e4.<br>The reason for checking the tombstone is to prevent posts from being deleted due to fraudulent delete requests.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\nexport async function GET(\n  req: Request,\n  { params }: { params: Promise&lt;{ username: string; id: string }&gt; }\n) {\n... ...\n  if (!post) {\n    \/\/  404 \ub9d0\uace0 410 + Tombstone, GoToSocial, Mastodon\uc5d0 \uc0ad\uc81c \ud655\uc778 \uc6a9\n    \/\/ For deletion confirmation on Tombstone, GoToSocial, Mastodon instead of 404 410\n    console.log(`\ud83e\udea6 Tombstone \uc751\ub2f5: ${id}`);\n    return NextResponse.json({\n      '@context': 'https:\/\/www.w3.org\/ns\/activitystreams',\n      id: `https:\/\/${DOMAIN}\/users\/${username}\/statuses\/${id}`,\n      <strong>type: 'Tombstone'<\/strong>, \/\/ \u2b50\ufe0f\n      formerType: 'Note',\n      deleted: new Date().toISOString()\n    }, {\n      status: 410, \/\/ 410 Gone\n      headers: {\n        'Content-Type': 'application\/activity+json; charset=utf-8',\n        'Access-Control-Allow-Origin': '*'\n      }\n    });\n  }\n\n  \/\/ id, url \ubaa8\ub450 \/statuses\/\ub85c \uc77c\uce58 \uc2dc\ud0b4 \/ Match both id and url to \/statuses\/\n  const note = {\n    '@context': 'https:\/\/www.w3.org\/ns\/activitystreams',\n    id: `https:\/\/${DOMAIN}\/users\/${username}\/statuses\/${id}`,\n    type: 'Note',\n    attributedTo: `https:\/\/${DOMAIN}\/users\/${username}`,\n    content: post.content?.startsWith('&lt;p&gt;') ? post.content : `&lt;p&gt;${post.content}&lt;\/p&gt;`,\n    published: new Date(post.created_at || Date.now()).toISOString(),\n    to: &#91;'https:\/\/www.w3.org\/ns\/activitystreams#Public'],\n    cc: &#91;`https:\/\/${DOMAIN}\/users\/${username}\/followers`],\n    url: `https:\/\/${DOMAIN}\/users\/${username}\/statuses\/${id}`\n  };\n... ...\n}\n... ...<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 \ud14c\uc2a4\ud2b8 \/ Test<\/p>\n\n\n\n<p>\u2714\ufe0f \uace0\ud22c\uc18c\uc15c\uc5d0\uc11c \uae00 \uc791\uc131\uc2dc \ub85c\uceec\uc11c\ubc84\ub85c \uae00 \ubc30\ub2ec\ub418\ub294\uc9c0 \ud655\uc778<br>Verify if posts are delivered to the local server when creating a post on GoToSocial.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"633\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-2-gotosocial-jpg.jpg\" alt=\"\" class=\"wp-image-10949\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-2-gotosocial-jpg.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-2-gotosocial-jpg-300x237.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-2-gotosocial-jpg-768x608.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-2-gotosocial-jpg-400x317.jpg 400w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">gotosocial<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"434\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-2-aloy-jpg.jpg\" alt=\"\" class=\"wp-image-10950\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-2-aloy-jpg.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-2-aloy-jpg-300x163.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-2-aloy-jpg-768x417.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-2-aloy-jpg-400x217.jpg 400w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">aloy-horizon.duckdns.org<\/figcaption><\/figure>\n\n\n\n<p>\u2714\ufe0f \ub9ac\ubaa8\ud2b8\uae00 \ubc0f \ub85c\uceec \uae00 \uc9c1\uc811\uc0ad\uc81c(cleanup-orphan)<br>Direct deletion of remote and local entries<\/p>\n\n\n\n<p>&#8212; \ud130\ubbf8\ub110\uc5d0\uc11c \uc2e4\ud589 \/ Run in the terminal<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>curl -X DELETE \"https:\/\/aloy-horizon.duckdns.org\/api\/cleanup-orphan?id=5a24536b-06ec-400c-8539-4c1350dd1d19&amp;username=user1\"<\/code><\/pre>\n\n\n\n<p>&#8211;\uc11c\ubc84\ub85c\uadf8 \/ Server Log<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"348\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-5a24-delete-serverlog-jpg.jpg\" alt=\"\" class=\"wp-image-10939\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-5a24-delete-serverlog-jpg.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-5a24-delete-serverlog-jpg-300x131.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-5a24-delete-serverlog-jpg-768x334.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-5a24-delete-serverlog-jpg-400x174.jpg 400w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">cleanup-orphan &#8211; server log<\/figcaption><\/figure>\n\n\n\n<p>\u2714\ufe0f \ub85c\uceec\uc11c\ubc84\uc5d0\uc11c \uae00 \uc791\uc131\ud558\uace0 \uc0ad\uc81c\uc2dc \ub9ac\ubaa8\ud2b8 \uc11c\ubc84 \uae00\ub3c4 \uc0ad\uc81c \ub418\ub294\uc9c0 \ud14c\uc2a4\ud2b8<br>Testing whether a post on the remote server is also deleted when creating and deleting a post on the local server.<\/p>\n\n\n\n<p>&#8212; \ud130\ubbf8\ub110\uc5d0\uc11c \uae00\uc4f0\uae30 \/ Writing in the terminal<\/p>\n\n\n\n<p>&#8212;  pinafore.social\uc5d0 \ub85c\uadf8\uc778\ud574\uc11c \uae00\uc368\ub3c4 \ub429\ub2c8\ub2e4.<br>You can log in to pinafore.social and write posts.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>curl -X POST https:\/\/aloy-horizon.duckdns.org\/api\/posts \\\n  -H \"Content-Type: application\/json\" \\\n  -d '{\"username\":\"user1\",\"content\":\"Hello local UI #apiposts myapp47\"}'<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"428\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-2-serverlog-jpg.jpg\" alt=\"\" class=\"wp-image-10944\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-2-serverlog-jpg.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-2-serverlog-jpg-300x161.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-2-serverlog-jpg-768x411.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp47-2-serverlog-jpg-400x214.jpg 400w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">Server Log<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>\u2714\ufe0f pinafore\uc5d0\uc11c \uae00 \uc0ad\uc81c \uae30\ub2a5 \ud14c\uc2a4\ud2b8\ub294 \uc644\ub8cc\ud588\uace0 \uc774\ubbf8\uc9c0 \ucca8\ubd80\ub098 \uc124\uba85\uc740 \uc0dd\ub7b5\ud569\ub2c8\ub2e4.<br>I have finished testing the post deletion function in Pinafore; I am omitting the image attachments and descriptions.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>\uc694\ud55c\ubcf5\uc74c 8\uc7a5 32\uc808 \/ John 8:32<\/p>\n\n\n\n<p>&#8220;\uadf8\ub9ac\uace0 \ub108\ud76c\ub294 \uc9c4\ub9ac\ub97c \uc54c\uac8c \ub420 \uac83\uc774\uba70, \uc9c4\ub9ac\uac00 \ub108\ud76c\ub97c \uc790\uc720\ub86d\uac8c \ud560 \uac83\uc774\ub2e4.&#8221;<\/p>\n\n\n\n<p>&#8220;Then you will know the truth ,and the truth will set you free&#8221;<\/p>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>\ud83d\udc49\ud83c\udffb myapp47\uc5d0\uc11c \ucd94\uac00\ub41c \uc0ac\ud56d \uc785\ub2c8\ub2e4.These are the additions made in myapp47. \u2714\ufe0f api\/clenaup-orphan \ub77c\uc6b0\ud2b8\ub85c \ud574\ub2f9\uae00\uc744 \uc9c1\uc811 \uc0ad\uc81c \ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.You can delete the post directly using the api\/cleanup-orphan route. \u2714\ufe0f app\/users\/[username]\/statuses\/[id]\/route.ts \uc774 \ub77c\uc6b0\ud2b8\uc5d0 tombstone\uc774 \ucd94\uac00\ub418\uc5c8\uc2b5\ub2c8\ub2e4.A tombstone has been added to the app\/users\/[username]\/statuses\/[id]\/route.ts route. \u2714\ufe0f app\/api\/v1\/statuses\/[id]\/route.ts \ub77c\uc6b0\ud2b8\uac00 \ucd94\uac00\ub418\uc5c8\uc2b5\ub2c8\ub2e4.(pinafore\uc5d0\uc11c \uae00 \uc0ad\uc81c \ud560 \ub54c \uc0ac\uc6a9 )The app\/api\/v1\/statuses\/[id]\/route.ts route [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":10939,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[28,27,1,7],"tags":[],"class_list":["post-10890","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-news","category-nextjs","category-uncategorized","category-website","has-thumbnail"],"_links":{"self":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/10890","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/comments?post=10890"}],"version-history":[{"count":65,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/10890\/revisions"}],"predecessor-version":[{"id":10964,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/10890\/revisions\/10964"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media\/10939"}],"wp:attachment":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=10890"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=10890"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=10890"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}