{"id":9927,"date":"2026-09-10T07:33:56","date_gmt":"2026-09-09T22:33:56","guid":{"rendered":"https:\/\/www.freelifemakers.org\/wordpress\/?p=9927"},"modified":"2026-09-10T10:48:14","modified_gmt":"2026-09-10T01:48:14","slug":"nextjs-sns-server-27","status":"publish","type":"post","link":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2026\/09\/10\/nextjs-sns-server-27\/","title":{"rendered":"[nextjs]SNS Server-27(myapp37)\u00a0"},"content":{"rendered":"\n<p>\ud83d\udc49\ud83c\udffb \ud68c\uc6d0\uac00\uc785 \ubc0f \ub85c\uadf8\uc778\uacfc \uad00\ub828\ub41c \uae30\ub2a5\uc785\ub2c8\ub2e4.<br>These are features related to sign-up and login.<\/p>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb myapp27\uc740 \ud314\ub85c\uc6b0,\ud314\ub85c\uc6cc \ub9ac\uc2a4\ud2b8 \uae30\ub2a5\uc744 \uad6c\ud604\ud569\ub2c8\ub2e4.<br>myapp27 implements features for the following and followers lists.<\/p>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb \ud314\ub85c\uc6b0\uc640 \ud314\ub85c\uc6cc \ub9ac\uc2a4\ud2b8\ub294 \ud504\ub85c\ud544\uc744 \ud074\ub9ad\ud558\uba74 \ubcfc \uc218 \uc788\uc2b5\ub2c8\ub2e4.<br>You can view the lists of people you follow and your followers by clicking on the profile.<\/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\"><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 <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 <strong>api\/v1\/accounts\/&#91;id]\/followers\/route.ts -&gt; followers<\/strong>\n\u2502   \u251c\u2500\u2500 <strong>api\/v1\/accounts\/&#91;id]\/following\/route.ts -&gt; following<\/strong>\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\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 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   \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=\"1p4ylQRCQZ\"><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=wTMeq8pUD3#?secret=1p4ylQRCQZ\" data-secret=\"1p4ylQRCQZ\" 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>&nbsp;\ud83d\udcc1 \ub77c\uc6b0\ud2b8 \ucd94\uac00 \ubc0f \ucf54\ub4dc \uc218\uc815 \/ Add routes and modify code<\/p>\n\n\n\n<p>\u2714\ufe0f \ud314\ub85c\uc6cc \/ follower<\/p>\n\n\n\n<p>&#8212; \uc2e0\uaddc \ucd94\uac00\ub41c \ub77c\uc6b0\ud2b8 \/ Newly added routes<\/p>\n\n\n\n<p>&#8212; app\/api\/v1\/accounts\/[id]\/followers\/route.ts<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/ \u2705 myapp37 - followers API\n\/\/ \/api\/v1\/accounts\/:id\/followers\n\nimport { NextResponse } from 'next\/server';\nimport db from '@\/lib\/db';\n\nconst DOMAIN = process.env.DOMAIN || 'aloy-horizon.duckdns.org';\n\nfunction parseActor(actor: string, idx: number) { ... }\nexport async function GET(req: Request, { params }: { params: Promise&lt;{ id: string }&gt; }) { ... }\n\nexport async function OPTIONS() { ... }<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f \ud314\ub85c\uc789 \/ following<\/p>\n\n\n\n<p>&#8212; \uc2e0\uaddc \ucd94\uac00\ub41c \ub77c\uc6b0\ud2b8 \/ Newly added routes<\/p>\n\n\n\n<p>&#8212; app\/api\/v1\/accounts\/[id]\/following\/route.ts<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u2705 myapp37 - following API\n\/\/ \/api\/v1\/accounts\/:id\/following\n\nimport { NextResponse } from 'next\/server';\nimport db from '@\/lib\/db';\n\nconst DOMAIN = process.env.DOMAIN || 'aloy-horizon.duckdns.org';\n\nfunction parseActor(actor: string, idx: number) { ... }\nexport async function GET(req: Request, { params }: { params: Promise&lt;{ id: string }&gt; }) { ... }\nexport async function OPTIONS() { ... }<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f pinafore\uc5d0\uc11c \ud314\ub85c\uc6cc,\ud314\ub85c\uc789 \ubaa9\ub85d\uc740 urlencode\ub77c\uc11c \ucf54\ub4dc \uc218\uc815<br>Modified the code because the follower and following lists in Pinafore are URL-encoded.<\/p>\n\n\n\n<p>&#8212; app\/api\/v1\/apps\/route.ts<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { NextResponse } from 'next\/server';\nimport db from '@\/lib\/db';\nimport { randomUUID } from 'crypto';\n\nconst DOMAIN = process.env.DOMAIN || 'aloy-horizon.duckdns.org';\n\nexport async function POST(req: Request) { \ntry {\n... ...\n    const contentType = req.headers.get('content-type') || '';\n    \n    if (contentType.includes('application\/json')) {\n      const body = await req.json();\n      clientName = body.client_name || 'Unknown';\n      redirectUris = body.redirect_uris || body.redirect_uri || '';\n      scopes = body.scopes || 'read write follow';\n      website = body.website || '';\n    }else{\n      \/\/ form-urlencoded! Pinafore!\uac00! \uc774\uac78\ub85c! \ubcf4\ub0c4!\n      \/\/\n      const text = await req.text();\n      const params = new URLSearchParams(text);\n      clientName = params.get('client_name') || 'Unknown';\n      redirectUris = params.get('redirect_uris') || params.get('redirect_uri') || '';\n      scopes = params.get('scopes') || 'read write follow';\n      website = params.get('website') || '';\n    }\n... ...\n\n    \/\/ \u2705 Pinafore\uac00 \uae30\ub300\ud558\ub294 \uc751\ub2f5! \n    \/\/ Pinafore expects this response!\n    return NextResponse.json({\n      id: clientId, \/\/ Pinafore\ub294 id\ub3c4 \ud655\uc778 \/ Pinafore also checks id\n      name: clientName,\n      website: website,\n      redirect_uri: redirectUris,\n      client_id: clientId,\n      client_secret: clientSecret,\n      vapid_key: '' \/\/ push\uc6a9, \uc5c6\uc5b4\ub3c4 \ub428 \/ for push, not required\n    });\n\n  } catch (e) {\n    console.error('apps \uc5d0\ub7ec \/ apps error:', e);\n    \/\/return NextResponse.json({ error: String(e) }, { status: 500 });\n\n    \/\/ \u2705 myapp37 - \uc5d0\ub7ec\ub098\ub3c4 \uc77c\ub2e8 \uc131\uacf5\uc73c\ub85c \ub9ac\ud134 \/ Return a success status for now, even if an error occurs.\n    return NextResponse.json({\n      id: '1',\n      name: 'Pinafore',\n      website: null,\n      redirect_uri: 'https:\/\/pinafore.social\/settings\/instances\/add',\n      client_id: 'pinafore_client_id',\n      client_secret: 'pinafore_client_secret',\n      vapid_key: null,\n    }, {\n      headers: { 'Access-Control-Allow-Origin': '*' }\n    });\n  }\n\n}<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f Notifications<\/p>\n\n\n\n<p>&#8212; \uc2e0\uaddc \ucd94\uac00\ub41c \ub77c\uc6b0\ud2b8 \/ Newly added routes<\/p>\n\n\n\n<p>&#8212; app\/api\/v1\/notifications\/route.ts<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u2705 myapp37 - myapp\/api\/notifications\/route.ts\n\nimport { NextResponse } from 'next\/server';\n\nexport async function GET() {\n  \/\/ \uc544\uc9c1! \uad6c\ud604 \uc548 \ud568! \ube48 \ubc30\uc5f4! \/ Not yet! Not implemented! Empty array!\n  return NextResponse.json(&#91;], {\n    headers: { 'Access-Control-Allow-Origin': '*' }\n  });\n}\n\nexport async function OPTIONS() {\n  return new NextResponse(null, {\n    status: 204,\n    headers: {\n      'Access-Control-Allow-Origin': '*',\n      'Access-Control-Allow-Methods': 'GET, OPTIONS',\n      'Access-Control-Allow-Headers': 'Content-Type, Authorization'\n    }\n  });\n}<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 \ud14c\uc2a4\ud2b8 \/ Test<\/p>\n\n\n\n<p>\u2714\ufe0f \ub85c\uadf8\uc778 \ud6c4 \ud504\ub85c\ud544\uc5d0\uc11c FOLLOWS\uc640 FOLLOW\ub97c \ud074\ub9ad\ud558\uba74 \ub9ac\uc2a4\ud2b8\ub97c \ubcfc \uc218 \uc788\uc2b5\ub2c8\ub2e4.<br>After logging in, you can view the lists by clicking on &#8220;FOLLOWS&#8221; and &#8220;FOLLOW&#8221; in your profile.<\/p>\n\n\n\n<p>\u2714\ufe0f \ud314\ub85c\uc6b0 \/ Follows<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"765\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp37-follows-jpg-1024x765.jpg\" alt=\"\" class=\"wp-image-9949\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp37-follows-jpg-1024x765.jpg 1024w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp37-follows-jpg-300x224.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp37-follows-jpg-768x574.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp37-follows-jpg-400x299.jpg 400w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp37-follows-jpg-800x598.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp37-follows-jpg.jpg 1352w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Follows<\/figcaption><\/figure>\n\n\n\n<p>\u2714\ufe0f \ud314\ub85c\uc6cc \/ Followers<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"616\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp37-followers-jpg.jpg\" alt=\"\" class=\"wp-image-9950\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp37-followers-jpg.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp37-followers-jpg-300x231.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp37-followers-jpg-768x591.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp37-followers-jpg-400x308.jpg 400w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">Followers<\/figcaption><\/figure>\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\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\ud83d\udc49\ud83c\udffb \ud68c\uc6d0\uac00\uc785 \ubc0f \ub85c\uadf8\uc778\uacfc \uad00\ub828\ub41c \uae30\ub2a5\uc785\ub2c8\ub2e4.These are features related to sign-up and login. \ud83d\udc49\ud83c\udffb myapp27\uc740 \ud314\ub85c\uc6b0,\ud314\ub85c\uc6cc \ub9ac\uc2a4\ud2b8 \uae30\ub2a5\uc744 \uad6c\ud604\ud569\ub2c8\ub2e4.myapp27 implements features for the following and followers lists. \ud83d\udc49\ud83c\udffb \ud314\ub85c\uc6b0\uc640 \ud314\ub85c\uc6cc \ub9ac\uc2a4\ud2b8\ub294 \ud504\ub85c\ud544\uc744 \ud074\ub9ad\ud558\uba74 \ubcfc \uc218 \uc788\uc2b5\ub2c8\ub2e4.You can view the lists of people you follow and your followers by clicking on the profile. \ud83d\udc49\ud83c\udffb \uc804\uccb4 \ucf54\ub4dc\ub294 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":9950,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[28,27,19,1,7],"tags":[],"class_list":["post-9927","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-news","category-nextjs","category-swift","category-uncategorized","category-website","has-thumbnail"],"_links":{"self":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/9927","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=9927"}],"version-history":[{"count":31,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/9927\/revisions"}],"predecessor-version":[{"id":9965,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/9927\/revisions\/9965"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media\/9950"}],"wp:attachment":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=9927"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=9927"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=9927"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}