{"id":11197,"date":"2026-09-28T07:45:20","date_gmt":"2026-09-27T22:45:20","guid":{"rendered":"https:\/\/www.freelifemakers.org\/wordpress\/?p=11197"},"modified":"2026-09-28T10:14:26","modified_gmt":"2026-09-28T01:14:26","slug":"nextjs-sns-server-40","status":"publish","type":"post","link":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2026\/09\/28\/nextjs-sns-server-40\/","title":{"rendered":"[nextjs]SNS Server-40(myapp50)\u00a0"},"content":{"rendered":"\n<p>\ud83d\udc49\ud83c\udffb myapp50\uc5d0\uc11c\ub294 \ud14c\ub9c8\uc5d0 \uacf5\uc720\uae30\ub2a5\uc744 \ucd94\uac00 \ud569\ub2c8\ub2e4.<br>myapp50 adds a sharing feature to the theme.<\/p>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb myapp50\ubd80\ud130\ub294 \ub85c\uceec\uc11c\ubc84\uc5d0\uc11c \ud130\ubbf8\ub110\ub85c \uae00 \uc791\uc131\ud558\uace0 \uae00 \uc0ad\uc81c\ud560 \ub54c \ud1a0\ud070\uc744 \uc785\ub825\ud574\uc57c\ud569\ub2c8\ub2e4.<br>Starting with myapp50, you must enter a token when creating or deleting posts via the terminal on the local server.<\/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  -&gt; webfinger\n\u2502   \u251c\u2500\u2500 api\/follow\/route.ts    -&gt; Follow API(temporary)\n\u2502   \u251c\u2500\u2500 api\/announce\/route.ts  -&gt; Boost(Announcement)\n\u2502   \u251c\u2500\u2500 api\/like\/route.ts.     -&gt; Like API\n\u2502   \u251c\u2500\u2500 api\/posts\/route.ts     -&gt; Writing API\n\u2502   \u251c\u2500\u2500 api\/timeline\/route.ts  -&gt; Timeline API\n\u2502   \u251c\u2500\u2500 api\/followinglist\/route.ts  -&gt; followinglist API\n\u2502   \u251c\u2500\u2500 api\/followerslist\/route.ts  -&gt; 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 -&gt; auth\n\u2502   \u251c\u2500\u2500 api\/v1\/apps\/route.ts.    -&gt; auth\n\u2502   \u251c\u2500\u2500 api\/v1\/accounts\/verify_credentials\/route.ts -&gt; auth\n\u2502   \u251c\u2500\u2500 api\/v1\/statuses\/route.ts -&gt; 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> -&gt; timeline\n\u2502   \u251c\u2500\u2500 <span style=\"background-color: initial; font-size: inherit; text-align: initial; color: initial;\">oauth\/authorize\/route.ts<\/span> -&gt; auth\n\u2502   \u251c\u2500\u2500 <span style=\"background-color: initial; font-size: inherit; text-align: initial; color: initial;\">oauth\/token\/route.ts<\/span> -&gt; 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> -&gt; 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> -&gt; search\n\u2502   \u251c\u2500\u2500 api\/v1\/accounts\/&#91;id]\/followers\/route.ts -&gt; followers\n\u2502   \u251c\u2500\u2500 api\/v1\/accounts\/&#91;id]\/following\/route.ts -&gt; following\n\u2502   \u251c\u2500\u2500 api\/v1\/statuses\/&#91;id]\/route.ts -&gt; -&gt; Post delete(pinafore)\n\u2502   \u251c\u2500\u2500 api\/auth\/signup\/route.ts        -&gt; Signup\n\u2502   \u251c\u2500\u2500 api\/auth\/login\/route.ts         -&gt; Login\n\u2502   \u251c\u2500\u2500<strong> <\/strong>api\/auth\/logout\/route.ts        -&gt; Logout\n\u2502   \u251c\u2500\u2500<strong> <\/strong>api\/auth\/refresh\/route.ts       -&gt; Refresh Token\n\u2502   \u251c\u2500\u2500<strong> <\/strong>api\/cleanup-orphan\/route.ts     -&gt; post,outbox clean up\n\u2502   \u251c\u2500\u2500<strong> <\/strong>api\/auth\/me\/route.tsx           -&gt; Login Check<strong>\n<\/strong>\u2502   \u251c\u2500\u2500 auth\/signup\/page.tsx            -&gt; Signup UI\n\u2502   \u251c\u2500\u2500 auth\/signup\/page.tsx            -&gt; Login UI\n\u2502   \u251c\u2500\u2500 users\/&#91;username]\/\n\u2502   \u2502   \u251c\u2500\u2500 statuses\/&#91;id]\/route.ts -&gt; Indivisual Post\n\u2502   \u2502   \u251c\u2500\u2500 route.ts               -&gt; Acotr Information\n\u2502   \u2502   \u251c\u2500\u2500 followers\/route.ts     -&gt; Followers List\n\u2502   \u2502   \u251c\u2500\u2500 following\/route.ts     -&gt; Following List\n\u2502   \u2502   \u251c\u2500\u2500 inbox\/route.ts         -&gt; Inbox\n\u2502   \u2502   \u2514\u2500\u2500 outbox\/route.ts        -&gt; outbox\n\u2502   \u251c\u2500\u2500 usersui\/&#91;username]\/\n\u2502   \u2502   \u251c\u2500\u2500 page.tsx               -&gt; Timeline UI(Server, 404)\n\u2502   \u2502   \u251c\u2500\u2500 ClientPage.tsx.        -&gt; Timeline UI(Client,Call Active Themes)\n\u2502   \u2502   \u2514\u2500\u2500 _components\/themes\/\n\u2502   \u2502       \u251c\u2500\u2500 themeex\/ThemeexTheme.tsx   -&gt; Example Theme\n\u2502   \u2502       \u251c\u2500\u2500 pinafore\/PinaforeTheme.tsx -&gt; Theme 1\n\u2502   \u2502       \u251c\u2500\u2500 pinafore\/FollowersList.tsx -&gt; Theme 1, FollowersList\n\u2502   \u2502       \u251c\u2500\u2500 pinafore\/FollowingList.tsx -&gt; Theme 1, FollowingList\n\u2502   \u2502       \u251c\u2500\u2500 pinafore\/NotificationsList.tsx -&gt; Theme 1, NotificationsList\n\u2502   \u2502       \u251c\u2500\u2500 mastodon\/MastodonTheme.tsx -&gt; Theme 2\n\u2502   \u2502       \u2514\u2500\u2500 minimal\/MinimaltTheme.tsx  -&gt; 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              -&gt; Theme Provider\n\u2502   \u251c\u2500\u2500 watchThemes.ts         -&gt; Check real-time theme changes\n\u2502   \u251c\u2500\u2500 auth.ts                -&gt; Authentication, User Management\n\u2502   \u251c\u2500\u2500 ap.ts                  -&gt; Follow,Undo,Create,Likes,Announce\n\u2502   \u251c\u2500\u2500 visibility.ts          -&gt; Visibility(Public,Unlisted,Private,Direct)\n\u2502   \u2514\u2500\u2500 db.ts                  -&gt; DB connection\n\u251c\u2500\u2500 data\/\n\u2502   \u251c\u2500\u2500 keys\/userIDs\/          -&gt; private.pem, public.pem(New)\n\u2502   \u2514\u2500\u2500 keys\/                  -&gt; private.pem, public.pem(legacy)\n\u251c\u2500\u2500 data.sqlite                -&gt; Database(1\/3)\n\u251c\u2500\u2500 data.sqlite-wal            -&gt; Database(2\/3)\n\u251c\u2500\u2500 data.sqlite-shm            -&gt; Database(3\/3)\n\u251c\u2500\u2500 Caddyfile                  -&gt; https \n\u251c\u2500\u2500 instrumentation.ts         -&gt; 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=\"NOLZyDDwVx\"><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=akPo3gNZJG#?secret=NOLZyDDwVx\" data-secret=\"NOLZyDDwVx\" 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 \ucf54\ub4dc \uc218\uc815 \/ Code modification<\/p>\n\n\n\n<p>\u2714\ufe0f \uacf5\uc720 \uae30\ub2a5 \ucd94\uac00 \/ Added sharing feature<\/p>\n\n\n\n<p>&#8212; app\/usersui\/[username]\/ClientPage.tsx<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\n  \/\/ \u2705 myapp50 - \uacf5\uc720 \uae30\ub2a5 - (ActivityPub\uc774\ub791 \uc0c1\uad00\uc5c6\uc74c)\n  \/\/ Sharing feature - (Unrelated to ActivityPub)\n  const handleShare = async (post: any) => {\n    const latest = timelineRef.current.find((p: any) => p.id === post.id) || post;\n    const DOMAIN = process.env.NEXT_PUBLIC_DOMAIN || 'aloy-horizon.duckdns.org';\n\n    let url = latest.original_id || latest.id;\n    if (!url.startsWith('http')) {\n      url = `https:\/\/${DOMAIN}\/users\/${latest.username}\/statuses\/${url}`;\n    }\n    \n    const shareUrl = url.includes('\/statuses\/')? url : `https:\/\/${DOMAIN}\/users\/${latest.username}\/statuses\/${latest.id}`;\n\n    const text = latest.content? latest.content.replace(\/&lt;&#91;^>]*>\/g, '').slice(0, 100) : '';\n\n    \/\/ 1. \ubaa8\ubc14\uc77c - \ub124\uc774\ud2f0\ube0c \uacf5\uc720 \uc2dc\ud2b8 (\uce74\ud1a1, \ud154\ub808\uadf8\ub7a8, \uc5d0\uc5b4\ub4dc\ub78d \uc790\ub3d9)\n    \/\/ Mobile \u2013 Native share sheet (KakaoTalk, Telegram, AirDrop supported automatically)\n    if (navigator.share) {\n      try {\n        await navigator.share({\n          title: `${latest.username}\uc758 \uae00`,\n          text: text,\n          url: shareUrl\n        });\n        return { ok: true, method: 'native' };\n      } catch (e) {\n        \/\/ \ucde8\uc18c\ud55c \uacbd\uc6b0 \ubb34\uc2dc\n        console.log('share cancelled', e);\n      }\n    }\n\n    \/\/ 2. PC \ud3f4\ubc31 - \ud074\ub9bd\ubcf4\ub4dc \ubcf5\uc0ac\n    \/\/ PC Fallback - Copy to Clipboard\n    try {\n      await navigator.clipboard.writeText(shareUrl);\n      alert(`\ud83d\udd17 \ub9c1\ud06c \ubcf5\uc0ac\ub428\\n${shareUrl}`);\n      return { ok: true, method: 'clipboard' };\n    } catch {\n      \/\/ \ud074\ub9bd\ubcf4\ub4dc\ub3c4 \ub9c9\ud78c \uacbd\uc6b0\n      prompt('\ub9c1\ud06c \ubcf5\uc0ac:', shareUrl);\n      return { ok: true, method: 'prompt' };\n    }\n  };\n... ...\n  \/\/ \u2705 myapp50 - handleShare\ub97c onShare\uc5d0 \ucd94\uac00\ud574\uc11c \ud14c\ub9c8\ub85c \ub118\uae40\n  \/\/ Added handleShare to onShare and passed it to the theme.\n  const props = { timeline, username, initialView, onBoost: handleBoost, onLike: handleLike, onShare: handleShare };\n... ...<\/code><\/pre>\n\n\n\n<p>&#8212; app\/usersui\/[username]\/_components\/themes\/pinafore\/PinaforeTheme.tsx <\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\nexport function PinaforeTheme({ timeline : initialTimeline, username, initialView, onBoost, onLike, <strong>onShare<\/strong> }: any) {\n... ...\n     &lt;div className=\"status-actions\"&gt;\n           &lt;button onClick={() =&gt; onBoost(p)} className={p.isMyBoost? 'boosted' : ''}&gt;\ud83d\udd01 {p.boostCount || ''}&lt;\/button&gt;\n           &lt;button onClick={() =&gt; onLike(p)} className={p.isMyLike? 'liked' : ''}&gt;\u2b50 {p.likeCount || ''}&lt;\/button&gt;\n            <strong>&lt;button onClick={() =&gt; onShare(p)}&gt;\u2708\ufe0f&lt;\/button&gt; <\/strong>{\/* \u2705 myapp50 - Share *\/}\n            &lt;button&gt;\ud83d\udcac&lt;\/button&gt;\n      &lt;\/div&gt;\n... ...\n}<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f \uae00\uc4f0\uae30,\uae00\uc0ad\uc81c \ubcf4\uc548\uac15\ud654(\ub85c\uceec\uc11c\ubc84)<br>Enhanced security for posting and deleting content (local server)<\/p>\n\n\n\n<p>&#8212; app\/api\/posts\/route.ts<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>\/\/ \u2705 myapp50 - \uacf5\ud1b5 \uc778\uc99d \ud568\uc218 - refresh_token(\ucfe0\ud0a4) + Bearer \ub458 \ub2e4 \uccb4\ud06c\n\/\/ Common authentication function \u2013 checks for both refresh_token (cookie) and Bearer token.\nfunction getAuthenticatedUser(req: Request): string | null {\n  \/\/ 1. Bearer \ud1a0\ud070 (Pinafore, curl)\n  const auth = req.headers.get('Authorization') || '';\n  const token = auth.replace('Bearer ', '').trim();\n  if (token) {\n    try {\n      const oauth = db.prepare('SELECT username FROM oauth_tokens WHERE access_token=?').get(token) as any;\n      if (oauth?.username) return oauth.username;\n    } catch {}\n  }\n  \/\/ 2. refresh_token \ucfe0\ud0a4 (\uc6f9 UI)\n  try {\n    const viewer = getViewerFromRequest(req as any);\n    if (viewer) return viewer;\n  } catch {}\n  return null;\n}\n... ...\nexport async function POST(req: Request) {\n\n  let { content,visibility } = await req.json();\n  \/\/ \u2705 myapp48 - visibility default value\n  visibility = visibility || 'public';\n\n  \/\/ \u2705 myapp45 - apply token - deleted myapp50\n  \/\/ const auth = req.headers.get('Authorization') || '';\n  \/\/ const token = auth.replace('Bearer ', '').trim();\n  \/\/ if (token) {\n  \/\/   const oauth = db.prepare('SELECT username FROM oauth_tokens WHERE access_token=?').get(token) as any;\n  \/\/   if (oauth?.username) username = oauth.username; \/\/ \ud1a0\ud070 \uc788\uc73c\uba74 \ud1a0\ud070 \uc720\uc800\ub85c \ub36e\uc5b4\uc4f0\uae30!\n  \/\/ }\n\n   \/\/ \u2705 myapp50 - \ubc14\ub514 username \uc808\ub300 \uc2e0\ub8b0 \uae08\uc9c0, \uc778\uc99d\ub41c \uc720\uc800\ub9cc \uc0ac\uc6a9\n   \/\/ Never blindly trust usernames; use only verified users.\n <strong> const username = getAuthenticatedUser(req);<\/strong>\n... ...\n}\n\n<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f \uae00\uc4f0\uae30 \uc0ad\uc81c\ub294 v1\/statuses\/route.ts\ub85c \uc124\uc815<br>Post deletion is configured in v1\/statuses\/route.ts.<\/p>\n\n\n\n<p>&#8212; \uae30\uc874 posts\/route.ts\ub294 \uc0ad\uc81c\ud568.<br>Deleted the existing posts\/route.ts.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>const handleDelete = async (postId: string) => {\n  if (!confirm('\uc0ad\uc81c\ud560\uae4c? \/ Delete?')) return;\n  try {\n    const token = localStorage.getItem('access_token') || localStorage.getItem('token') || '';\n    const res = await fetch(`\/api\/v1\/statuses\/${postId}`, { \n      method: 'DELETE',\n      headers: {\n        ...(token? { Authorization: `Bearer ${token}` } : {})\n      },\n      credentials: 'include' \/\/ refresh_token \ucfe0\ud0a4 \ud3ec\ud568\n    });\n    if (res.ok) {\n      setTimeline((prev: any&#91;]) => prev.filter((t: any) => t.id !== postId &amp;&amp; t.original_id !== postId));\n      console.log(`\ud83d\uddd1 Delete ${postId} ok`);\n    } else {\n      const err = await res.json().catch(()=>({}));\n      console.error('delete fail', err);\n      alert(`\uc0ad\uc81c \uc2e4\ud328: ${err.error || res.status}`);\n    }\n  } catch (e) {\n    console.error(e);\n    alert('\uc0ad\uc81c \uc2e4\ud328 \/ Deletion failed');\n  }\n};<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 \ud14c\uc2a4\ud2b8 \/ Test<\/p>\n\n\n\n<p>\u2714\ufe0f \uacf5\uc720\uae30\ub2a5 \/ Sharing feature<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"598\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp50-share-jpg.jpg\" alt=\"\" class=\"wp-image-11238\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp50-share-jpg.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp50-share-jpg-300x224.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp50-share-jpg-768x574.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp50-share-jpg-400x299.jpg 400w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">Sharing feature<\/figcaption><\/figure>\n\n\n\n<p>\u2714\ufe0f \uc774 \ub85c\uceec \uc11c\ubc84 \ubd80\ubd84\uc740 \ub098\uc911\uc5d0 \uc0ad\uc81c \ub420 \uc218\ub3c4 \uc788\uc74c(v1\/statues \uc640 \uae30\ub2a5 \uc911\ubcf5)<br>This local server section might be removed later.(Functionality overlaps with v1\/statues)<\/p>\n\n\n\n<p>\u2714\ufe0f \uc544\ub798\ub294 \uc0ac\uc6a9\ud558\uc9c0 \uc54a\uc9c0\ub9cc \ub77c\uc6b0\ud2b8\uac00 \uc874\uc7ac\ud558\uc9c0 \ub54c\ubb38\uc5d0 \ud1a0\ud070 \uc785\ub825\uc73c\ub85c \ubcf4\uc548\uc124\uc815\uc744 \uac15\ud654\ud569\ub2c8\ub2e4.<br>Although the route below is not currently in use, it exists, so security settings are being strengthened by requiring a token for access.<\/p>\n\n\n\n<p>\u2714\ufe0f \ud1a0\ud070 \uc5c6\uc774  \ud130\ubbf8\ub110\uc5d0\uc11c \uae00\uc4f0\uae30 \ud55c\uacbd\uc6b0(\ub85c\uceec \uc11c\ubc84)<br>Writing in the terminal without a token (local server)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Terminal\ncurl -s -X POST https:\/\/aloy-horizon.duckdns.org\/api\/posts \\\n  -H \"Content-Type: application\/json\" \\\n  -d '{\"content\":\"No token test\"}'\n\n# response\n{\"error\":\"\ub85c\uadf8\uc778 \ud544\uc694 \/ username required\"}\n                                                                                                    <\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f \ud1a0\ud070\uc73c\ub85c \uae00\uc4f0\uae30 \ud55c\uacbd\uc6b0(\ub85c\uceec \uc11c\ubc84)<br>Writing posts using a token (local server)<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code># Terminal\ncurl -X POST https:\/\/aloy-horizon.duckdns.org\/api\/posts \\\n  -H \"Cookie: refresh_token=099b61b8616edcf48b4... ...\" \\\n  -H \"Content-Type: application\/json\" \\\n  -d '{\"content\":\"token present\"}'\n\n# response\n{\"id\":\"f0cba853-5fa3-4f28-bc44-6a367a78d0b3\",\"content\":\"token present\",\"created_at\":1790553173171,\"username\":\"user1\",\"visibility\":\"public\",\"original_id\":null,\"sensitive\":0}%       \n<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"702\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp50-token-present-jpg.jpg\" alt=\"\" class=\"wp-image-11235\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp50-token-present-jpg.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp50-token-present-jpg-300x263.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp50-token-present-jpg-768x674.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp50-token-present-jpg-400x351.jpg 400w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">UI<\/figcaption><\/figure>\n\n\n\n<p>\u2714\ufe0f \ud130\ubbf8\ub110\uc5d0\uc11c \ud1a0\ud070 \uc5c6\uc774 \uc0ad\uc81c \uc2dc\ub3c4\ud55c \uacbd\uc6b0<br>When attempting deletion without a token in the terminal<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code># Terminal\ncurl -s -X DELETE https:\/\/aloy-horizon.duckdns.org\/api\/posts \\\n -H \"Content-Type: application\/json\" \\\n -d '{\"username\":\"user1\",\"id\":\"f0cba853-5fa3-4f28-bc44-6a367a78d0b3\"}'\n\n# response\n{\"error\":\"unauthorized - username required\"}%      <\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f \ud130\ubbf8\ub110\uc5d0\uc11c \ud1a0\ud070\uc73c\ub85c \uc0ad\uc81c\ud558\ub294 \uacbd\uc6b0<br>When deleting using a token in the terminal<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code># Terminal\ncurl -s -X DELETE https:\/\/aloy-horizon.duckdns.org\/api\/posts \\\n -H \"Cookie: refresh_token=099b61b8616edcf48b4 ... ....\" \\\n -H \"Content-Type: application\/json\" \\\n -d '{\"username\":\"user1\",\"id\":\"f0cba853-5fa3-4f28-bc44-6a367a78d0b3\"}'\n\n# response\n{\"ok\":true,\"deletedId\":\"f0cba853-5fa3-4f28-bc44-6a367a78d0b3\"}%    <\/code><\/pre>\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 myapp50\uc5d0\uc11c\ub294 \ud14c\ub9c8\uc5d0 \uacf5\uc720\uae30\ub2a5\uc744 \ucd94\uac00 \ud569\ub2c8\ub2e4.myapp50 adds a sharing feature to the theme. \ud83d\udc49\ud83c\udffb myapp50\ubd80\ud130\ub294 \ub85c\uceec\uc11c\ubc84\uc5d0\uc11c \ud130\ubbf8\ub110\ub85c \uae00 \uc791\uc131\ud558\uace0 \uae00 \uc0ad\uc81c\ud560 \ub54c \ud1a0\ud070\uc744 \uc785\ub825\ud574\uc57c\ud569\ub2c8\ub2e4.Starting with myapp50, you must enter a token when creating or deleting posts via the terminal on the local server. \ud83d\udc49\ud83c\udffb \uc804\uccb4 \ucf54\ub4dc\ub294 \uae43\ud5c8\ube0c\uc5d0\uc11c \ud655\uc778 \ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.You can find the full [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":11238,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[28,27,1,7,29],"tags":[],"class_list":["post-11197","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-news","category-nextjs","category-uncategorized","category-website","category-webui","has-thumbnail"],"_links":{"self":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/11197","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=11197"}],"version-history":[{"count":33,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/11197\/revisions"}],"predecessor-version":[{"id":11243,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/11197\/revisions\/11243"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media\/11238"}],"wp:attachment":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=11197"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=11197"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=11197"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}