{"id":10439,"date":"2026-09-19T09:23:30","date_gmt":"2026-09-19T00:23:30","guid":{"rendered":"https:\/\/www.freelifemakers.org\/wordpress\/?p=10439"},"modified":"2026-09-19T13:41:07","modified_gmt":"2026-09-19T04:41:07","slug":"nextjs-sns-server-33","status":"publish","type":"post","link":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2026\/09\/19\/nextjs-sns-server-33\/","title":{"rendered":"[nextjs]SNS Server-33(myapp43)\u00a0"},"content":{"rendered":"\n<p>\ud83d\udc49\ud83c\udffb myapp43\uc5d0\uc11c\ub294 \ud14c\ub9c8\ud30c\uc77c\uc5d0\uc11c \ud314\ub85c\uc6b0,\ud314\ub85c\uc6cc\ubaa9\ub85d\uc744 \ud638\ucd9c\ud558\ub294 \ubc29\uc2dd\uc73c\ub85c \uc804\ud658\ud569\ub2c8\ub2e4.<br>In myapp43, we are switching to a method that calls the lists of people being followed and followers directly from the theme files.<\/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 <strong>api\/followinglist\/route.ts  -&gt; followinglist API<\/strong>\n\u2502   \u251c\u2500\u2500 <strong>api\/followerslist\/route.ts  -&gt; followerslist API<\/strong>\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\/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\/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 <strong>pinafore\/FollowersList.tsx -&gt; Theme 1,FollowersList<\/strong>\n\u2502   \u2502       \u251c\u2500\u2500 <strong>pinafore\/FollowingList.tsx -&gt; Theme 1,FollowingList<\/strong>\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=\"XoqTGR8Kw6\"><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=PgyNPgNDdG#?secret=XoqTGR8Kw6\" data-secret=\"XoqTGR8Kw6\" 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 \uad6c\uc870 \ubcc0\uacbd \uc124\uba85 \/ Explanation of Structural Changes<\/p>\n\n\n\n<p>\u2714\ufe0f \ud604\uc7ac \ubc29\uc2dd\uc740 \ud314\ub85c\uc6cc,\ud314\ub85c\uc6b0\ub97c \ud074\ub9ad\ud558\uba74 \uc0c8\ub85c\uc6b4 \ud398\uc774\uc9c0\ub85c \ud314\ub85c\uc6cc,\ud314\ub85c\uc6b0 \ub9ac\uc2a4\ud2b8\uac00 \ud45c\uc2dc\ub429\ub2c8\ub2e4.<br>In the current method, clicking on &#8220;Followers&#8221; or &#8220;Following&#8221; displays the respective list on a new page.<\/p>\n\n\n\n<p>\u2714\ufe0f \uc9c0\uae08 \uc774 \uc571\uc5d0 \uc788\ub294 \uc5d1\ud2f0\ube0c \ud14c\ub9c8\uae30\ub2a5\uc744 \ud65c\uc6a9\ud558\ub824\uba74 \ud14c\ub9c8\ud398\uc774\uc9c0\uc5d0\uc11c  \ud314\ub85c\uc6cc,\ud314\ub85c\uc6b0 \ub9ac\uc2a4\ud2b8\ub97c \ud638\ucd9c\ud558\ub294\uac8c \ud6a8\uc728\uc801\uc785\ub2c8\ub2e4.<br>To utilize the active theme feature currently in this app, it is efficient to call up the follower and following lists from the theme page.<\/p>\n\n\n\n<p>\u2714\ufe0f \uadf8\ub7ec\uba74 \ud558\ub098\uc758 \ud398\uc774\uc9c0\uc5d0\uc11c \ud074\ub9ad\uc73c\ub85c,\ud0c0\uc784\ub77c\uc778,\ud314\ub85c\uc6b0 \ubc0f \ud314\ub85c\uc6cc \ub9ac\uc2a4\ud2b8\ub97c \ucef4\ud3ec\ub10c\ud2b8 \ud615\uc2dd\uc73c\ub85c \ubcc0\uacbd\ud558\ubbc0\ub85c \ud14c\ub9c8\ubcc4\ub85c \ub514\uc790\uc778 \uc77c\uad00\uc131\uc744 \uc720\uc9c0 \ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<br>This allows you to switch between the timeline and the lists of people you follow and your followers as components with a single click on the same page, thereby maintaining design consistency across themes.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># \uae30\uc874 \ub77c\uc6b0\ud2b8 -&gt; \uc0ad\uc81c \/ Existing route -&gt; Delete\napp\/usersui\/&#91;username]\/followers\/ \napp\/usersui\/&#91;username]\/following\/ \n\n# \uc2e0\uaddc \ub77c\uc6b0\ud2b8 \/ New Route\napp\/api\/followlist\/route.ts\napp\/api\/followinglist\/route.ts <\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 \ucf54\ub4dc\uc218\uc815 \ubc0f \ub77c\uc6b0\ud2b8 \ucd94\uac00 \/ Code Modification and<\/p>\n\n\n\n<p>\u2714\ufe0f app\/api\/followinglist\/route.ts -&gt; \ub77c\uc6b0\ud2b8 \ucd94\uac00 \/ Add route<\/p>\n\n\n\n<p>&#8212; API<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\nexport async function GET(req: Request) {\n  const data = rows.map(r =&gt; {\n... ...\n\n      \/\/ \u2705 \ub3c4\uba54\uc778\uc774 \ub0b4 \ub3c4\uba54\uc778\uc77c \ub54c\ub9cc \ub85c\uceec DB \uc870\ud68c!\n      \/\/ Query the local DB only when the domain matches mine!\n      const isLocalDomain = hostname === DOMAIN || hostname === 'localhost' || hostname.endsWith(`.${DOMAIN}`);\n\n      let info = null;\n      if (isLocalDomain &amp;&amp; remoteName) {\n        info = db.prepare('SELECT username, display_name FROM users WHERE username=?').get(remoteName) as any;\n      }\n\n      const isLocalUser = isLocalDomain &amp;&amp;!!info;\n\n      return {\n        username: remoteName || r.actor,\n        display_name: info?.display_name || remoteName || 'remote',\n        acct: isLocalUser\n         ? `${remoteName}@${DOMAIN}` \/\/ \u2705 \uc9c4\uc9dc \ub85c\uceec\uc77c \ub54c\ub9cc aloy\n          : `${remoteName}@${hostname}`, \/\/ \u2705 freelifemakers.com\uc774\uba74 freelifemakers@freelifemakers.com\n        actor: r.actor,\n        domain: hostname,\n      };\n    } catch {\n      return { acct: r.actor, actor: r.actor, username: r.actor };\n    }\n  });\n  }\n}<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f app\/api\/followerslist\/route.ts -&gt; \ub77c\uc6b0\ud2b8 \ucd94\uac00 \/ Add route<\/p>\n\n\n\n<p>&#8212; API<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>followinglist\/route.ts\uc640 \ud14c\uc774\ube14\uc774\ub984\ub9cc \ub2e4\ub984 \uc804\uccb4 \ucf54\ub4dc \ub3d9\uc77c\ud568.\nIt differs from followinglist\/route.ts only in the table name; the rest of the code is identical.<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f app\/usersuui\/[username]\/_components\/theme\/pinafore\/FollowersList.tsx -&gt; \ud398\uc774\uc9c0 \ucd94\uac00 \/ Add page<\/p>\n\n\n\n<p>&#8212; UI(\ud14c\ub9c8\uc5d0\ud3ec\ud568 \/ Included in the theme)<\/p>\n\n\n\n<p>&#8212; API\uc815\ubcf4 \ubc1b\uc544\uc640\uc11c return\ubd80\ubd84\uc758 HTML\uc5d0 \ucd9c\ub825<br>Fetch the API data and output it to the HTML in the return section.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>\/\/ \u2705 app\/usersui\/&#91;username]\/_components\/theme\/pinafore\/FollowersList.tsx\n\n'use client';\nimport { useEffect, useState } from 'react';\n\nexport default function FollowersList({ username, style }: { username: string, style?: any }) {\n  const &#91;users, setUsers] = useState&lt;any&#91;]&gt;(&#91;]);\n  const &#91;loading, setLoading] = useState(true);\n\n  useEffect(() =&gt; {\n    \/\/ \u2705 \/api\/followerslist\/route.ts \ud638\ucd9c!\n    \/\/ Calling \/api\/followerslist\/route.ts \n    fetch(`\/api\/followerslist?username=${username}`)\n     .then(r =&gt; r.json())\n     .then(d =&gt; { setUsers(Array.isArray(d)? d : d.accounts || &#91;]); setLoading(false); })\n     .catch(() =&gt; setLoading(false));\n  }, &#91;username]);\n\n  if (loading) return &lt;div style={{ padding: 20, textAlign: 'center' }}&gt;Loading...&lt;\/div&gt;;\n\n  return (\n    &lt;div style={style}&gt;\n      {users.map((u, i) =&gt; (\n        &lt;div key={i} style={{ display: 'flex', gap: 12, padding: '12px 16px', borderBottom: '1px solid #eee' }}&gt;\n          &lt;div style={{ width: 46, height: 46, borderRadius: '50%', background: '#6364ff', color: 'white', display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: 800 }}&gt;\n            {(u.display_name || u.username || '?')&#91;0].toUpperCase()}\n          &lt;\/div&gt;\n          &lt;div&gt;\n            &lt;div style={{ fontWeight: 700 }}&gt;{u.display_name || u.username}&lt;\/div&gt;\n            &lt;div style={{ fontSize: 13, color: '#657786' }}&gt;{u.acct || u.actor}&lt;\/div&gt;\n          &lt;\/div&gt;\n        &lt;\/div&gt;\n      ))}\n      {users.length === 0 &amp;&amp; &lt;div style={{ padding: 40, textAlign: 'center', color: '#999' }}&gt;\ud314\ub85c\uc6cc \uc5c6\uc74c \/ No followers&lt;\/div&gt;}\n    &lt;\/div&gt;\n  );\n}<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f app\/usersuui\/[username]\/_components\/theme\/pinafore\/FollowingList.tsx -&gt; \ud398\uc774\uc9c0 \ucd94\uac00 \/ Add page<\/p>\n\n\n\n<p>&#8212; UI(\ud14c\ub9c8\uc5d0\ud3ec\ud568 \/ Included in the theme)<\/p>\n\n\n\n<p>&#8212; API\uc815\ubcf4 \ubc1b\uc544\uc640\uc11c return\ubd80\ubd84\uc758 HTML\uc5d0 \ucd9c\ub825<br>Fetch the API data and output it to the HTML in the return section.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>\ucf54\ub4dc \ub3d9\uc77c\ud558\uace0 FollowerList.tsx\ubd80\ubd84\uc758 \ub370\uc774\ud130\ubca0\uc774\uc2a4 \ud14c\uc774\ube14\uba85\ub9cc \ub2e4\ub984(following)\nThe code is identical, except for the database table name in `FollowerList.tsx` (which is `following`).<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f app\/usersuui\/[username]\/_components\/theme\/pinafore\/PinaforeTheme.tsx -&gt; \ucf54\ub4dc\uc218\uc815\/ Code Modification<\/p>\n\n\n\n<p>&#8212; \ubc84\ud2bc \ud074\ub9ad\uc2dc \ud0c0\uc784\ub77c\uc778 \uc601\uc5ed\ubd80\ubd84\uc5d0 view\uc758 \uac12\uc5d0 \ub530\ub77c\uc11c \ub2e4\ub978 \ucef4\ud3ec\ub10c\ud2b8\ub97c \ubc30\uce58\ud569\ub2c8\ub2e4.<br>When the button is clicked, a different component is placed in the timeline area based on the <code>view<\/code> value.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\nexport function PinaforeTheme({ timeline, username, onBoost, onLike }: any) {\n... ...\n  \/\/ \u2705 myapp43 -  \ub9c1\ud06c \uad00\uc810: \ud398\uc774\uc9c0 \uc774\ub3d9 \uc5c6\uc774 \uc2ac\ub86f\ub9cc \uad50\uccb4! \/ Link Perspective: Swap only the slot without navigating to a new page!\n  const switchView = (e: React.MouseEvent, v: typeof view) =&gt; {\n    e.preventDefault();\n    setView(v);\n    const url = v === 'timeline'? `\/@${username}` : `\/@${username}\/${v}`;\n    window.history.pushState({}, '', url);\n  };\n\n  return (\n... ...\n              &lt;div className=\"profile-stats\"&gt;\n\n                &lt;a href={`\/@${username}\/following`} onClick={(e) =&gt; switchView(e, 'following')}&gt;\n                  &lt;b&gt;{counts.following}&lt;\/b&gt; &lt;span&gt;\ud314\ub85c\uc789\/Followng&lt;\/span&gt;\n                &lt;\/a&gt;\n                &lt;a href={`\/@${username}\/followers`} onClick={(e) =&gt; switchView(e, 'followers')}&gt;\n                  &lt;b&gt;{counts.followers}&lt;\/b&gt; &lt;span&gt;\ud314\ub85c\uc6cc\/Follower&lt;\/span&gt;\n                &lt;\/a&gt;\n                &lt;a href={`\/@${username}`} onClick={(e) =&gt; switchView(e, 'timeline')}&gt;\n                  &lt;b&gt;{counts.posts}&lt;\/b&gt; &lt;span&gt;\uac8c\uc2dc\ubb3c\/Toots&lt;\/span&gt;\n                &lt;\/a&gt;\n              &lt;\/div&gt;\n    ... ...\n          {view === 'timeline' &amp;&amp; (\n            &lt;&gt;\n            {timeline.length === 0 &amp;&amp; (\n              &lt;div style={{ padding: 20, color: '#999' }}&gt;\ud0c0\uc784\ub77c\uc778\uc774 \ube44\uc5b4\uc788\uc2b5\ub2c8\ub2e4 \/ No posts&lt;\/div&gt;\n            )}\n            {timeline.map((p: any) =&gt; (\n        \n              &lt;article key={`${p.source}-${p.id}`} className=\"pinafore-status\"&gt;\n               ... ...\n              &lt;\/article&gt;\n\n            ))}\n            &lt;\/&gt;\n          )}\n          {view === 'followers' &amp;&amp; (\n            &lt;FollowersList username={username} style={{ padding: '0' }} \/&gt;\n          )}\n\n          {view === 'following' &amp;&amp; (\n            &lt;FollowingList username={username} style={{ padding: '0' }} \/&gt;\n          )}\n  );\n}<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f lib\/watchThemes -&gt; \ucf54\ub4dc\uc218\uc815 \/ Code Modification<\/p>\n\n\n\n<p>&#8212; watchThemes\ub294 \ud30c\uc77c\uc774\ub098 \ub514\ub809\ud1a0\ub9ac\ubcc0\uacbd\uc774 \uc788\ub294\uc9c0 \ud655\uc778\ud574\uc11c \uac31\uc2e0\ub41c \ud14c\ub9c8\ub97c \ubd88\ub7ec\uc62c index.ts\ud30c\uc77c\uc744 \uc0dd\uc131\ud569\ub2c8\ub2e4.<br>watchThemes monitors for changes to files or directories and generates an <code>index.ts<\/code> file to load the updated themes.<\/p>\n\n\n\n<p>&#8212; \ud14c\ub9c8 \ub514\ub809\ud1a0\ub9ac\uc5d0 \uc0c8\ub85c \ucd94\uac00\ub41c followerlist.tsx,followinglist.tsx \ud30c\uc77c\uc744 index.ts\uc5d0 \ud3ec\ud568\uc2dc\ud0a4\uac8c \ub429\ub2c8\ub2e4.<br>The newly added <code>followerlist.tsx<\/code> and <code>followinglist.tsx<\/code> files in the theme directory will be included in <code>index.ts<\/code>.<\/p>\n\n\n\n<p>&#8212; \uadf8\ub798\uc11c followerslist.tsx, followinglist.tsx \ud30c\uc77c\uc744 \ud14c\ub9c8 \ud30c\uc77c\uc5d0\uc11c \uc81c\uc678 \uc2dc\ud0a4\ub294 \ucf54\ub4dc\ub97c \ucd94\uac00\ud569\ub2c8\ub2e4.<br>So, I am adding code to exclude the <code>followerslist.tsx<\/code> and <code>followinglist.tsx<\/code> files from the theme files.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\nexport function watchThemes() {\n... ...\n          \/\/ \u2705 myapp43 - followerlist,followinglist \ud30c\uc77c \uc2a4\ud0b5 \/ Skip followerlist and followinglist files.\n          files = files.filter(f =&gt;!f.toLowerCase().includes('list'));\n          if (!files.length) continue; \/\/ false -&gt; continue\n\n          \/\/ \u2705 myapp43 - PinaforeTheme.tsx \uac19\uc740 Theme \ud30c\uc77c \uc6b0\uc120 \uc815\ub82c\n          files.sort((a,b) =&gt; {\n            const aIsTheme = a.toLowerCase().includes('theme')? 0 : 1;\n            const bIsTheme = b.toLowerCase().includes('theme')? 0 : 1;\n            return aIsTheme - bIsTheme;\n          });\n... ...\n}<\/code><\/pre>\n\n\n\n<p>\ud83d\udca1 \ud30c\uc77c \uc815\ub82c \uacfc\uc815 \/ File sorting process<\/p>\n\n\n\n<p>&#8212; const fileName = files[0];\uc774 \ubd80\ubd84\uc774 \ud14c\ub9c8\ud30c\uc77c\uc774\ub984\uc73c\ub85c \uc0ac\uc6a9\ub429\ub2c8\ub2e4.<br>The part <code>const fileName = files[0];<\/code> is used as the theme file name.<\/p>\n\n\n\n<p>&#8211;\uadf8\ub798\uc11c \uc815\ub82c\uacfc\uc815\uc744 \ud1b5\ud574\uc11c \uc2e4\uc81c\ub85c \ubc30\uc5f4 0\ubc88\uc5d0 \ud14c\ub9c8\ud30c\uc77c \uc774\ub984\uc774 \uc14b\ud305\ub418\ub3c4\ub85d \ud569\ub2c8\ub2e4.<br>Therefore, through the sorting process, the theme file name is actually set at index 0 of the array.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>\/\/ \uc77d\uc5b4\uc628 \ud30c\uc77c \ubc30\uc5f4\nconst files = &#91;'FollowersList.tsx', 'PinaforeTheme.tsx', 'FollowingList.tsx']\n\n\/\/ sort\uac00 \ub0b4\ubd80\uc801\uc73c\ub85c \ud638\ucd9c\ud558\ub294 \uacfc\uc815\n\/\/ files.sort((a,b) =&gt; ...)\n\n1\ucc28 \ube44\uad50: a = 'FollowersList.tsx', b = 'PinaforeTheme.tsx'\n  -&gt; aIsTheme = 1, bIsTheme = 0\n  -&gt; 1 - 0 = 1 (\uc591\uc218) -&gt; b\uac00 \uc55e\uc73c\ub85c! \n  -&gt; &#91;'PinaforeTheme.tsx', 'FollowersList.tsx', 'FollowingList.tsx']\n\n2\ucc28 \ube44\uad50: a = 'FollowersList.tsx', b = 'FollowingList.tsx'\n  -&gt; aIsTheme = 1, bIsTheme = 1\n  -&gt; 1 - 1 = 0 -&gt; \uc21c\uc11c \uadf8\ub300\ub85c!\n\n\ucd5c\uc885: &#91;'PinaforeTheme.tsx', 'FollowersList.tsx', 'FollowingList.tsx']<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f next.config.ts<\/p>\n\n\n\n<p>&#8212; view\uc5d0 get \ubc29\uc2dd\uc73c\ub85c \uac12\uc744 \uc804\ub2ec\ud569\ub2c8\ub2e4.<br>Pass values \u200b\u200bto the view using the GET method.<\/p>\n\n\n\n<p>&#8212; \uc774 \uac12\uc740 sns\ud398\uc774\uc9c0\uc5d0\uc11c following \ub9ac\uc2a4\ud2b8\uc640 followers \ub9ac\uc2a4\ud2b8\ub97c \ubd88\ub7ec\uc624\ub294 \uc5ed\ud560\uc744 \ud569\ub2c8\ub2e4.<br>This value serves to retrieve the &#8220;following&#8221; and &#8220;followers&#8221; lists from the social media page.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>import type { NextConfig } from \"next\";\n\nconst nextConfig: NextConfig = {\n\n  \/* allow domain*\/\n  allowedDevOrigins: &#91;'aloy-horizon.duckdns.org', '*.duckdns.org'],\n\n  \/* host.domain.org\/@userid *\/\n  async rewrites() {\n    return &#91;\n      {\n        source: '\/@:username',\n        destination: '\/usersui\/:username',\n      },\n      {\n        source: '\/@:username\/following',\n        destination: '\/usersui\/:username?view=following', \/\/ \u2705 myapp43 - initialView\n      },\n      {\n        source: '\/@:username\/followers',\n        destination: '\/usersui\/:username?view=followers',\n      },\n    ]\n  },\n  \n};\n\nexport default nextConfig;\n<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f initialView <\/p>\n\n\n\n<p>&#8212; initialView\ub97c \uc14b\ud305\ud558\uc9c0 \uc54a\uc73c\uba74 next.config.ts\uc5d0\uc11c get\ubc29\uc2dd\uc73c\ub85c \uc804\ub2ec\ub418\ub294 view\uac12\uc744 \ubc1b\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.<br>If <code>initialView<\/code> is not set, you cannot receive the <code>view<\/code> value passed via the GET method in <code>next.config.ts<\/code>.<\/p>\n\n\n\n<p>&#8212; \uc774\ub7f0\uacbd\uc6b0 \ubc84\ud2bc \ud074\ub9ad\uc2dc\ub294 \uc815\uc0c1\uc801\uc73c\ub85c followers,following\ub9ac\uc2a4\ud2b8\ub97c \ubd88\ub7ec\uc624\uc9c0\ub9cc \ub77c\uc6b0\ud2b8\ub97c \uc7ac\uc2e4\ud589\ud558\uba74  \ud0c0\uc784\ub77c\uc778\uc744 \ubd88\ub7ec\uc624\uac8c \ub429\ub2c8\ub2e4.<br>In this case, clicking the button correctly loads the followers and following lists, but reloading the route causes the timeline to load instead.<\/p>\n\n\n\n<p>&#8212; \uadf8\ub798\uc11c \ubc84\ud2bc \ud074\ub9ad \ubfd0\uc544\ub2c8\ub77c \ub77c\uc6b0\ud2b8\uac00 \uc7ac\uc2e4\ud589\ub420 \ub54c\ub3c4 view\uac12\uc744 \uc804\ub2ec\ubc1b\uc544\uc11c followers,following \ub9ac\uc2a4\ud2b8\ub97c \uc81c\ub300\ub85c \ubd88\ub7ec\uc62c \uc218 \uc788\uc2b5\ub2c8\ub2e4.<br>This allows the <code>view<\/code> value to be passed not only when the button is clicked but also when the route is re-executed, ensuring the followers and following lists are loaded correctly.<\/p>\n\n\n\n<p>&#8212; \ubcc0\uc218\uc804\ub2ec \/ Variable passing : paget.tsx -&gt; ClientPage.tsx -&gt; pinafore\/PinaforeTheme.tsx<\/p>\n\n\n\n<p>&#8212; app\/usersui\/[username]\/page.tsx<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\ntype Props = {\n  params: Promise&lt;{ username: string }&gt;,\n  searchParams: Promise&lt;{ view?: string }&gt;\n};\nexport default async function Page({ params,searchParams }: Props) {\n... ...\nreturn &lt;ClientPage username={username} initialView={view} \/&gt;;\n}<\/code><\/pre>\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>... ...\nexport default function ClientPage({ username, <strong>initialView<\/strong>}: {username:String, initialView?:String}) {\n... ...\n  const props = { timeline, username, <strong>initialView<\/strong>,onBoost: handleBoost, onLike: handleLike };\n  \n  \/\/ getThemeComponent : import { themeRegistry, getThemeComponent } from '.\/_components\/themes'; --&gt; index.ts\n  const ActiveTheme = getThemeComponent(theme as any) || themeRegistry.pinafore?.component || themeRegistry&#91;themeNames&#91;0]]?.component;\n  if (!ActiveTheme) return &lt;div&gt;No themes found&lt;\/div&gt;;\n\n  return &lt;ActiveTheme {...props} \/&gt;;\n}<\/code><\/pre>\n\n\n\n<p>&#8212; app\/usersui\/[username]\/ClientPage.tsx<\/p>\n\n\n\n<p>\ud83d\udcc1 \uae30\uc874 \ub77c\uc6b0\ud2b8 \uc0ad\uc81c(\uc0ac\uc6a9\uc548\ud568.)<br>Delete existing route (unused).<\/p>\n\n\n\n<p>\u2714\ufe0f \uae30\uc874\uc758 \ud314\ub85c\uc6cc,\ud314\ub85c\uc6b0 \ub77c\uc6b0\ud2b8 \ubc0f \ud558\uc704 \ud30c\uc77c\uc744 \uc0ad\uc81c\ud569\ub2c8\ub2e4.<br>Delete the existing follower and following routes and sub-files.<\/p>\n\n\n\n<p>&#8212; app\/usersui\/[username]\/followers\/<\/p>\n\n\n\n<p>&#8212; app\/usersui\/[username]\/followiing\/<\/p>\n\n\n\n<p>\ud83d\udcc1 \ud14c\uc2a4\ud2b8 \/ Test<\/p>\n\n\n\n<p>\u2714\ufe0f \ud314\ub85c\uc789 \ub9ac\uc2a4\ud2b8 \/ following list<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"476\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp43-followinglist-jpg.jpg\" alt=\"\" class=\"wp-image-10498\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp43-followinglist-jpg.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp43-followinglist-jpg-300x179.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp43-followinglist-jpg-768x457.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp43-followinglist-jpg-400x238.jpg 400w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">Following LIst<\/figcaption><\/figure>\n\n\n\n<p>\u2714\ufe0f \ud314\ub85c\uc6cc \ub9ac\uc2a4\ud2b8 \/ followers list<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"468\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp43-followerslist-jpg.jpg\" alt=\"\" class=\"wp-image-10499\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp43-followerslist-jpg.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp43-followerslist-jpg-300x176.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp43-followerslist-jpg-768x449.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp43-followerslist-jpg-400x234.jpg 400w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">Followers List<\/figcaption><\/figure>\n\n\n\n<p>\u2714\ufe0f \ud0c0\uc784\ub77c\uc778 \/ Timeline<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"517\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp43-toots-jpg.jpg\" alt=\"\" class=\"wp-image-10501\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp43-toots-jpg.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp43-toots-jpg-300x194.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp43-toots-jpg-768x496.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/09\/myapp43-toots-jpg-400x259.jpg 400w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">Timeline<\/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 myapp43\uc5d0\uc11c\ub294 \ud14c\ub9c8\ud30c\uc77c\uc5d0\uc11c \ud314\ub85c\uc6b0,\ud314\ub85c\uc6cc\ubaa9\ub85d\uc744 \ud638\ucd9c\ud558\ub294 \ubc29\uc2dd\uc73c\ub85c \uc804\ud658\ud569\ub2c8\ub2e4.In myapp43, we are switching to a method that calls the lists of people being followed and followers directly from the theme files. \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 Structure \ud83d\udcc1 \ud504\ub85c\uc81d\ud2b8 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":10499,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[28,27,1,7],"tags":[],"class_list":["post-10439","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\/10439","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=10439"}],"version-history":[{"count":59,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/10439\/revisions"}],"predecessor-version":[{"id":10504,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/10439\/revisions\/10504"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media\/10499"}],"wp:attachment":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=10439"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=10439"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=10439"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}