{"id":8961,"date":"2026-08-29T08:53:56","date_gmt":"2026-08-28T23:53:56","guid":{"rendered":"https:\/\/www.freelifemakers.org\/wordpress\/?p=8961"},"modified":"2026-08-29T12:56:17","modified_gmt":"2026-08-29T03:56:17","slug":"nextjs-sns-server-16","status":"publish","type":"post","link":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2026\/08\/29\/nextjs-sns-server-16\/","title":{"rendered":"[nextjs]SNS Server-16(myapp26)"},"content":{"rendered":"\n<p>\ud83d\udc49\ud83c\udffb myapp26\uc5d0\ub294 \uc2a4\ud0a8\uae30\ub2a5\uc744 \uad6c\ud604\ud569\ub2c8\ub2e4.<br>Skin functionality is implemented in myapp26.<\/p>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb \ucf54\ub4dc \uc591\uc774 \ub9ce\uc544\uc11c \uc8fc\uc694 \ubd80\ubd84\ub9cc \uc124\uba85\ud569\ub2c8\ub2e4 .<br>Due to the large volume of code, I will explain only the key parts.<\/p>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb \uc804\uccb4\ucf54\ub4dc\ub294 \uae43\ud5c8\ube0c \ucf54\ub4dc\ub97c \ucc38\uc870\ud558\uc138\uc694<br>Please refer to the GitHub repository for the full code.<\/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>myapp26\/  \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 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 <strong>page.tsx <\/strong>              -&gt; Timeline UI\n\u2502   \u2502   \u2514\u2500\u2500 <strong>_components\/themes\/<\/strong>\n\u2502   \u2502       \u251c\u2500\u2500 <strong>pinafore\/Pinaforetheme.tsx  -&gt; Theme 1<\/strong>\n\u2502   \u2502       \u251c\u2500\u2500 <strong>mastodon\/Mastodontheme.tsx  -&gt; Theme 2<\/strong>\n\u2502   \u2502       \u2514\u2500\u2500 <strong>minimal\/Minimaltheme.tsx    -&gt; Theme 3<\/strong>\n\u2502   \u251c\u2500\u2500 <strong>layout.tsx<\/strong>, page.tsx, globals.css\n\u2502   \u2514\u2500\u2500 favicon.ico\n\u251c\u2500\u2500 lib\/\n\u2502   \u251c\u2500\u2500 <strong>theme.tsx              -&gt; Theme Provider<\/strong>\n\u2502   \u251c\u2500\u2500 ap.ts                  -&gt; Follow Accept\n\u2502   \u2514\u2500\u2500 db.ts                  -&gt; DB connection\n\u251c\u2500\u2500 data\/\n\u2502   \u2514\u2500\u2500 keys\/                  -&gt; private.pem, public.pem\n\u251c\u2500\u2500 data.sqlite                -&gt; Database\n\u251c\u2500\u2500 Caddyfile                  -&gt; https \n\u2514\u2500\u2500 package.json<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 \ud504\ub85c\uc81d\ud2b8 \uc2dc\uc791(myapp26)<br>Project Start (myapp26)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npx create-next-app@latest<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 SQLite\uc124\uce58 \/ Installing SQLite<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cd ~\/myapp26\nnpm install better-sqlite3\nnpm install -D @types\/better-sqlite3<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 DDNS,https\uc124\uc815 \/ DDNS,https settings<\/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=\"mE2JZQjFvG\"><a href=\"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2026\/08\/10\/nextjs-dns-caddy\/\">[nextjs]nextjs+domain(ddns)+https(caddy)<\/a><\/blockquote><iframe loading=\"lazy\" class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; visibility: hidden;\" title=\"&#8220;[nextjs]nextjs+domain(ddns)+https(caddy)&#8221; &#8212; freelifemakers.org\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2026\/08\/10\/nextjs-dns-caddy\/embed\/#?secret=SHTrecIPTI#?secret=mE2JZQjFvG\" data-secret=\"mE2JZQjFvG\" width=\"560\" height=\"315\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe>\n<\/div><\/figure>\n\n\n\n<p>\ud83d\udcc1 \ub3c4\uba54\uc778\ud5c8\uc6a9, @userid \uc0ac\uc6a9\ud558\uae30<br>Allowing domains, using @userid<\/p>\n\n\n\n<p>&#8212; next.config.ts<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import type { NextConfig } from \"next\";\n\nconst nextConfig: NextConfig = {\n  \/* allow domain*\/\n  allowedDevOrigins: &#91;'aloy-horizon.duckdns.org', '*.duckdns.org'],\n\n  \/* host.domain.org\/@userid *\/\n<strong>  async rewrites() {\n    return &#91;\n      {\n        source: '\/@:username',\n        destination: '\/usersui\/:username',\n      },\n    ]\n  }<\/strong>\n};\n\n\nexport default nextConfig;\n<\/code><\/pre>\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 myapp26\/lib\/theme.tsx\ud30c\uc77c\uc744 \ubd88\ub7ec\uc640 \ucee8\ud14d\uc2a4\ud2b8 \ud504\ub85c\ubc14\uc774\ub354\ub97c \uc801\uc6a9\ud569\ub2c8\ub2e4.<br>Import the <code>myapp26\/lib\/theme.tsx<\/code> file and apply the context provider.<\/p>\n\n\n\n<p>\ud83d\udca1 \ucee8\ud14d\uc2a4\ud2b8 \ud504\ub85c\ubc14\uc774\ub354\ub294 \ud558\ub098\uc758 \uc774\ubca4\ud2b8\ub85c \uc804\uccb4 \uc0c1\ud0dc\ub97c \ubcc0\uacbd\ud558\ub294 \uae30\ub2a5\uc73c\ub85c \ud14c\ub9c8\uc801\uc6a9\uc774\ub098 \uc5b8\uc5b4 \uc801\uc6a9 \uc124\uc815\uc5d0 \ub9ce\uc774 \uc0ac\uc6a9\ub429\ub2c8\ub2e4.<br>A Context Provider is a feature that allows the entire state to be updated via a single event; it is commonly used for settings such as applying themes or languages.<\/p>\n\n\n\n<p>&#8212; myapp26\/app\/usersui\/[username]\/Layout.tsx<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>import { ThemeProvider } from \"@\/lib\/theme\";<\/strong> \/\/ \u2705 myapp26\n\n... ...\n\nexport default function RootLayout({ children }: LayoutProps&lt;\"\/\"&gt;) {\n  return (\n    &lt;html\n      lang=\"en\"\n      className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}\n    &gt;\n      &lt;body className=\"min-h-full flex flex-col\"&gt;\n        {\/* \u2705 myapp26 - Add ThemeProvide *\/}\n        <strong>&lt;ThemeProvider&gt;<\/strong>\n          {children}\n        <strong>&lt;\/ThemeProvider&gt;<\/strong>\n      &lt;\/body&gt;\n    &lt;\/html&gt;\n  );\n}<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f \uc5ec\uae30\uc11c \ud14c\ub9c8\ud30c\uc77c\uc744 \ubd88\ub7ec\uc624\uace0 \ud14c\ub9c8(\uc2a4\ud0a8)\uc744\uc801\uc6a9\ud569\ub2c8\ub2e4.<br>Here, you load the theme file and apply the theme (skin).<\/p>\n\n\n\n<p>&#8212; myapp26\/app\/paget.tsx<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>... ...\nimport { PinaforeTheme } from '.\/_components\/themes\/pinafore\/Pinaforetheme';\nimport { MastodonTheme } from '.\/_components\/themes\/mastodon\/Mastodontheme';\nimport { MinimalTheme } from '.\/_components\/themes\/minimal\/Minimaltheme';\n... ...\n\n  \/\/ \u2705 timeline fetch\n  useEffect(() =&gt; {\n    params.then(p =&gt; {\n      setUsername(p.username);\n      fetch(`\/api\/timeline?username=${p.username}`)\n        .then(r =&gt; r.json())\n        .then(data =&gt; {\n          setTimeline(data);\n          setLoading(false);\n        });\n    });\n  }, &#91;params]);\n... ...\n  if (loading) return &lt;div style={{ padding: 20 }}&gt;Loading...&lt;\/div&gt;;\n\n  \/\/ \u2705 theme \ubd84\uae30 + props \uc804\ub2ec \/ Theme branching + props passing\n  const props = { timeline, username, onBoost: handleBoost, onLike: handleLike };\n\n  \/\/ apply theme\n  if (theme === 'pinafore') return &lt;PinaforeTheme {...props} \/&gt;\n  if (theme === 'mastodon') return &lt;MastodonTheme {...props} \/&gt;\n  if (theme === 'minimal') return &lt;MinimalTheme {...props} \/&gt;\n  \n  return &lt;PinaforeTheme {...props} \/&gt;;<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 \ub514\ub809\ud1a0\ub9ac \ubc0f \ud30c\uc77c \ucd94\uac00 \/ Add directories and files<\/p>\n\n\n\n<p>\u2714\ufe0f \ud0c0\uc784\ub77c\uc778 \uc2a4\ud0a8(\ud14c\ub9c8) UI \/ Timeline Skin (Theme) UI<\/p>\n\n\n\n<p>&#8212; \uc544\ub798\uc758 \ud30c\uc77c\uc740 \ubaa8\ub450 \ud14c\ub9c8 \ub514\uc790\uc778\uc73c\ub85c \uc88b\uc544\uc694,\ubd80\uc2a4\ud2b8\uae30\ub2a5\uc740 \ube60\uc838\uc788\uc2b5\ub2c8\ub2e4.<br>The files below are all theme designs; the boost function is not included.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>myapp26\/app\/usersui\/&#91;username]\/_components\/themes\/pinafore\/Pinaforetheme.tsx\n\nmyapp26\/app\/usersui\/&#91;username]\/_components\/themes\/mastodon\/Mastodontheme.tsx\n\nmyapp26\/app\/usersui\/&#91;username]\/_components\/themes\/minimal\/Minimaltheme.tsx<\/code><\/pre>\n\n\n\n<p>&#8212; \uc138 \ud30c\uc77c \ubaa8\ub450 \ub3d9\uc77c\ud558\uba70 \ud14c\ub9c8\uc758 \uad6c\ubd84\uc774 \uac00\ub2a5\ud558\uac8c  \ud14c\ub9c8 \uc774\ub984\ub9cc \ud45c\uc2dc\uc92c\uc2b5\ub2c8\ub2e4. <br>All three files are identical; only the theme names are displayed to distinguish between them.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;h2&gt;\ud83d\udc18 {username}\/ <strong>Pinafore<\/strong>&lt;\/h2&gt; {\/* \ud14c\ub9c8\uc774\ub984 \/ Theme Name *\/}<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"529\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-skim-pinafore-jpg.jpg\" alt=\"\" class=\"wp-image-9013\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-skim-pinafore-jpg.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-skim-pinafore-jpg-300x198.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-skim-pinafore-jpg-768x508.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-skim-pinafore-jpg-400x265.jpg 400w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">Pinafore theme<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"497\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-skin-mastodon-jpg.jpg\" alt=\"\" class=\"wp-image-9016\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-skin-mastodon-jpg.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-skin-mastodon-jpg-300x186.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-skin-mastodon-jpg-768x477.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-skin-mastodon-jpg-400x249.jpg 400w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">Mastodon theme<\/figcaption><\/figure>\n\n\n\n<p>&#8212; \ud14c\ub9c8 \ubcc0\uc218\uc758 \uac12\uc774 \ubcc0\ud558\uba74 \ucee8\ud14d\uc2a4\ud2b8 \ud504\ub85c\ubc14\uc774\ub354\uc5d0\uc11c \ub85c\uceec \uc2a4\ud1a0\ub9ac\uc9c0\uc758 \uac12\uc744 \ubcc0\uacbd\ud569\ub2c8\ub2e4.<br>When the value of the theme variable changes, the context provider updates the value in local storage.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>... ...\nconst &#91;theme, <strong>setTheme<\/strong>] = useState&lt;ThemeName&gt;('pinafore');\n... ...         \n&lt;select \n            value={theme} \/\/  \ud604\uc7ac \ub85c\uceec\uc2a4\ud1a0\ub9ac\uc9c0 \uac12 \ud45c\uc2dc \/ Display current local storage value\n            onChange={(e) =&gt; {\n            <strong>setTheme(e.target.value as any); <\/strong>\n         }}&gt;\n            &lt;option value=\"pinafore\"&gt;Pinafore&lt;\/option&gt;\n            &lt;option value=\"mastodon\"&gt;Mastodon&lt;\/option&gt;\n            &lt;option value=\"minimal\"&gt;Minimal&lt;\/option&gt;\n          &lt;\/select&gt;<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"656\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-skin-minimal-jpg-1024x656.jpg\" alt=\"\" class=\"wp-image-9007\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-skin-minimal-jpg-1024x656.jpg 1024w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-skin-minimal-jpg-300x192.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-skin-minimal-jpg-768x492.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-skin-minimal-jpg-1536x984.jpg 1536w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-skin-minimal-jpg-400x256.jpg 400w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-skin-minimal-jpg-800x512.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-skin-minimal-jpg.jpg 1680w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Minimal<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"576\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-minimal-localstorage-jpg.jpg\" alt=\"\" class=\"wp-image-9018\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-minimal-localstorage-jpg.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-minimal-localstorage-jpg-300x216.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-minimal-localstorage-jpg-768x553.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp26-minimal-localstorage-jpg-400x288.jpg 400w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">Browser Local storage<\/figcaption><\/figure>\n\n\n\n<p>\u2714\ufe0f \ucee8\ud14d\uc2a4\ud2b8 \ud504\ub85c\ubc14\uc774\ub354 \/ Context Provider<\/p>\n\n\n\n<p>&#8212; myapp26\/lib\/theme.tsx<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>... ...\n  useEffect(() =&gt; {\n    const saved = <strong>localStorage.getItem('theme') as ThemeName;<\/strong>\n    if (saved) setTheme(saved);\n  }, &#91;]);\n... ...  \n\nreturn (\n    &lt;ThemeContext.Provider value={{ <strong>theme, setTheme: updateTheme<\/strong> }}&gt;\n      &lt;div data-theme={<strong>theme<\/strong>} style={{ minHeight: '100%', display: 'flex', flexDirection: 'column', flex: 1 }}&gt;\n        {children}\n      &lt;\/div&gt;\n    &lt;\/ThemeContext.Provider&gt;\n  );\n<\/code><\/pre>\n\n\n\n<p>1)\ucee8\ud14d\uc2a4\ud2b8 \ud504\ub85c\ubc14\uc774\ub354\uc5d0 theme\ubcc0\uc218\ub97c \ud30c\ub77c\uba54\ud130\ub85c \uc801\uc6a9\ud569\ub2c8\ub2e4.<br>Apply the <code>theme<\/code> variable as a parameter to the context provider.<\/p>\n\n\n\n<p>2)theme \uac12\uc774 \ubcc0\uacbd\ub418\uba74 \ub2e4\ub978 \ud14c\ub9c8\ud30c\uc77c\uc744 \ubd88\ub7ec\uc624\uae30 \uc704\ud574\uc11c \uc0ac\uc6a9\ub429\ub2c8\ub2e4.<br>It is used to load a different theme file when the <code>theme<\/code> value changes.<\/p>\n\n\n\n<p>3)\ud14c\ub9c8\uc774\ub984\uc740 \ube0c\ub77c\uc6b0\uc800\uc758 \ub85c\uceec \uc2a4\ud1a0\ub9ac\uc9c0\uc5d0 \uc800\uc7a5\ub429\ub2c8\ub2e4.<br>The theme name is stored in the browser&#8217;s local storage.<\/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 myapp26\uc5d0\ub294 \uc2a4\ud0a8\uae30\ub2a5\uc744 \uad6c\ud604\ud569\ub2c8\ub2e4.Skin functionality is implemented in myapp26. \ud83d\udc49\ud83c\udffb \ucf54\ub4dc \uc591\uc774 \ub9ce\uc544\uc11c \uc8fc\uc694 \ubd80\ubd84\ub9cc \uc124\uba85\ud569\ub2c8\ub2e4 .Due to the large volume of code, I will explain only the key parts. \ud83d\udc49\ud83c\udffb \uc804\uccb4\ucf54\ub4dc\ub294 \uae43\ud5c8\ube0c \ucf54\ub4dc\ub97c \ucc38\uc870\ud558\uc138\uc694Please refer to the GitHub repository for the full code. https:\/\/github.com\/gideonslife01\/flm-nextjs \ud83d\udcc1 \uc804\uccb4 \ud504\ub85c\uc81d\ud2b8 \uad6c\uc870 \/ Overall Project Structure \ud83d\udcc1 \ud504\ub85c\uc81d\ud2b8 [&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-8961","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\/8961","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=8961"}],"version-history":[{"count":52,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/8961\/revisions"}],"predecessor-version":[{"id":9020,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/8961\/revisions\/9020"}],"wp:attachment":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=8961"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=8961"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=8961"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}