{"id":10141,"date":"2026-09-12T08:14:38","date_gmt":"2026-09-11T23:14:38","guid":{"rendered":"https:\/\/www.freelifemakers.org\/wordpress\/?p=10141"},"modified":"2026-09-12T13:35:50","modified_gmt":"2026-09-12T04:35:50","slug":"nextjs-sns-server-29","status":"publish","type":"post","link":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2026\/09\/12\/nextjs-sns-server-29\/","title":{"rendered":"[nextjs]SNS Server-29(myapp39)\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 myapp39\uc5d0\uc11c\ub294  \uc774\uc804\uc5d0 \uc644\ub8cc\ub418\uc9c0 \uc54a\uc558\ub358 \ub85c\uadf8\uc778 \uae30\ub2a5\uc744 \uc644\uc131\ud569\ub2c8\ub2e4.<br>In myapp39, we complete the login functionality that was not finished previously.<\/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 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 <strong>api\/auth\/signup\/route.ts  -&gt; Signup<\/strong>\n\u2502   \u251c\u2500\u2500 <strong>api\/auth\/login\/route.ts   -&gt; Login<\/strong>\n\u2502   \u251c\u2500\u2500<strong> api\/auth\/logout\/route.ts  -&gt; Logout\n<\/strong>\u2502   \u251c\u2500\u2500 <strong>auth\/signup\/page.tsx -&gt; Signup UI<\/strong>\n\u2502   \u251c\u2500\u2500 <strong>auth\/signup\/page.tsx -&gt; Login UI<\/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=\"P5RHaBYQfJ\"><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=DORibabXbW#?secret=P5RHaBYQfJ\" data-secret=\"P5RHaBYQfJ\" 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 \ub77c\uc6b0\ud2b8 \ucd94\uac00 \/. Add Route<\/p>\n\n\n\n<p>\u2714\ufe0f app\/api\/auth\/signup\/route.ts &#8211; \ud68c\uc6d0\uac00\uc785 \/ Signup<\/p>\n\n\n\n<p>\u2714\ufe0f app\/api\/auth\/login\/route.ts &#8211; \ub85c\uadf8\uc778 \/ Login<\/p>\n\n\n\n<p>\u2714\ufe0f app\/auth\/login\/page.tsx &#8211; \ub85c\uadf8\uc778 UI \/ Login UI<\/p>\n\n\n\n<p>\u2714\ufe0f app\/auth\/signup\/page.tsx &#8211; \ud68c\uc6d0\uac00\uc785 UI \/ Signup UI<\/p>\n\n\n\n<p>\u2714\ufe0f app\/api\/auth\/logout\/route.ts &#8211; \ub85c\uadf8\uc544\uc6c3 \/ Logout<\/p>\n\n\n\n<p>\ud83d\udcc1 \ucf54\ub4dc\uc218\uc815 \/ Code Modification<\/p>\n\n\n\n<p>\u2714\ufe0f lib\/auth.ts<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>export function getUsernameFromRequest(req: Request | NextRequest): string | null { ... }\nexport function getUsernameFromToken(token: string): string | null { ... }<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f app\/api\/v1\/instance\/route.ts <\/p>\n\n\n\n<p>&#8212; OPTIONS\ud568\uc218 \uc81c\uac70(middleware.ts\uc5d0\uc11c \ucc98\ub9ac)<br>Remove OPTIONS function (handled in middleware.ts)<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>\/\/ \u2705 myapp39 - app\/api\/v1\/instance\/route.ts - middleware\uac00! CORS \ucc98\ub9ac!\ud558\ub2c8\uae4c! \uae54\ub054!\nimport { NextResponse } from 'next\/server';\n\nconst DOMAIN = process.env.DOMAIN || 'aloy-horizon.duckdns.org';\n\nexport async function GET() {\n  return NextResponse.json({\n    uri: `https:\/\/${DOMAIN}`, \n    title: 'Aloy Horizon',\n    short_description: 'My ActivityPub server!',\n    description: 'My own Fediverse server running Next.js',\n    email: 'admin@aloy-horizon.duckdns.org',\n    version: '4.3.0 (compatible; Aloy Horizon 1.0)',\n    urls: {\n      streaming_api: `wss:\/\/${DOMAIN}`\n    },\n    stats: {\n      user_count: 1,\n      status_count: 100,\n      domain_count: 1000\n    },\n    thumbnail: `https:\/\/${DOMAIN}\/icon.png`,\n    languages: &#91;'en', 'ko'],\n    registrations: true,\n    approval_required: false,\n    invites_enabled: false,\n    configuration: {\n      statuses: {\n        max_characters: 500,\n        max_media_attachments: 4\n      }\n    },\n    rules: &#91;]\n  });\n}\n\/\/ OPTIONS\ud568\uc218 \uc81c\uac70 middleware.ts\uc5d0\uc11c \ucc98\ub9ac\n\/\/ Remove OPTIONS function, handle in middleware.ts<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>\u2714\ufe0f app\/oauth\/authorize\/route.ts &#8211; localhost:3000<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\nconst DOMAIN = process.env.DOMAIN || 'aloy-horizon.duckdns.org';\n\/\/const DOMAIN = 'aloy-horizon.duckdns.org';\nconst ORIGIN = `https:\/\/${DOMAIN}`;\n... ...\nexport async function GET(req: Request) { \n... ...\n  \/\/ \u2705 myapp39 - \ub85c\uadf8\uc778 \uccb4\ud06c \/ login check\n  const username = getUsernameFromCookie(req);\n... ...\n \/\/ \u2705 for CORS error\n  if (!username) {\n      const loginUrl = new URL('\/auth\/login', ORIGIN); \n      const realNextUrl = `${ORIGIN}${url.pathname}${url.search}`;\n      loginUrl.searchParams.set('next', realNextUrl);\n      return NextResponse.redirect(loginUrl.toString());\n  }\n... ...\n}<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f caddyfile<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>aloy-horizon.duckdns.org {\n  reverse_proxy localhost:3000 {\n    header_up Host {host}\n    header_up X-Real-IP {remote}\n    header_up X-Forwarded-For {remote}\n    header_up X-Forwarded-Proto {scheme}\n    header_up X-Forwarded-Host {host}\n  }\n encode gzip\n \n  # CORS\ub294! Next.js\uac00! \ucc98\ub9ac!\ud558\ub2c8\uae4c! Caddy\uc5d0\uc11c! \ud5e4\ub354! \ucd94\uac00! \uae08\uc9c0!\n  # Next.js handles CORS, so do not add headers in Caddy!\n}<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f middleware.ts<\/p>\n\n\n\n<p>&#8212; Pinafore\uc5d0\uc11c \ub85c\uadf8\uc778 \ud558\uba74! ERR_CONNECTION_REFUSED + CORS <br>Logging in on Pinafore results in ERR_CONNECTION_REFUSED + CORS!<\/p>\n\n\n\n<p>&#8212; \ubaa8\ub4e0 \uc694\uccad\uc5d0 CORS\ucc98\ub9ac \uc801\uc6a9 \/ Apply CORS handling to all requests.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>\/\/ \u2705 myapp39\/middleware.ts - CORS \uc804\uccb4 \ucc98\ub9ac \/ Global CORS Handling\nimport { NextResponse } from 'next\/server';\nimport type { NextRequest } from 'next\/server';\n\nexport function middleware(req: NextRequest) {\n\n  \/\/ \u2705 OPTIONS preflight \uba3c\uc800 \ucc98\ub9ac\n  \/\/ Process the OPTIONS preflight request first.\n  if (req.method === 'OPTIONS') {\n    return new NextResponse(null, {\n      status: 204,\n      headers: {\n        'Access-Control-Allow-Origin': '*',\n        'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n        'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n        'Access-Control-Max-Age': '86400',\n      },\n    });\n  }\n\n  \/\/ \u2705 \uc77c\ubc18 \uc694\uccad \/ General Request\n  const res = NextResponse.next();\n  res.headers.set('Access-Control-Allow-Origin', '*');\n  res.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');\n  res.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');\n  \n  return res;\n}\n\nexport const config = {\n  matcher: &#91;'\/api\/:path*', '\/oauth\/:path*', '\/.well-known\/:path*', '\/users\/:path*'],\n};<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 \ud14c\uc2a4\ud2b8 \/ Test<\/p>\n\n\n\n<p>\u2714\ufe0f \ud130\ubbf8\ub110 \ud14c\uc2a4\ud2b8 \/ Terminal test<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code># \ud68c\uc6d0\uac00\uc785 \/ Signup\ncurl -X POST https:\/\/aloy-horizon.duckdns.org\/api\/auth\/signup \\\n  -H \"Content-Type: application\/json\" \\\n  -d '{\"username\":\"test1\",\"email\":\"test1@test.com\",\"password\":\"123456\",\"display_name\":\"Test1\"}'\n\n# Database\nsqlite&gt; select username from users;\ntest1\nuser1\nuser2\nsqlite&gt; <\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f \uc6f9\uc0ac\uc774\ud2b8 \ub85c\uadf8\uc778 \/ Website login<\/p>\n\n\n\n<p>&#8212; https:\/\/aloy-horizon.duckdns.org\/auth\/login<\/p>\n\n\n\n<p>1)pinafore\uc5d0\uc11c \ub85c\uadf8\uc778 \ud560\uacbd\uc6b0<br>When logging in on Pinafore<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"500\" height=\"727\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp39-login2-jpg.jpg\" alt=\"\" class=\"wp-image-10198\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp39-login2-jpg.jpg 500w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp39-login2-jpg-206x300.jpg 206w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp39-login2-jpg-400x582.jpg 400w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><figcaption class=\"wp-element-caption\">pinafore login<\/figcaption><\/figure>\n\n\n\n<p>2)\uc6f9\uc0ac\uc774\ud2b8\uc5d0\uc11c \ub85c\uadf8\uc778 \ud560\uacbd\uc6b0<br>When logging in on the website<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"500\" height=\"540\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp39-login-jpg.jpg\" alt=\"\" class=\"wp-image-10197\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp39-login-jpg.jpg 500w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp39-login-jpg-278x300.jpg 278w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp39-login-jpg-400x432.jpg 400w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><figcaption class=\"wp-element-caption\">website login<\/figcaption><\/figure>\n\n\n\n<p>\u2714\ufe0f \ub85c\uadf8\uc544\uc6c3 \/ Logout<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"500\" height=\"400\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp39-logout-jpg.jpg\" alt=\"\" class=\"wp-image-10203\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp39-logout-jpg.jpg 500w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp39-logout-jpg-300x240.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp39-logout-jpg-400x320.jpg 400w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><figcaption class=\"wp-element-caption\">Logout<\/figcaption><\/figure>\n\n\n\n<p>\u2714\ufe0f \uc6f9 \ud68c\uc6d0\uac00\uc785 \/ Website Signup<\/p>\n\n\n\n<p>&#8212; https:\/\/aloy-horizon.duckdns.org\/auth\/signup<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"500\" height=\"576\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp39-signup-jpg.png\" alt=\"\" class=\"wp-image-10202\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp39-signup-jpg.png 500w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp39-signup-jpg-260x300.png 260w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp39-signup-jpg-400x461.png 400w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/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","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 myapp39\uc5d0\uc11c\ub294 \uc774\uc804\uc5d0 \uc644\ub8cc\ub418\uc9c0 \uc54a\uc558\ub358 \ub85c\uadf8\uc778 \uae30\ub2a5\uc744 \uc644\uc131\ud569\ub2c8\ub2e4.In myapp39, we complete the login functionality that was not finished previously. \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 code on GitHub. https:\/\/github.com\/gideonslife01\/flm-nextjs \ud83d\udcc1 \uc804\uccb4 \ud504\ub85c\uc81d\ud2b8 \uad6c\uc870 \/ Overall Project [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[28,27,1,7],"tags":[],"class_list":["post-10141","post","type-post","status-publish","format-standard","hentry","category-news","category-nextjs","category-uncategorized","category-website","missing-thumbnail"],"_links":{"self":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/10141","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=10141"}],"version-history":[{"count":46,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/10141\/revisions"}],"predecessor-version":[{"id":10204,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/10141\/revisions\/10204"}],"wp:attachment":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=10141"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=10141"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=10141"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}