{"id":12990,"date":"2026-10-27T10:21:56","date_gmt":"2026-10-27T01:21:56","guid":{"rendered":"https:\/\/www.freelifemakers.org\/wordpress\/?p=12990"},"modified":"2026-10-27T13:00:23","modified_gmt":"2026-10-27T04:00:23","slug":"nextjs-sns-server-51-10","status":"publish","type":"post","link":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2026\/10\/27\/nextjs-sns-server-51-10\/","title":{"rendered":"[nextjs]SNS Server-51(myapp61+)[\uc54c\ub9bc\/Notifications]\u00a0"},"content":{"rendered":"\n<p>\ud83d\udc49\ud83c\udffb \uc774\ubc88\uc5d0\ub294 \uc54c\ub9bc \uae30\ub2a5\uc5d0 \ub300\ud574\uc11c \uc0b4\ud3b4 \ubd05\ub2c8\ub2e4.<br>Next, we will take a look at the notification feature.<\/p>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb \uc774\uc804\uc5d0 \ud398\uc774\uc9c0\ub124\uc774\uc158\uc744 \uc704\ud574 \ub2e4\ub8e8\uc5c8\ub358 \ud0c0\uc784\ub77c\uc778 \uad6c\uc870\uc640 \ub9e4\uc720 \uc720\uc0ac\ud569\ub2c8\ub2e4.<br>It is very similar to the timeline structure we previously covered for pagination.<\/p>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb API\ubd80\ubd84\uc758 \ud398\uc774\uc9c0\ub124\uc774\uc158\uc740 \uc544\uc9c1 \uc644\uc804\ud788 \uad6c\ud604\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4.<br>Pagination for the API section has not yet been fully implemented.<\/p>\n\n\n\n<p>\ud83d\udcc1 UI\ubd80\ubd84 \/ UI section<\/p>\n\n\n\n<p>\u2714\ufe0f themeex\ub97c \ud14c\ub9c8\ub85c \uc0ac\uc6a9\ud558\ub294 \uacbd\uc6b0 \uc54c\ub9bc UI\ubd80\ubd84\uc740 \ud504\ub85c\uc81d\ud2b8 \ub8e8\ud2b8\ub85c \ubd80\ud130 \uc544\ub798\uc758 \uacbd\ub85c\uc5d0 \uc788\uc2b5\ub2c8\ub2e4.<br>If you are using the &#8216;themeex&#8217; theme, the notification UI components can be found at the following path, relative to the project root:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>app\/usersui\/&#91;username]\/_components\/themes\/themeex\/NotificationsList.tsx<\/code><\/pre>\n\n\n\n<p>1)tsx\ud30c\uc77c\uc758 \uc704\uce58\ub294 \ud0c0\uc784\ub77c\uc778 \ud30c\uc77c\uc758 \uc704\uce58\uc640 \ub3d9\uc77c\ud569\ub2c8\ub2e4.<br>The location of the .tsx file is the same as the location of the timeline file.<\/p>\n\n\n\n<p>\u2714\ufe0f \ud398\uc774\uc9c0\ub124\uc774\uc158 \/ Pagination(userCursorPagination)<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>  const {\n    flatData: notis,\n    <strong>fetchNextPage<\/strong>,\n    hasNextPage,\n    isFetchingNextPage,\n    isLoading\n  } = useCursorPagination({\n    key: &#91;'notifications', username],\n    fetcher: async (cursor) => {\n      const params = new URLSearchParams();\n      params.set('username', username);\n      params.set('limit', '20');\n      if (cursor) params.set('max_id', cursor);\n\n      const r = await fetch(`\/api\/v1\/notifications?${params.toString()}`, { credentials: 'include' });\n      const data = await r.json();\n      const list = Array.isArray(data)? data : data.data || &#91;];\n\n      return {\n        data: list,\n        nextCursor: list.length === 30? list&#91;list.length - 1]?.id || list&#91;list.length - 1]?.created_at : null,\n        hasMore: list.length === 30,\n      };\n    },\n  });\n<\/code><\/pre>\n\n\n\n<p>1)\ud398\uc774\uc9c0\ub124\uc774\uc158 \uad6c\ud604\uc744 \uc704\ud574\uc11cuseCursorPagination \ud6c5\uc744 \ud638\ucd9c\ud558\uace0 fetcher\uc5d0 \uc775\uba85\ud568\uc218\ub97c \uc804\ub2ec\ud569\ub2c8\ub2e4.<br>To implement pagination, call the <code>useCursorPagination<\/code> hook and pass an anonymous function to the <code>fetcher<\/code>.<\/p>\n\n\n\n<p>\u2714\ufe0f \ud398\uc774\uc9c0\ub124\uc774\uc158(\ubb34\ud55c\uc2a4\ud06c\ub864 \uc635\uc800\ubc84)<br>Pagination (Infinite Scroll Observer)<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\n  const <strong>loaderRef <\/strong>= useRef&lt;HTMLDivElement&gt;(null);\n  useEffect(() =&gt; {\n    const <strong>el = loaderRef.current;<\/strong>\n    if (!el ||!hasNextPage) return;\n    const <strong>observer<\/strong> = new IntersectionObserver(\n      (&#91;entry]) =&gt; {\n        if (entry.isIntersecting &amp;&amp;!isFetchingNextPage) fetchNextPage();\n      },\n      { threshold: 0.3 }\n    );\n   <strong> observer.observe(el);<\/strong>\n    return () =&gt; observer.disconnect();\n  }, &#91;hasNextPage, isFetchingNextPage, fetchNextPage]);\n... ...\n\n      &lt;div ref={<strong>loaderRef<\/strong>} className=\"h-10 flex items-center justify-center text-sm text-&#91;#999]\"&gt;\n        {isFetchingNextPage &amp;&amp; &lt;span&gt;\ubd88\ub7ec\uc624\ub294 \uc911 \/ Loading ...&lt;\/span&gt;}\n        {!hasNextPage &amp;&amp; notis.length &gt; 0 &amp;&amp; &lt;span className=\"text-xs\"&gt;\ub05d \/ No more&lt;\/span&gt;}\n      &lt;\/div&gt;<\/code><\/pre>\n\n\n\n<p>1)\uc0ac\uc6a9\uc790\uac00 \ud654\uba74 \uc2a4\ud06c\ub864\uc744 \ub0b4\ub9ac\uba74 \ubb34\ud55c\uc2a4\ud06c\ub864 \uc635\uc800\ubc84\uac00 &lt;div ref={loaderRef}\ub97c \ud655\uc778\ud558\uba74 fetchNextPage()\ud568\uc218\ub97c \uc2e4\ud589\ud569\ub2c8\ub2e4.<br>When the user scrolls down the screen, the infinite scroll observer detects the <code>&lt;div ref={loaderRef}><\/code> element and triggers the <code>fetchNextPage()<\/code> function.<\/p>\n\n\n\n<p>2)fetchNextPage()\ud568\uc218\ub294 userCursorPagination\ud6c5\uc5d0\uc11c \ub9ac\ud134\ub418\ub294 \ud568\uc218\uc785\ub2c8\ub2e4.<br>The <code>fetchNextPage()<\/code> function is a function returned by the <code>userCursorPagination<\/code> hook.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>\/\/ app\/usersui\/&#91;username]\/_components\/themes\/themeex\/NotificationsList.tsx\n... ...\n  const {\n    flatData: notis,\n    <strong>fetchNextPage,<\/strong>\n    hasNextPage,\n    isFetchingNextPage,\n    isLoading\n  } = <strong>useCursorPagination<\/strong>({\n    key: &#91;'notifications', username],\n    <strong>fetcher:<\/strong> async (cursor) => {\n... ....\n\n      const r = <strong>await fetch(`\/api\/v1\/notifications?${params.toString()}<\/strong>`, { credentials: 'include' });\n... ...\n      };\n    },\n  });<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>\/\/ app\/hooks\/useCursorPagination.ts\n... ...\nconst <strong>fetchNextPage<\/strong> = useCallback(async () => {\n... ...\n const res: any = await <strong>fetcher<\/strong>(nextCursorRef.current || undefined);\n... ...\n      setPages(prev => {\n        \/\/ Set : \uc911\ubcf5 \uc5c6\ub294 \uc9d1\ud569 \/ Set with no duplicates\n        const seen = new Set(prev.flat().map((p:any) => p.id));\n        const filtered = data.filter((p:any) => p.id &amp;&amp;!seen.has(p.id));\n        if (filtered.length === 0) {\n          setHasNextPage(false);\n          return prev;\n        }\n        return &#91;...prev, filtered];\n      });\n... ...\n} \n... ...\n   return {\n    flatData,\n    pages: pages.map(data => ({ data })),\n    <strong>fetchNextPage<\/strong>, \/\/ \ub2e4\uc74c \ud398\uc774\uc9c0 \uac00\uc838\uc624\ub294 \ud568\uc218 \/ Function to fetch the next page\n    hasNextPage,   \/\/ \ub2e4\uc74c \ud398\uc774\uc9c0\uac00 \uc788\ub294\uc9c0 \/ Whether there is a next page\n    isFetchingNextPage, \/\/ \ub2e4\uc74c \ud398\uc774\uc9c0 \ub85c\ub529\uc911\uc778\uc9c0 \/ Checking if the next page is loading...\n    isLoading, \/\/ \uccab \ub85c\ub529\uc911\uc778\uc9c0 \/ Is it loading for the first time?\n  };<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f \ub370\uc774\ud130\ub97c UI\uc5d0 \ucd9c\ub825 \/ Display data in the UI<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>  return (\n    &lt;div style={style} className=\"bg-white\">\n... ...\n\n{notis.map((n: any, idx: number) => (\n... ...\n              &lt;div className=\"text- mt-1\">\n                {n.type === 'follow' &amp;&amp; &lt;span>\ub2d8\uc774 \ud314\ub85c\uc6b0(follow) \ud588\uc2b5\ub2c8\ub2e4 &lt;span className=\"text-&#91;#6364ff]\">\ud83d\udc64&lt;\/span>&lt;\/span>}\n                {n.type === 'favourite' &amp;&amp; &lt;span>\ub2d8\uc774 \uc88b\uc544\uc694(like) \ud588\uc2b5\ub2c8\ub2e4 \u2764&lt;\/span>}\n                {n.type === 'reblog' &amp;&amp; &lt;span>\ub2d8\uc774 \ubd80\uc2a4\ud2b8(boost) \ud588\uc2b5\ub2c8\ub2e4 \ud83d\udd01&lt;\/span>}\n                {!&#91;'follow','favourite','reblog'].includes(n.type) &amp;&amp; &lt;span>{n.type}&lt;\/span>}\n              &lt;\/div>\n... ...\n ))}\n... ...\n    &lt;\/div>\n  );<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>\ud83d\udcc1 API<\/p>\n\n\n\n<p>\u2714\ufe0fapp\/api\/v1\/notifications\/route.ts<\/p>\n\n\n\n<p>\u2714\ufe0f Notification.tsx\uc5d0\uc11c useCursorPagination()\ud6c5\uc758 \ud30c\ub77c\uba54\ud130\ub85c \uc804\ub2ec\ub418\ub294 \ucf5c\ubc31\ud568\uc218(fetcher)\uc5d0\uc11c \uc2e4\ud589\ub429\ub2c8\ub2e4.<br>It is executed within the callback function (fetcher) that is passed as a parameter to the <code>useCursorPagination()<\/code> hook in <code>Notification.tsx<\/code>.<\/p>\n\n\n\n<p>\u2714\ufe0f \uc0ad\uc81c\uc608\uc815 \ucf54\ub4dc \/ Code scheduled for deletion<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>    const max_id = searchParams.get('max_id'); \n    if (max_id) {\n      return NextResponse.json(&#91;], {\n        headers: { 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application\/json' }\n      });\n    }<\/code><\/pre>\n\n\n\n<p>1)\ud398\uc774\uc9c0\ub124\uc774\uc158\uc774 \uc544\uc9c1 API\uc5d0\uc11c \uad6c\ud604\ub418\uc9c0\uc54a\uc544 Tursky\uc571\uc5d0\uc11c max_id\ub97c \ud638\ucd9c\ud558\uba74 \ubb34\ud55c \ub85c\ub529\ub418\ub294 \ubd80\ubd84\uc744 \ub9c9\uc544\ub193\uc740 \ucf54\ub4dc\uc785\ub2c8\ub2e4.<br>This code prevents an infinite loading state in the Tursky app that occurs when <code>max_id<\/code> is called, as pagination has not yet been implemented in the API.<\/p>\n\n\n\n<p>2)max_id\ub294 max_id\ub97c \uae30\uc900\uc73c\ub85c \ub370\uc774\ud130 \ubca0\uc774\uc2a4\uc5d0\uc11c \uae00 \uc791\uc131 \ub0a0\uc9dc\ub97c \uac80\uc0c9\ud569\ub2c8\ub2e4. <br><code>max_id<\/code> is used to retrieve the post creation date from the database, based on the <code>max_id<\/code> value.<\/p>\n\n\n\n<p>3)\uadf8\ub9ac\uace0 \uac80\uc0c9\ub41c \ub0a0\uc9dc \ubcf4\ub2e4 \ub354 \uc774\uc804 \ub0a0\uc9dc\uc758 \uae00\uc744 \uac80\uc0c9\uc744 \ud569\ub2c8\ub2e4.<br>And it searches for posts with a date earlier than the date found.<\/p>\n\n\n\n<p>3)max_id\ub294 \ud398\uc774\uc9c0\ub124\uc774\uc158 \uad6c\ud604\uc744 \uc704\ud574 \uc5b4\ub514\ubd80\ud130 \uae00\uc744 \ud638\ucd9c\ud560\uac83\uc778\uc9c0\uc5d0 \ub300\ud55c \uae30\uc900\uc774 \ub429\ub2c8\ub2e4.<br><code>max_id<\/code> serves as a reference point for determining where to begin fetching posts when implementing pagination.<\/p>\n\n\n\n<p>4)\uc704\uc758 \ucf54\ub4dc\ub294 \ud398\uc774\uc9c0\ub124\uc774\uc158\uc774 \uc644\uc804\ud788 \uad6c\ud604\ub418\uba74 \uc0ad\uc81c \ub429\ub2c8\ub2e4.<br>The code above will be removed once pagination is fully implemented.<\/p>\n\n\n\n<p>\u2714\ufe0f \ub370\uc774\ud130 \uc218\uc9d1 \ubc0f \ub9ac\ud134 \/ Data Collection and Return<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\nconst <strong>notifications<\/strong>: any&#91;] = &#91;];\n... ...\n    return NextResponse.json(<strong>notifications.slice(0, limit<\/strong>), {\n      headers: { 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application\/json' }\n    });<\/code><\/pre>\n\n\n\n<p>1)notifications \ubc30\uc5f4\uc740 \uc54c\ub9bc \ub370\uc774\ud130\ub97c \uc218\uc9d1\ud574\uc11c json\ub370\uc774\ud130\ub85c \ub9ac\ud134\ud569\ub2c8\ub2e4.<br>The <code>notifications<\/code> array collects notification data and returns it as JSON data.<\/p>\n\n\n\n<p>2)\uccab \ubc30\uc5f4(0)\ubd80\ud145 limit\uae4c\uc9c0 \uac12\uc744 \ub9ac\ud134\ud569\ub2c8\ub2e4.<br>Returns values \u200b\u200bfrom the first index (0) up to the limit.<\/p>\n\n\n\n<p>\u2714\ufe0f Follow\uc54c\ub9bc,Like\uc54c\ub9bc,Reblog(=boost)\uc54c\ub9bc<br>Follow notifications, Like notifications, Reblog (=boost) notifications<\/p>\n\n\n\n<p>&#8212; \uc544\ub798\uc758\ucf54\ub4dc\ub97c \ubcf4\uba74 \uac01 \uc54c\ub9bc\uc758 \uac12\uc744 notifications\ubc30\uc5f4\uc5d0 \ucd94\uac00\ud558\ub294 \uac83\uc744 \ubcfc \uc218 \uc788\uc2b5\ub2c8\ub2e4.(notifications.push)<br>Looking at the code below, you can see that the value of each notification is added to the <code>notifications<\/code> array.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>1.Follow\uc54c\ub9bc \/ Follow notifications\n\n\n    try {\n      const follows = db.prepare(`SELECT id, actor, inbox, username, created_at FROM followers WHERE username =? ORDER BY created_at DESC LIMIT 20`).all(username) as any&#91;];\n      for (let i=0; i&lt;follows.length; i++) {\n        const row = follows&#91;i];\n        const actor = row.actor || '';\n        if (actor.includes(myActor)) continue; \/\/ \uc790\uae30 \uc81c\uc678!\n        const parsed = parseActor(actor, i);\n        <strong>notifications.push<\/strong>({\n          id: `follow_${i}_${row.id}`,\n          type: 'follow',\n          created_at: row.created_at? new Date(row.created_at).toISOString() : new Date().toISOString(),\n          account: makeAccount(parsed, i, row.created_at),\n          status: null,\n        });\n      }\n    } catch(e){ console.error('follow', e); }\n\n\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>2.Like\uc54c\ub9bc \/ Like notifications\n\n    try {\n      const likes = db.prepare(`SELECT id, actor, object, username, created_at FROM likes WHERE username =? ORDER BY created_at DESC LIMIT 30`).all(username) as any&#91;];\n      console.log(`\u2764 likes table rows=${likes.length} for ${username}`);\n      for (let i=0; i&lt;likes.length; i++) {\n        const row = likes&#91;i];\n        const actor = row.actor || '';\n        const objectId = row.object || '';\n        console.log(` like: actor=${actor} object=${objectId}`);\n\n        \/\/ \uc790\uae30 \uc790\uc2e0 \uc88b\uc544\uc694 \uc81c\uc678 \/ Excludes your own \"likes.\"\n        if (actor.includes(myActor) || actor.includes(`\/users\/${username}`) &amp;&amp; actor.includes(DOMAIN)) {\n          console.log(` -> self like skip!`);\n          continue;\n        }\n\n        const parsed = parseActor(actor, i+100);\n\n        const isMyPost = objectId.includes(DOMAIN) || objectId.includes('aloy-horizon');\n        if (!isMyPost) {\n          console.log(` -> not my post, skip (outgoing like)`);\n          continue;\n        }\n\n        \/\/ \uc6d0\ubcf8 \uae00 \ucc3e\uae30 \/ Find the original post\n        let statusObj: any = null;\n        try {\n          const shortId = objectId.split('\/').pop()?.split('?')&#91;0];\n          const post = db.prepare(`SELECT id, content, created_at FROM posts WHERE id =? OR id LIKE? LIMIT 1`).get(objectId, `%${shortId}%`) as any;\n          if (post) {\n            statusObj = {\n              id: post.id,\n              uri: objectId,\n              url: objectId,\n              content: post.content || '&lt;p>\ub0b4 \uae00&lt;\/p>',\n              created_at: post.created_at? new Date(post.created_at).toISOString() : new Date().toISOString(),\n              account: { id: '1', username, acct: `${username}@${DOMAIN}`, display_name: username, avatar: `https:\/\/${DOMAIN}\/icon.png` },\n              visibility: 'public', reblogs_count: 0, favourites_count: 0, replies_count: 0,\n            };\n          } else {\n... ...\n          }\n        } catch {}\n\n       <strong> notifications.push<\/strong>({\n          id: `fav_${i}_${row.id}`,\n          type: 'favourite',\n          created_at: row.created_at? new Date(row.created_at).toISOString() : new Date().toISOString(),\n          account: makeAccount(parsed, i+100, row.created_at),\n          status: statusObj,\n        });\n      }\n    } catch(e){ console.error('likes notif', e); }<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>3.Reblog \/ Reblog notifications\n\n    try {\n      const boosts = db.prepare(`SELECT id, actor, object, username, created_at FROM announces WHERE username =? ORDER BY created_at DESC LIMIT 20`).all(username) as any&#91;];\n      for (let i=0; i&lt;boosts.length; i++) {\n        const row = boosts&#91;i];\n        const actor = row.actor || '';\n        if (actor.includes(myActor)) continue;\n        const parsed = parseActor(actor, i+200);\n        <strong>notifications.push<\/strong>({\n          id: `reblog_${i}_${row.id}`,\n          type: 'reblog',\n          created_at: row.created_at? new Date(row.created_at).toISOString() : new Date().toISOString(),\n          account: makeAccount(parsed, i+200, row.created_at),\n          status: null,\n        });\n      }\n    } catch(e){}<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f \ub370\uc774\ud130 \ub0b4\ub9bc\ucc28\uc21c \uc815\ub82c \/ Sort data in descending order<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code> notifications.sort((a,b)=> new Date(<strong>b.created_at<\/strong>).getTime() - new Date(<strong>a.created_at<\/strong>).getTime());<\/code><\/pre>\n\n\n\n<p>1)b &#8211; a \ub0b4\ub9bc\ucc28\uc21c, a &#8211; b \uc624\ub984\ucc28\uc21c<br>b &#8211; a for descending order, a &#8211; b for ascending order<\/p>\n\n\n\n<p>2)\uc704\uc758 \ucf54\ub4dc\ub294 \ub0b4\ub9bc\ucc28\uc21c \uc815\ub82c \uc785\ub2c8\ub2e4.<br>The code above sorts in descending order.<\/p>\n\n\n\n<p>3)sort\ud568\uc218\ub294 \uc790\uccb4 \ub0b4\ubd80 \uc54c\uace0\ub9ac\uc998\uc5d0 \ub530\ub77c \uc815\ub82c\uae30\ub2a5\uc744 \uc218\ud589\ud569\ub2c8\ub2e4.<br>The <code>sort<\/code> function performs sorting based on its own internal algorithm.<\/p>\n\n\n\n<p>\ud83d\udcc1 \ud14c\uc2a4\ud2b8 \/ Test<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"554\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/10\/Notifications-jpg.jpg\" alt=\"\" class=\"wp-image-13049\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/10\/Notifications-jpg.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/10\/Notifications-jpg-300x208.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/10\/Notifications-jpg-768x532.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/10\/Notifications-jpg-400x277.jpg 400w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">themeex<\/figcaption><\/figure>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>\ub9c8\ud0dc\ubcf5\uc74c 21\uc7a5 22\uc808 \/ Matthew 21: 22<\/p>\n\n\n\n<p>&#8220;\ub108\ud76c\uac00 \uae30\ub3c4\ud560 \ub54c\uc5d0 \ubb34\uc5c7\uc774\ub4e0\uc9c0 \ubbff\uace0 \uad6c\ud558\ub294 \uac83\uc740 \ub2e4 \ubc1b\uc73c\ub9ac\ub77c \ud558\uc2dc\ub2c8\ub77c&#8221;<\/p>\n\n\n\n<p>&#8220;And everything you ask in prayer, believing, you will receive.&#8221;<\/p>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>\ud83d\udc49\ud83c\udffb \uc774\ubc88\uc5d0\ub294 \uc54c\ub9bc \uae30\ub2a5\uc5d0 \ub300\ud574\uc11c \uc0b4\ud3b4 \ubd05\ub2c8\ub2e4.Next, we will take a look at the notification feature. \ud83d\udc49\ud83c\udffb \uc774\uc804\uc5d0 \ud398\uc774\uc9c0\ub124\uc774\uc158\uc744 \uc704\ud574 \ub2e4\ub8e8\uc5c8\ub358 \ud0c0\uc784\ub77c\uc778 \uad6c\uc870\uc640 \ub9e4\uc720 \uc720\uc0ac\ud569\ub2c8\ub2e4.It is very similar to the timeline structure we previously covered for pagination. \ud83d\udc49\ud83c\udffb API\ubd80\ubd84\uc758 \ud398\uc774\uc9c0\ub124\uc774\uc158\uc740 \uc544\uc9c1 \uc644\uc804\ud788 \uad6c\ud604\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4.Pagination for the API section has not yet been fully implemented. \ud83d\udcc1 [&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-12990","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\/12990","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=12990"}],"version-history":[{"count":57,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/12990\/revisions"}],"predecessor-version":[{"id":13051,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/12990\/revisions\/13051"}],"wp:attachment":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=12990"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=12990"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=12990"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}