{"id":64992,"date":"2025-05-16T16:47:07","date_gmt":"2025-05-16T07:47:07","guid":{"rendered":"https:\/\/kinsta.com\/jp\/?p=64992&#038;preview=true&#038;preview_id=64992"},"modified":"2025-05-16T22:32:31","modified_gmt":"2025-05-16T13:32:31","slug":"add-interactivity-scheduling-monitoring-slackbot","status":"publish","type":"post","link":"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/","title":{"rendered":"WordPress\u7ba1\u7406\u7528Slackbot\u306b\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u6027\u3001\u81ea\u52d5\u5316\u3001\u76e3\u8996\u6a5f\u80fd\u3092\u8ffd\u52a0\u3059\u308b\u65b9\u6cd5"},"content":{"rendered":"<p>Slackbot\u3092\u9069\u5207\u306b\u8a2d\u5b9a\u3059\u308c\u3070\u3001<a href=\"https:\/\/kinsta.com\/jp\/blog\/how-to-use-slack\/\">Slack<\/a>\u4e0a\u3067\u30dc\u30bf\u30f3\u3084\u30c9\u30ed\u30c3\u30d7\u30c0\u30a6\u30f3\u3001\u5b9a\u671f\u30bf\u30b9\u30af\u3001\u30b9\u30de\u30fc\u30c8\u901a\u77e5\u306a\u3069\u3092\u4f7f\u3063\u3066\u3001<a href=\"https:\/\/kinsta.com\/jp\/blog\/what-is-wordpress\/\">WordPress<\/a>\u30b5\u30a4\u30c8\u306e\u7ba1\u7406\u3092\u52b9\u7387\u5316\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n<p>\u4eca\u56de\u306f\u3001WordPress\u30b5\u30a4\u30c8\u306e\u7ba1\u7406\u7528\u306b\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u306a\u5bfe\u8a71\u6a5f\u80fd\u3001\u81ea\u52d5\u5316\u3001\u76e3\u8996\u6a5f\u80fd\u3092Slackbot\u306b\u5b9f\u88c5\u3059\u308b\u65b9\u6cd5\u3092\u53d6\u308a\u4e0a\u3052\u307e\u3059\u3002<\/p>\n<div><\/div><kinsta-auto-toc heading=\"Table of Contents\" exclude=\"last\" list-style=\"arrow\" selector=\"h2\" count-number=\"-1\"><\/kinsta-auto-toc>\n<h2>\u524d\u63d0\u6761\u4ef6<\/h2>\n<p>\u3053\u308c\u304b\u3089\u3054\u7d39\u4ecb\u3059\u308b\u5185\u5bb9\u306f\u3001\u4ee5\u4e0b\u304c\u5fc5\u8981\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n<ul>\n<li>\u30dc\u30c3\u30c8\u6a29\u9650\u3068\u30b9\u30e9\u30c3\u30b7\u30e5\u30b3\u30de\u30f3\u30c9\u3092\u6301\u3064Slack\u30a2\u30d7\u30ea<\/li>\n<li>API\u30a2\u30af\u30bb\u30b9\u6a29\u3092\u6301\u3064<a href=\"https:\/\/kinsta.com\/jp\/\">Kinsta\u30a2\u30ab\u30a6\u30f3\u30c8<\/a>\u3068\u30c6\u30b9\u30c8\u7528\u30b5\u30a4\u30c8<\/li>\n<li>\u30ed\u30fc\u30ab\u30eb\u74b0\u5883\u3078\u306eNode.js\u3068NPM\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb<\/li>\n<li>JavaScript\u306e\u57fa\u790e\u77e5\u8b58\uff08\u5c11\u306a\u304f\u3068\u3082\u30b3\u30fc\u30c9\u306e\u30b3\u30d4\u30fc\u3068\u5fae\u8abf\u6574\u306b\u6163\u308c\u3066\u3044\u308b\u3053\u3068\uff09<\/li>\n<li>Slack\u3068Kinsta API\u30ad\u30fc<\/li>\n<\/ul>\n<h2>\u306f\u3058\u3081\u306b<\/h2>\n<p>\u3053\u306eSlackbot\u306f\u3001<a href=\"https:\/\/kinsta.com\/jp\/blog\/what-is-node-js\/\">Node.js<\/a>\u3068Slack\u306eJavaScript\u30d5\u30ec\u30fc\u30e0\u30ef\u30fc\u30af\u3067\u3042\u308b<a href=\"https:\/\/api.slack.com\/bolt\">Bolt<\/a>\u3092\u4f7f\u3044\u3001\u30b9\u30e9\u30c3\u30b7\u30e5\u30b3\u30de\u30f3\u30c9\u3092Kinsta\u306eAPI\u306b\u9023\u643a\u3055\u305b\u3066\u30a2\u30af\u30b7\u30e7\u30f3\u3092\u5b9f\u884c\u3067\u304d\u308b\u3088\u3046\u306b\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n<p>\u4eca\u56de\u306f\u3001Slack\u30a2\u30d7\u30ea\u306e\u4f5c\u6210\u3084Kinsta API\u30a2\u30af\u30bb\u30b9\u306e\u53d6\u5f97\u306b\u95a2\u3059\u308b\u624b\u9806\u306f\u5272\u611b\u3057\u307e\u3059\u3002<a href=\"https:\/\/kinsta.com\/jp\/blog\/create-slackbot-site-management\/\">\u30b5\u30a4\u30c8\u7ba1\u7406\u7528\u306bNode.js\u3068Kinsta API\u3092\u4f7f\u3063\u3066Slackbot\u3092\u4f5c\u6210\u3059\u308b\u65b9\u6cd5\u306f\u3053\u3061\u3089<\/a>\u3092\u3054\u89a7\u304f\u3060\u3055\u3044\u3002<\/p>\n<p>\u5148\u306b\u4e0a\u8a18\u306e\u8a18\u4e8b\u306b\u76ee\u3092\u901a\u3057\u3066\u304b\u3089\u3001\u672c\u8a18\u4e8b\u3092\u3054\u89a7\u3044\u305f\u3060\u304f\u306e\u304c\u304a\u3059\u3059\u3081\u3067\u3059\u3002\u3053\u306e\u8a18\u4e8b\u3067\u306f\u3001Slack\u30a2\u30d7\u30ea\u306e\u4f5c\u6210\u3001\u30dc\u30c3\u30c8\u30c8\u30fc\u30af\u30f3\u3068Signing Secret\u306e\u53d6\u5f97\u3001Kinsta API\u30ad\u30fc\u306e\u53d6\u5f97\u306b\u3064\u3044\u3066\u3054\u8aac\u660e\u3057\u307e\u3059\u3002<\/p>\n<h2>Slackbot\u306b\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u6a5f\u80fd\u3092\u8ffd\u52a0<\/h2>\n<p>Slackbot\u306f\u30b9\u30e9\u30c3\u30b7\u30e5\u30b3\u30de\u30f3\u30c9\u3060\u3051\u306b\u983c\u308b\u5fc5\u8981\u306f\u3042\u308a\u307e\u305b\u3093\u3002\u30dc\u30bf\u30f3\u3001\u30e1\u30cb\u30e5\u30fc\u3001\u30e2\u30fc\u30c0\u30eb\u306a\u3069\u306e\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u306a\u8981\u7d20\u3092\u4f7f\u3048\u3070\u3001\u30dc\u30c3\u30c8\u3092\u3088\u308a\u76f4\u611f\u7684\u3067\u30e6\u30fc\u30b6\u30fc\u30d5\u30ec\u30f3\u30c9\u30ea\u30fc\u306a\u30c4\u30fc\u30eb\u306b\u5909\u8eab\u3055\u305b\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n<p>\u4f8b\u3048\u3070\u3001<code>\/clear_cache environment_id<\/code>\u3068\u5165\u529b\u3059\u308b\u4ee3\u308f\u308a\u306b\u3001\u30b5\u30a4\u30c8\u306e\u30b9\u30c6\u30fc\u30bf\u30b9\u3092\u78ba\u8a8d\u3057\u305f\u5f8c\u3001\u30dc\u30bf\u30f3\u3092\u30af\u30ea\u30c3\u30af\u3057\u3066\u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u30af\u30ea\u30a2\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u308c\u3070\u4fbf\u5229\u3067\u3059\u3002\u3053\u308c\u306b\u306f<a href=\"https:\/\/www.npmjs.com\/package\/@slack\/web-api\" target=\"_blank\" rel=\"noopener noreferrer\">Slack\u306eWeb API\u30af\u30e9\u30a4\u30a2\u30f3\u30c8<\/a>\u304c\u5fc5\u8981\u306b\u306a\u308a\u307e\u3059\u3002\u4ee5\u4e0b\u306e\u30b3\u30de\u30f3\u30c9\u3067\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306b\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n<pre><code class=\"language-bash\">npm install @slack\/web-api<\/code><\/pre>\n<p><code>app.js<\/code>\u3067\u521d\u671f\u5316\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">const { WebClient } = require('@slack\/web-api');\nconst web = new WebClient(process.env.SLACK_BOT_TOKEN);<\/code><\/pre>\n<p><code>.env<\/code>\u30d5\u30a1\u30a4\u30eb\u306b<code>SLACK_BOT_TOKEN<\/code>\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u308b\u3053\u3068\u3092\u78ba\u8a8d\u3057\u307e\u3059\u3002\u4f8b\u3068\u3057\u3066\u3001\u524d\u56de\u306e\u8a18\u4e8b\u3067\u3054\u7d39\u4ecb\u3057\u305f<code>\/site_status<\/code>\u30b3\u30de\u30f3\u30c9\u3092\u6539\u826f\u3057\u3066\u307f\u307e\u3059\u3002\u5358\u306b\u30c6\u30ad\u30b9\u30c8\u3092\u9001\u4fe1\u3059\u308b\u3060\u3051\u3067\u306a\u304f\u3001\u300c<strong>\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u30af\u30ea\u30a2<\/strong>\u300d\u300c<strong>\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u306e\u4f5c\u6210<\/strong>\u300d\u300c<strong>\u30b9\u30c6\u30fc\u30bf\u30b9\u306e\u8a73\u7d30\u78ba\u8a8d<\/strong>\u300d\u306e\u3088\u3046\u306a\u30af\u30a4\u30c3\u30af\u30a2\u30af\u30b7\u30e7\u30f3\u7528\u306e\u30dc\u30bf\u30f3\u3092\u8ffd\u52a0\u3057\u307e\u3059\u3002<\/p>\n<p>\u3053\u306e\u30cf\u30f3\u30c9\u30e9\u306f\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">app.command('\/site_status', async ({ command, ack, say }) =&gt; {\n  await ack();\n  \n  const environmentId = command.text.trim();\n  \n  if (!environmentId) {\n    await say('\u74b0\u5883ID\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u69cb\u6587: \/site_status [environment-id]');\n    return;\n  }\n  \n  try {\n    \/\/ \u74b0\u5883\u30b9\u30c6\u30fc\u30bf\u30b9\u306e\u53d6\u5f97\n    const response = await kinstaRequest(`\/sites\/environments\/${environmentId}`);\n    \n    if (response && response.site && response.site.environments && response.site.environments.length &gt; 0) {\n      const env = response.site.environments[0];\n      \n      \/\/ \u30b9\u30c6\u30fc\u30bf\u30b9\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u6574\u3048\u308b\n      let statusMessage = formatSiteStatus(env);\n      \n      \/\/ \u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u306a\u30dc\u30bf\u30f3\u3067\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u9001\u4fe1\n      await web.chat.postMessage({\n        channel: command.channel_id,\n        text: statusMessage,\n        blocks: [\n          {\n            type: 'section',\n            text: {\n              type: 'mrkdwn',\n              text: statusMessage\n            }\n          },\n          {\n            type: 'actions',\n            elements: [\n              {\n                type: 'button',\n                text: {\n                  type: 'plain_text',\n                  text: '\ud83e\uddf9 \u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u30af\u30ea\u30a2',\n                  emoji: true\n                },\n                value: environmentId,\n                action_id: 'clear_cache_button'\n              },\n              {\n                type: 'button',\n                text: {\n                  type: 'plain_text',\n                  text: '\ud83d\udcca \u30b9\u30c6\u30fc\u30bf\u30b9\u306e\u8a73\u7d30\u78ba\u8a8d',\n                  emoji: true\n                },\n                value: environmentId,\n                action_id: 'detailed_status_button'\n              },\n              {\n                type: 'button',\n                text: {\n                  type: 'plain_text',\n                  text: '\ud83d\udcbe \u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u306e\u4f5c\u6210',\n                  emoji: true\n                },\n                value: environmentId,\n                action_id: 'create_backup_button'\n              }\n            ]\n          }\n        ]\n      });\n    } else {\n      await say(`\u26a0\ufe0f ID ${environmentId} \u306e\u74b0\u5883\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f`);\n    }\n  } catch (error) {\n    console.error('\u30b5\u30a4\u30c8\u30b9\u30c6\u30fc\u30bf\u30b9\u306e\u30c1\u30a7\u30c3\u30af\u3067\u30a8\u30e9\u30fc\u304c\u767a\u751f: ', error);\n    await say(`\u274c \u30b5\u30a4\u30c8\u306e\u72b6\u614b\u306e\u78ba\u8a8d\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f: ${error.message}`);\n  }\n});<\/code><\/pre>\n<p>\u5404\u30dc\u30bf\u30f3\u3092\u30af\u30ea\u30c3\u30af\u3059\u308b\u3068\u3001\u30a2\u30af\u30b7\u30e7\u30f3\u304c\u30c8\u30ea\u30ac\u30fc\u3055\u308c\u307e\u3059\u3002\u4ee5\u4e0b\u3001\u300c<strong>\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u30af\u30ea\u30a2<\/strong>\u300d\u30dc\u30bf\u30f3\u3092\u3069\u306e\u3088\u3046\u306b\u6271\u3046\u304b\u3092\u898b\u3066\u307f\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">\/\/ \u30dc\u30bf\u30f3\u306e\u30a2\u30af\u30b7\u30e7\u30f3\u30cf\u30f3\u30c9\u30e9\u3092\u8ffd\u52a0\napp.action('clear_cache_button', async ({ body, ack, respond }) =&gt; {\n  await ack();\n  \n  const environmentId = body.actions[0].value;\n  \n  await respond(`\u74b0\u5883 ${environmentId} \u306e\u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u30af\u30ea\u30a2\u3057\u3066\u3044\u307e\u3059...\ud83d\udd04`);\n  \n  try {\n    \/\/ Kinsta API\u3092\u547c\u3073\u51fa\u3057\u3066\u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u30af\u30ea\u30a2\n    const response = await kinstaRequest(\n      `\/sites\/environments\/${environmentId}\/clear-cache`,\n      'POST'\n    );\n    \n    if (response && response.operation_id) {\n      await respond(`\u2705 \u30ad\u30e3\u30c3\u30b7\u30e5\u30af\u30ea\u30a2\u306e\u64cd\u4f5c\u3092\u958b\u59cb\u3002\u30aa\u30da\u30ec\u30fc\u30b7\u30e7\u30f3ID: ${response.operation_id}`);\n    } else {\n      await respond('\u26a0\ufe0f \u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u30af\u30ea\u30a2\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u9001\u4fe1\u3057\u307e\u3057\u305f\u304c\u3001\u30aa\u30da\u30ec\u30fc\u30b7\u30e7\u30f3ID\u304c\u8fd4\u3055\u308c\u307e\u305b\u3093\u3067\u3057\u305f');\n    }\n  } catch (error) {\n    console.error('\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u30af\u30ea\u30a2\u30a8\u30e9\u30fc:', error);\n    await respond(`\u274c \u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u30af\u30ea\u30a2\u30a8\u30e9\u30fc: ${error.message}`);\n  }\n});<\/code><\/pre>\n<p>\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u30dc\u30bf\u30f3\u3084\u30b9\u30c6\u30fc\u30bf\u30b9\u30dc\u30bf\u30f3\u3082\u540c\u3058\u30d1\u30bf\u30fc\u30f3\u3067\u3001\u305d\u308c\u305e\u308c\u3092\u9069\u5207\u306aAPI\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u3084\u30b3\u30de\u30f3\u30c9\u30ed\u30b8\u30c3\u30af\u306b\u30ea\u30f3\u30af\u3055\u305b\u308c\u3070\u3088\u3044\u3002<\/p>\n<pre><code class=\"language-js\">\/\/ \u4ed6\u306e\u30dc\u30bf\u30f3\u7528\u30cf\u30f3\u30c9\u30e9\napp.action('detailed_status_button', async ({ body, ack, respond }) =&gt; {\n  await ack();\n  const environmentId = body.actions[0].value;\n  \/\/ detailed_status\u30b3\u30de\u30f3\u30c9\u3068\u540c\u69d8\u306e\u8a73\u7d30\u306a\u30b9\u30c6\u30fc\u30bf\u30b9\u30c1\u30a7\u30c3\u30af\u3092\u5b9f\u88c5\n  \/\/ ...\n});\n\napp.action('create_backup_button', async ({ body, ack, respond }) =&gt; {\n  await ack();\n  const environmentId = body.actions[0].value;\n  \/\/ create_backup\u30b3\u30de\u30f3\u30c9\u3068\u540c\u69d8\u306e\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u4f5c\u6210\u3092\u5b9f\u88c5\n  \/\/ ...\n});<\/code><\/pre>\n<h3>\u30c9\u30ed\u30c3\u30d7\u30c0\u30a6\u30f3\u3067\u30b5\u30a4\u30c8\u3092\u9078\u629e<\/h3>\n<p>\u74b0\u5883ID\u306e\u5165\u529b\u306f\u3001\u30c1\u30fc\u30e0\u30e1\u30f3\u30d0\u30fc\u5168\u54e1\u304c\u3069\u306eID\u304c\u3069\u306e\u74b0\u5883\u306b\u5c5e\u3057\u3066\u3044\u308b\u304b\u3092\u628a\u63e1\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u3001\u9762\u5012\u306a\u64cd\u4f5c\u306b\u306a\u308a\u5f97\u307e\u3059\u3002<\/p>\n<p>\u3053\u308c\u3092\u3088\u308a\u76f4\u611f\u7684\u306b\u884c\u3048\u308b\u3088\u3046\u3001<code>\/site_status [environment-id]<\/code>\u3092\u5165\u529b\u3059\u308b\u4ee3\u308f\u308a\u306b\u3001Slack\u306e\u30c9\u30ed\u30c3\u30d7\u30c0\u30a6\u30f3\u3067\u30b5\u30a4\u30c8\u3092\u9078\u629e\u3067\u304d\u308b\u3088\u3046\u306b\u3057\u307e\u3059\u3002\u9078\u629e\u3059\u308b\u3068\u3001\u8a72\u5f53\u306e\u30b5\u30a4\u30c8\u306e\u30b9\u30c6\u30fc\u30bf\u30b9\u304c\u8868\u793a\u3055\u308c\u3001\u5148\u307b\u3069\u5b9f\u88c5\u3057\u305f\u30af\u30a4\u30c3\u30af\u30a2\u30af\u30b7\u30e7\u30f3\u30dc\u30bf\u30f3\u3092\u4f7f\u7528\u3067\u304d\u308b\u3088\u3046\u306b\u3057\u307e\u3059\u3002<\/p>\n<p>\u4ee5\u4e0b\u306e\u3088\u3046\u306a\u6d41\u308c\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n<ul>\n<li>Kinsta API\u304b\u3089\u5168\u3066\u306e\u30b5\u30a4\u30c8\u3092\u53d6\u5f97<\/li>\n<li>\u5404\u30b5\u30a4\u30c8\u306e\u74b0\u5883\u3092\u53d6\u5f97<\/li>\n<li>\u3053\u308c\u3089\u306e\u30aa\u30d7\u30b7\u30e7\u30f3\u3067\u30c9\u30ed\u30c3\u30d7\u30c0\u30a6\u30f3\u30e1\u30cb\u30e5\u30fc\u3092\u69cb\u7bc9<\/li>\n<li>\u30e6\u30fc\u30b6\u30fc\u306e\u9078\u629e\u3092\u51e6\u7406\u3057\u3066\u30b5\u30a4\u30c8\u306e\u30b9\u30c6\u30fc\u30bf\u30b9\u3092\u8868\u793a<\/li>\n<\/ul>\n<p>\u4ee5\u4e0b\u306f\u30c9\u30ed\u30c3\u30d7\u30c0\u30a6\u30f3\u30e1\u30cb\u30e5\u30fc\u3092\u8868\u793a\u3059\u308b\u30b3\u30de\u30f3\u30c9\u3067\u3059\u3002<\/p>\n<pre><code class=\"language-js\">app.command('\/select_site', async ({ command, ack, say }) =&gt; {\n  await ack();\n  \n  try {\n    \/\/ \u3059\u3079\u3066\u306e\u30b5\u30a4\u30c8\u3092\u53d6\u5f97\n    const response = await kinstaRequest('\/sites');\n    \n    if (response && response.company && response.company.sites) {\n      const sites = response.company.sites;\n      \n      \/\/ \u5404\u30b5\u30a4\u30c8\u306b\u30aa\u30d7\u30b7\u30e7\u30f3\u3092\u4f5c\u6210\n      const options = [];\n      \n      for (const site of sites) {\n        \/\/ \u3053\u306e\u30b5\u30a4\u30c8\u306e\u74b0\u5883\u3092\u53d6\u5f97\n        const envResponse = await kinstaRequest(`\/sites\/${site.id}\/environments`);\n        \n        if (envResponse && envResponse.site && envResponse.site.environments) {\n          for (const env of envResponse.site.environments) {\n            options.push({\n              text: {\n                type: 'plain_text',\n                text: `${site.name} (${env.name})`\n              },\n              value: env.id\n            });\n          }\n        }\n      }\n      \n      \/\/ \u30c9\u30ed\u30c3\u30d7\u30c0\u30a6\u30f3\u3067\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u9001\u4fe1\n      await web.chat.postMessage({\n        channel: command.channel_id,\n        text: '\u7ba1\u7406\u3059\u308b\u30b5\u30a4\u30c8\u3092\u9078\u629e:',\n        blocks: [\n          {\n            type: 'section',\n            text: {\n              type: 'mrkdwn',\n              text: '*\u7ba1\u7406\u3059\u308b\u30b5\u30a4\u30c8\u3092\u9078\u629e:*'\n            },\n            accessory: {\n              type: 'static_select',\n              placeholder: {\n                type: 'plain_text',\n                text: 'Select a site'\n              },\n              options: options.slice(0, 100), \/\/ Slack\u306e\u30aa\u30d7\u30b7\u30e7\u30f3\u306f\u6700\u5927100\u500b\u307e\u3067\n              action_id: 'site_selected'\n            }\n          }\n        ]\n      });\n    } else {\n      await say('\u274c \u30b5\u30a4\u30c8\u306e\u53d6\u5f97\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002API\u8a8d\u8a3c\u60c5\u5831\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002');\n    }\n  } catch (error) {\n    console.error('\u30a8\u30e9\u30fc:', error);\n    await say(`\u274c \u30b5\u30a4\u30c8\u306e\u53d6\u5f97\u30a8\u30e9\u30fc: ${error.message}`);\n  }\n});<\/code><\/pre>\n<p>\u30b5\u30a4\u30c8\u304c\u9078\u629e\u3059\u308b\u3068\u3001\u4ee5\u4e0b\u306e\u30a2\u30af\u30b7\u30e7\u30f3\u30cf\u30f3\u30c9\u30e9\u3067\u51e6\u7406\u3055\u308c\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">\/\/ \u30b5\u30a4\u30c8\u9078\u629e\u3092\u51e6\u7406\napp.action('site_selected', async ({ body, ack, respond }) =&gt; {\n  await ack();\n  \n  const environmentId = body.actions[0].selected_option.value;\n  const siteName = body.actions[0].selected_option.text.text;\n  \n  \/\/ \u74b0\u5883\u30b9\u30c6\u30fc\u30bf\u30b9\u3092\u53d6\u5f97\n  try {\n    const response = await kinstaRequest(`\/sites\/environments\/${environmentId}`);\n    \n    if (response && response.site && response.site.environments && response.site.environments.length &gt; 0) {\n      const env = response.site.environments[0];\n      \n      \/\/\u30b9\u30c6\u30fc\u30bf\u30b9\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u6574\u3048\u308b\n      let statusMessage = `*${siteName}* (ID: `${environmentId}`)nn${formatSiteStatus(env)}`;\n      \n      \/\/ \u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u306a\u30dc\u30bf\u30f3\u3067\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u9001\u4fe1\uff08site_status\u30b3\u30de\u30f3\u30c9\u306b\u985e\u4f3c\uff09\n      \/\/ ...\n    } else {\n      await respond(`\u26a0\ufe0f ID ${environmentId} \u306e\u74b0\u5883\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f`);\n    }\n  } catch (error) {\n    console.error('\u30a8\u30e9\u30fc:', error);\n    await respond(`\u274c \u74b0\u5883\u306e\u53d6\u5f97\u30a8\u30e9\u30fc: ${error.message}`);\n  }\n});<\/code><\/pre>\n<p>\u306a\u304a\u3001\u3053\u308c\u306b\u3088\u308a\u30b5\u30a4\u30c8\u306e\u9078\u629e\u304c\u7c21\u7d20\u5316\u3055\u308c\u307e\u3059\u304c\u3001\u8aa4\u3063\u3066\u5371\u967a\u306a\u64cd\u4f5c\u3092\u5b9f\u884c\u3057\u306a\u3044\u3088\u3046\u306b\u6ce8\u610f\u3057\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n<h3>\u78ba\u8a8d\u30c0\u30a4\u30a2\u30ed\u30b0\u306e\u8868\u793a<\/h3>\n<p>\u8aa4\u3063\u3066\u5b9f\u884c\u3059\u308b\u3068\u5371\u967a\u306a\u64cd\u4f5c\u3082\u3042\u308a\u307e\u3059\u3002\u4f8b\u3048\u3070\u3001\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u30af\u30ea\u30a2\u306f\u4e00\u898b\u91cd\u8981\u306a\u64cd\u4f5c\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u304c\u3001\u672c\u756a\u30b5\u30a4\u30c8\u3067\u4f5c\u696d\u3057\u3066\u3044\u308b\u5834\u5408\u3001\u30ef\u30f3\u30af\u30ea\u30c3\u30af\u3067\u306f\u5b9f\u884c\u3059\u308b\u306e\u306b\u306f\u62b5\u6297\u304c\u3042\u308b\u306f\u305a\u3002\u305d\u3053\u3067\u5f79\u7acb\u3064\u306e\u304cSlack\u306e\u30e2\u30fc\u30c0\u30eb\uff08\u30c0\u30a4\u30a2\u30ed\u30b0\uff09\u306e\u8868\u793a\u3067\u3059\u3002<\/p>\n<p><code>clear_cache_button<\/code>\u304c\u30af\u30ea\u30c3\u30af\u3055\u308c\u305f\u3089\u5373\u5ea7\u306b\u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u30af\u30ea\u30a2\u3059\u308b\u306e\u3067\u306f\u306a\u304f\u3001\u78ba\u8a8d\u7528\u306e\u30e2\u30fc\u30c0\u30eb\u3092\u8868\u793a\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">app.action('clear_cache_button', async ({ body, ack, context }) =&gt; {\n  await ack();\n  \n  const environmentId = body.actions[0].value;\n  \n  \/\/ \u78ba\u8a8d\u30c0\u30a4\u30a2\u30ed\u30b0\u3092\u958b\u304f\n  try {\n    await web.views.open({\n      trigger_id: body.trigger_id,\n      view: {\n        type: 'modal',\n        callback_id: 'clear_cache_confirmation',\n        private_metadata: environmentId,\n        title: {\n          type: 'plain_text',\n          text: 'Confirm Cache Clearing'\n        },\n        blocks: [\n          {\n            type: 'section',\n            text: {\n              type: 'mrkdwn',\n              text: `\u74b0\u5883 ${environmentId} \u306e\u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u30af\u30ea\u30a2\u3057\u307e\u3059\u304b\uff1f`\n            }\n          }\n        ],\n        submit: {\n          type: 'plain_text',\n          text: '\u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u30af\u30ea\u30a2'\n        },\n        close: {\n          type: 'plain_text',\n          text: '\u30ad\u30e3\u30f3\u30bb\u30eb'\n        }\n      }\n    });\n  } catch (error) {\n    console.error('\u78ba\u8a8d\u30c0\u30a4\u30a2\u30ed\u30b0\u3092\u958b\u304f\u969b\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f:', error);\n  }\n});<\/code><\/pre>\n<p>\u4e0a\u306e\u30b3\u30fc\u30c9\u3067\u306f\u3001<code>web.views.open()<\/code>\u3092\u4f7f\u7528\u3057\u3066\u3001\u660e\u78ba\u306a\u30bf\u30a4\u30c8\u30eb\u3001\u8b66\u544a\u30e1\u30c3\u30bb\u30fc\u30b8\u3001\u304a\u3088\u3073\u300c<strong>\u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u30af\u30ea\u30a2<\/strong>\u300d\u3068\u300c<strong>\u30ad\u30e3\u30f3\u30bb\u30eb<\/strong>\u300d\u306e2\u3064\u306e\u30dc\u30bf\u30f3\u3092\u6301\u3064\u30e2\u30fc\u30c0\u30eb\u3092\u8d77\u52d5\u3057\u3001<code>private_metadata<\/code>\u306b<code>environmentId<\/code>\u3092\u4fdd\u5b58\u3057\u3066\u3001\u300c<strong>\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u30af\u30ea\u30a2<\/strong>\u300d\u3092\u30af\u30ea\u30c3\u30af\u3057\u305f\u969b\u306b\u8868\u793a\u3067\u304d\u308b\u3088\u3046\u306b\u306a\u3063\u3066\u3044\u307e\u3059\u3002<\/p>\n<p>\u30e2\u30fc\u30c0\u30eb\u3067\u300c<strong>\u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u30af\u30ea\u30a2<\/strong>\u300d\u3092\u30af\u30ea\u30c3\u30af\u3059\u308b\u3068\u3001Slack\u304c<code>view_submission<\/code>\u30a4\u30d9\u30f3\u30c8\u3092\u9001\u4fe1\u3057\u307e\u3059\u3002\u3053\u306e\u30a4\u30d9\u30f3\u30c8\u3092\u51e6\u7406\u3057\u3001\u64cd\u4f5c\u3092\u5b9f\u884c\u3059\u308b\u65b9\u6cd5\u306f\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">\/\/ \u78ba\u8a8d\u30c0\u30a4\u30a2\u30ed\u30b0\u306e\u5165\u529b\u3092\u51e6\u7406\napp.view('clear_cache_confirmation', async ({ ack, body, view }) =&gt; {\n  await ack();\n  \n  const environmentId = view.private_metadata;\n  const userId = body.user.id;\n  \n  \/\/ \u5bfe\u5fdc\u3059\u308b\u30e6\u30fc\u30b6\u30fc\u306eDM\u30c1\u30e3\u30f3\u30cd\u30eb\u3092\u691c\u7d22\n  const result = await web.conversations.open({\n    users: userId\n  });\n  \n  const channel = result.channel.id;\n  \n  await web.chat.postMessage({\n    channel,\n    text: `\ud83d\udd04 \u74b0\u5883 ${environmentId} \u306e\u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u30af\u30ea\u30a2\u3057\u3066\u3044\u307e\u3059...`\n  });\n  \n  try {\n    \/\/ Kinsta API\u3092\u547c\u3073\u51fa\u3057\u3066\u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u30af\u30ea\u30a2\n    const response = await kinstaRequest(\n      `\/sites\/environments\/${environmentId}\/clear-cache`,\n      'POST'\n    );\n    \n    if (response && response.operation_id) {\n      await web.chat.postMessage({\n        channel,\n        text: `\u2705 \u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u30af\u30ea\u30a2\u64cd\u4f5c\u3092\u958b\u59cb\u3002\u30aa\u30da\u30ec\u30fc\u30b7\u30e7\u30f3ID: ${response.operation_id}`\n      });\n    } else {\n      await web.chat.postMessage({\n        channel,\n        text: '\u26a0\ufe0f \u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u30af\u30ea\u30a2\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u9001\u4fe1\u3057\u307e\u3057\u305f\u304c\u3001\u30aa\u30da\u30ec\u30fc\u30b7\u30e7\u30f3ID\u304c\u8fd4\u3055\u308c\u307e\u305b\u3093\u3067\u3057\u305f\u3002'\n      });\n    }\n  } catch (error) {\n    console.error('\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u30af\u30ea\u30a2\u30a8\u30e9\u30fc: ', error);\n    await web.chat.postMessage({\n      channel,\n      text: `\u274c \u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u30af\u30ea\u30a2\u30a8\u30e9\u30fc: ${error.message}`\n    });\n  }\n});<\/code><\/pre>\n<p>\u4e0a\u306e\u30b3\u30fc\u30c9\u3067\u306f\u3001\u78ba\u8a8d\u30c0\u30a4\u30a2\u30ed\u30b0\u3067\u64cd\u4f5c\u3092\u78ba\u5b9a\u3057\u305f\u5f8c\u3001<code>private_metadata<\/code>\u304b\u3089<code>environmentId<\/code>\u3092\u53d6\u5f97\u3057\u3001<code>web.conversations.open()<\/code>\u3092\u4f7f\u7528\u3057\u3066\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8DM\u3092\u958b\u3044\u3066\u3001\u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u30af\u30ea\u30a2\u3059\u308b\u305f\u3081\u306bAPI\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u5b9f\u884c\u3002\u305d\u306e\u7d50\u679c\u306b\u5fdc\u3058\u3066\u5b8c\u4e86\u307e\u305f\u306f\u30a8\u30e9\u30fc\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u8868\u793a\u3057\u307e\u3059\u3002<\/p>\n<h3>\u30d7\u30ed\u30b0\u30ec\u30b9\u30d0\u30fc\u306e\u8ffd\u52a0<\/h3>\n<p>Slack\u306e\u30b3\u30de\u30f3\u30c9\u306e\u4e2d\u306b\u306f\u3001\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u30af\u30ea\u30a2\u3084\u30b9\u30c6\u30fc\u30bf\u30b9\u306e\u78ba\u8a8d\u306a\u3069\u3001\u5373\u5ea7\u306b\u5b9f\u884c\u3067\u304d\u308b\u3082\u306e\u3082\u3042\u308a\u307e\u3059\u304c\u3001\u305d\u3046\u3067\u306f\u306a\u3044\u3082\u306e\u3082\u3042\u308a\u307e\u3059\u3002<\/p>\n<p>\u4f8b\u3048\u3070\u3001\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u306e\u4f5c\u6210\u3084\u30d5\u30a1\u30a4\u30eb\u306e\u30c7\u30d7\u30ed\u30a4\u306b\u306f\u6570\u79d2\u304b\u3089\u6570\u5206\u304b\u304b\u308b\u3053\u3068\u304c\u3042\u308a\u307e\u3059\u3002\u305d\u306e\u9593\u306b\u30dc\u30c3\u30c8\u304b\u3089\u306e\u5fdc\u7b54\u304c\u306a\u3051\u308c\u3070\u3001\u6b63\u5e38\u306b\u51e6\u7406\u304c\u884c\u308f\u308c\u3066\u3044\u306a\u3044\u3068\u52d8\u9055\u3044\u3059\u308b\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002<\/p>\n<p>Slack\u306b\u306f\u7d44\u307f\u8fbc\u307f\u306e\u30d7\u30ed\u30b0\u30ec\u30b9\u30d0\u30fc\u306f\u3042\u308a\u307e\u305b\u3093\u304c\u3001\u3061\u3087\u3063\u3068\u3057\u305f\u5de5\u592b\u3067\u30d7\u30ed\u30b0\u30ec\u30b9\u30d0\u30fc\u64ec\u304d\u3092\u4f5c\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002\u4ee5\u4e0b\u306fBlock Kit\u3092\u4f7f\u3063\u3066\u8996\u899a\u7684\u306a\u30d7\u30ed\u30b0\u30ec\u30b9\u30d0\u30fc\u3067\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u66f4\u65b0\u3059\u308b\u30d8\u30eb\u30d1\u30fc\u95a2\u6570\u3067\u3059\u3002<\/p>\n<pre><code class=\"language-js\">async function updateProgress(channel, messageTs, text, percentage) {\n  \/\/ \u30d7\u30ed\u30b0\u30ec\u30b9\u30d0\u30fc\u3092\u4f5c\u6210\n  const barLength = 20;\n  const filledLength = Math.round(barLength * (percentage \/ 100));\n  const bar = '\u2588'.repeat(filledLength) + '\u2591'.repeat(barLength - filledLength);\n  \n  await web.chat.update({\n    channel,\n    ts: messageTs,\n    text: `${text} [${percentage}%]`,\n    blocks: [\n      {\n        type: 'section',\n        text: {\n          type: 'mrkdwn',\n          text: `${text} [${percentage}%]n`${bar}``\n        }\n      }\n    ]\n  });\n}<\/code><\/pre>\n<p>\u3053\u308c\u3092<code>\/create_backup<\/code>\u30b3\u30de\u30f3\u30c9\u306b\u7d44\u307f\u8fbc\u3093\u3067\u307f\u307e\u3059\u3002\u64cd\u4f5c\u5168\u4f53\u304c\u5b8c\u4e86\u3059\u308b\u306e\u3092\u305f\u3060\u5f85\u3064\u306e\u3067\u306f\u306a\u304f\u3001\u9032\u6357\u3092\u8868\u793a\u3059\u308b\u3088\u3046\u306b\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">app.command('\/create_backup', async ({ command, ack, say }) =&gt; {\n  await ack();\n  \n  const args = command.text.split(' ');\n  const environmentId = args[0];\n  const tag = args.length &gt; 1 ? args.slice(1).join(' ') : `\u624b\u52d5\u30d0\u30c3\u30af\u30a2\u30c3\u30d7 ${new Date().toISOString()}`;\n  \n  if (!environmentId) {\n    await say('\u74b0\u5883ID\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u69cb\u6587: \/create_backup [environment-id] [optional-tag]');\n    return;\n  }\n  \n  \/\/ \u6700\u521d\u306e\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u6295\u7a3f\u3057\u3001\u66f4\u65b0\u306e\u305f\u3081\u306e\u30bf\u30a4\u30e0\u30b9\u30bf\u30f3\u30d7\u3092\u53d6\u5f97\n  const initial = await say('\ud83d\udd04 \u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u3092\u958b\u59cb\u3057\u307e\u3059...');\n  const messageTs = initial.ts;\n  \n  try {\n    \/\/ \u9032\u6357\u72b6\u6cc1\u309210%\u306b\u66f4\u65b0\n    await updateProgress(command.channel_id, messageTs, '\ud83d\udd04 \u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u3092\u4f5c\u6210\u4e2d\u3067\u3059...', 10);\n    \n    \/\/ \u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u306e\u4f5c\u6210\u306bKinsta API\u3092\u547c\u3073\u51fa\u3059\n    const response = await kinstaRequest(\n      `\/sites\/environments\/${environmentId}\/manual-backups`,\n      'POST',\n      { tag }\n    );\n    \n    if (response && response.operation_id) {\n      await updateProgress(command.channel_id, messageTs, '\ud83d\udd04 \u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u4e2d\u3067\u3059...', 30);\n      \n      \/\/ \u7a3c\u50cd\u72b6\u6cc1\u306e\u30dd\u30fc\u30ea\u30f3\u30b0\n      let completed = false;\n      let percentage = 30;\n      \n      while (!completed && percentage  setTimeout(resolve, 3000));\n        \n        \/\/ \u52d5\u4f5c\u72b6\u6cc1\u306e\u78ba\u8a8d\n        const statusResponse = await kinstaRequest(`\/operations\/${response.operation_id}`);\n        \n        if (statusResponse && statusResponse.operation) {\n          const operation = statusResponse.operation;\n          \n          if (operation.status === 'completed') {\n            completed = true;\n            percentage = 100;\n          } else if (operation.status === 'failed') {\n            await web.chat.update({\n              channel: command.channel_id,\n              ts: messageTs,\n              text: `\u274c \u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002\u30a8\u30e9\u30fc: ${operation.error || '\u4e0d\u660e\u306a\u30a8\u30e9\u30fc'}`\n            });\n            return;\n          } else {\n            \/\/ \u9032\u6357\u3092\u66f4\u65b0\n            percentage += 10;\n            if (percentage &gt; 95) percentage = 95;\n            \n            await updateProgress(\n              command.channel_id, \n              messageTs, \n              '\ud83d\udd04 \u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u4e2d\u3067\u3059...', \n              percentage\n            );\n          }\n        }\n      }\n      \n      \/\/ \u6700\u7d42\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\n      await web.chat.update({\n        channel: command.channel_id,\n        ts: messageTs,\n        text: `\u2705 \u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u304c\u5b8c\u4e86\u3057\u307e\u3057\u305f`,\n        blocks: [\n          {\n            type: 'section',\n            text: {\n              type: 'mrkdwn',\n              text: `\u2705 \u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u304c\u6b63\u5e38\u306b\u5b8c\u4e86\u3057\u307e\u3057\u305f\u3002\u30bf\u30b0: ${tag} \u30aa\u30da\u30ec\u30fc\u30b7\u30e7\u30f3ID: ${response.operation_id}`\n            }\n          }\n        ]\n      });\n    } else {\n      await web.chat.update({\n        channel: command.channel_id,\n        ts: messageTs,\n        text: '\u26a0\ufe0f \u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u9001\u4fe1\u3057\u307e\u3057\u305f\u304c\u3001\u30aa\u30da\u30ec\u30fc\u30b7\u30e7\u30f3ID\u304c\u8fd4\u3055\u308c\u307e\u305b\u3093\u3067\u3057\u305f\u3002'\n      });\n    }\n  } catch (error) {\n    console.error('\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u4f5c\u6210\u30a8\u30e9\u30fc:', error);\n    \n    await web.chat.update({\n      channel: command.channel_id,\n      ts: messageTs,\n      text: `\u274c \u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u4f5c\u6210\u30a8\u30e9\u30fc: ${error.message}`\n    });\n  }\n});<\/code><\/pre>\n<h3>\u6210\u529f\u307e\u305f\u306f\u5931\u6557\u306e\u901a\u77e5<\/h3>\n<p>\u30dc\u30c3\u30c8\u306f\u300c\u6210\u529f\u2705\u300d\u3084\u300c\u5931\u6557\u274c\u300d\u306e\u3088\u3046\u306a\u30d7\u30ec\u30fc\u30f3\u30c6\u30ad\u30b9\u30c8\u3092\u8fd4\u3059\u306e\u304c\u4e00\u822c\u7684\u3067\u3001\u3053\u308c\u3067\u3082\u6a5f\u80fd\u306f\u3057\u307e\u3059\u304c\u3001\u3053\u308c\u3060\u3051\u3067\u306f\u6210\u529f\u3057\u305f\u7406\u7531\u3084\u5931\u6557\u3057\u305f\u7406\u7531\u306f\u308f\u304b\u308a\u307e\u305b\u3093\u3002<\/p>\n<p>\u6210\u529f\u30e1\u30c3\u30bb\u30fc\u30b8\u3068\u30a8\u30e9\u30fc\u30e1\u30c3\u30bb\u30fc\u30b8\u306b\u9069\u5207\u306a\u66f8\u5f0f\u3092\u8a2d\u5b9a\u3057\u3001\u6709\u7528\u306a\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3001\u63d0\u6848\u3001\u66f8\u5f0f\u3092\u8ffd\u52a0\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n<p>\u4ee5\u4e0b\u306e\u30e6\u30fc\u30c6\u30a3\u30ea\u30c6\u30a3\u3092<code>utils.js<\/code>\u306b\u8ffd\u52a0\u3057\u3066\u3001\u3059\u3079\u3066\u306e\u30b3\u30de\u30f3\u30c9\u3067\u518d\u5229\u7528\u3067\u304d\u308b\u3088\u3046\u306b\u3057\u307e\u3057\u3087\u3046\u3002<\/p>\n<pre><code class=\"language-js\">function formatSuccessMessage(title, details = []) {\n  let message = `\u2705 *${title}*nn`;\n  \n  if (details.length &gt; 0) {\n    details.forEach(detail =&gt; {\n      message += `\u2022 ${detail.label}: ${detail.value}n`;\n    });\n  }\n  \n  return message;\n}\n\nfunction formatErrorMessage(title, error, suggestions = []) {\n  let message = `\u274c *${title}*nn`;\n  message += `*\u30a8\u30e9\u30fc:* ${error}nn`;\n  \n  if (suggestions.length &gt; 0) {\n    message += '*\u63d0\u6848:*n';\n    suggestions.forEach(suggestion =&gt; {\n      message += `\u2022 ${suggestion}n`;\n    });\n  }\n  \n  return message;\n}\n\nmodule.exports = {\n  connectToSite,\n  logCommand,\n  formatSuccessMessage,\n  formatErrorMessage\n};<\/code><\/pre>\n<p>\u3053\u308c\u3089\u306e\u95a2\u6570\u306f\u3001\u69cb\u9020\u5316\u3055\u308c\u305f\u5165\u529b\u3092\u53d7\u3051\u53d6\u3063\u3066\u3001Slack\u3067\u898b\u3084\u3059\u3044\u5f62\u5f0f\u306b\u5909\u63db\u3057\u307e\u3059\u3002\u7d75\u6587\u5b57\u3084\u30e9\u30d9\u30eb\u3001\u6539\u884c\u306b\u3088\u308a\u3001\u3084\u308a\u53d6\u308a\u306e\u591a\u3044\u30b9\u30ec\u30c3\u30c9\u306e\u4e2d\u3067\u3082\u30d1\u30c3\u3068\u5185\u5bb9\u3092\u628a\u63e1\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002\u30b3\u30de\u30f3\u30c9\u30cf\u30f3\u30c9\u30e9\u306e\u5185\u90e8\u306f\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u306a\u308a\u307e\u3059\u3002\u4f8b\u3068\u3057\u3066<code>\/clear_cache<\/code>\u3092\u898b\u3066\u307f\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">app.command('\/clear_cache', async ({ command, ack, say }) =&gt; {\n  await ack();\n  \n  const environmentId = command.text.trim();\n  \n  if (!environmentId) {\n    await say('\u74b0\u5883ID\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u69cb\u6587: \/clear_cache [environment-id]');\n    return;\n  }\n  \n  try {\n    await say('\ud83d\udd04 Processing...');\n    \n    \/\/ Kinsta API\u3092\u547c\u3073\u51fa\u3057\u3066\u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u30af\u30ea\u30a2\n    const response = await kinstaRequest(\n      `\/sites\/environments\/${environmentId}\/clear-cache`,\n      'POST'\n    );\n    \n    if (response && response.operation_id) {\n      const { formatSuccessMessage } = require('.\/utils');\n      \n      await say(formatSuccessMessage('Cache Clearing Started', [\n        { label: '\u74b0\u5883ID', value: ``${environmentId}`` },\n        { label: '\u30aa\u30da\u30ec\u30fc\u30b7\u30e7\u30f3ID', value: ``${response.operation_id}`` },\n        { label: '\u30b9\u30c6\u30fc\u30bf\u30b9', value: 'In Progress' }\n      ]));\n    } else {\n      const { formatErrorMessage } = require('.\/utils');\n      \n      await say(formatErrorMessage(\n        '\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u30af\u30ea\u30a2\u30a8\u30e9\u30fc',\n        '\u30aa\u30da\u30ec\u30fc\u30b7\u30e7\u30f3ID\u304c\u8fd4\u3055\u308c\u307e\u305b\u3093\u3067\u3057\u305f',\n        [\n          '\u74b0\u5883ID\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044',\n          'API\u8a8d\u8a3c\u60c5\u5831\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044',\n          '\u5f8c\u304b\u3089\u518d\u8a66\u884c\u3057\u3066\u304f\u3060\u3055\u3044'\n        ]\n      ));\n    }\n  } catch (error) {\n    console.error('Cache clearing error:', error);\n    \n    const { formatErrorMessage } = require('.\/utils');\n    \n    await say(formatErrorMessage(\n      'Cache Clearing Error',\n      error.message,\n      [\n        '\u74b0\u5883ID\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044',\n        'API\u8a8d\u8a3c\u60c5\u5831\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044',\n        '\u5f8c\u304b\u3089\u518d\u8a66\u884c\u3057\u3066\u304f\u3060\u3055\u3044'\n      ]\n    ));\n  }\n});<\/code><\/pre>\n<h2>\u8a2d\u5b9a\u6e08\u307f\u30b8\u30e7\u30d6\u3067WordPress\u306e\u30bf\u30b9\u30af\u3092\u81ea\u52d5\u5316<\/h2>\n<p>\u3053\u3053\u307e\u3067\u7d39\u4ecb\u3057\u305f\u64cd\u4f5c\u306f\u3001\u660e\u793a\u7684\u306b\u30b3\u30de\u30f3\u30c9\u3092\u30c8\u30ea\u30ac\u30fc\u3059\u308b\u3053\u3068\u304c\u524d\u63d0\u3067\u3059\u304c\u3001\u30dc\u30c3\u30c8\u304c\u6bce\u6669\u30b5\u30a4\u30c8\u3092\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u3057\u3066\u304f\u308c\u305f\u308a\u3001\u6bce\u671d\u59cb\u696d\u524d\u306b\u30b5\u30a4\u30c8\u304c\u30c0\u30a6\u30f3\u3057\u3066\u3044\u306a\u3044\u304b\u3092\u78ba\u8a8d\u3057\u305f\u308a\u3057\u3066\u304f\u308c\u308b\u3068\u975e\u5e38\u306b\u4fbf\u5229\u3067\u3059\u3002<\/p>\n<p><a href=\"https:\/\/www.npmjs.com\/package\/node-schedule\" target=\"_blank\" rel=\"noopener noreferrer\">node-schedule<\/a>\u30e9\u30a4\u30d6\u30e9\u30ea\u3092\u4f7f\u3063\u3066\u3001cron\u5f0f\u306b\u57fa\u3065\u3044\u3066\u30bf\u30b9\u30af\u3092\u5b9f\u884c\u3059\u308b\u3053\u3068\u3082\u53ef\u80fd\u3067\u3059\u3002\u307e\u305a\u306fnode-schedule\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-bash\">npm install node-schedule<\/code><\/pre>\n<p><code>app.js<\/code>\u306e\u5192\u982d\u3067\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u8a2d\u5b9a\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">const schedule = require('node-schedule');<\/code><\/pre>\n<p>\u307e\u305f\u3001\u8a2d\u5b9a\u6e08\u307f\u306e\u30bf\u30b9\u30af\u3092\u30ea\u30b9\u30c8\u30a2\u30c3\u30d7\u3057\u305f\u308a\u3001\u5f8c\u304b\u3089\u53d6\u308a\u6d88\u3057\u305f\u308a\u3067\u304d\u308b\u3088\u3046\u3001\u6709\u52b9\u306a\u8a2d\u5b9a\u6e08\u307f\u30bf\u30b9\u30af\u3092\u8ffd\u8de1\u3059\u308b\u65b9\u6cd5\u3082\u5fc5\u8981\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">const scheduledJobs = {};<\/code><\/pre>\n<h3>\u8a2d\u5b9a\u6e08\u307f\u30bf\u30b9\u30af\u30b3\u30de\u30f3\u30c9\u306e\u4f5c\u6210<\/h3>\n<p>\u30bf\u30b9\u30af\u306e\u7a2e\u985e\uff08<code>backup<\/code>\u3001<code>clear_cache<\/code>\u3001<code>status_check<\/code>\uff09\u3001\u74b0\u5883ID\u3001cron\u5f0f\u3092\u53d7\u3051\u53d6\u308b\u57fa\u672c\u7684\u306a<code>\/schedule_task<\/code>\u30b3\u30de\u30f3\u30c9\u304b\u3089\u59cb\u3081\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-bash\">\/schedule_task backup 12345 0 0 * * *<\/code><\/pre>\n<p>\u4ee5\u4e0b\u306e\u30b3\u30de\u30f3\u30c9\u306f\u6bce\u65e50\u6642\u306b\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u3092\u5b9f\u884c\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">app.command('\/schedule_task', async ({ command, ack, say }) =&gt; {\n  await ack();\n\n  const args = command.text.split(' ');\n  if (args.length  {\n      console.log(`\u74b0\u5883 ${environmentId} \u306b\u5bfe\u3057\u3066\u8a2d\u5b9a\u6e08\u307f\u306e ${taskType} \u3092\u5b9f\u884c\u4e2d`);\n\n      try {\n        switch (taskType) {\n          case 'backup':\n            await kinstaRequest(`\/sites\/environments\/${environmentId}\/manual-backups`, 'POST', {\n              tag: `\u8a2d\u5b9a\u6e08\u307f\u30d0\u30c3\u30af\u30a2\u30c3\u30d7 ${new Date().toISOString()}`\n            });\n            break;\n          case 'clear_cache':\n            await kinstaRequest(`\/sites\/environments\/${environmentId}\/clear-cache`, 'POST');\n            break;\n          case 'status_check':\n            const response = await kinstaRequest(`\/sites\/environments\/${environmentId}`);\n            const env = response?.site?.environments?.[0];\n            if (env) {\n              console.log(`Status: ${env.display_name} is ${env.is_blocked ? 'blocked' : 'running'}`);\n            }\n            break;\n        }\n      } catch (err) {\n        console.error(`Scheduled ${taskType} failed for ${environmentId}:`, err.message);\n      }\n    });\n\n    scheduledJobs[jobId] = {\n      job,\n      taskType,\n      environmentId,\n      cronSchedule,\n      userId: command.user_id,\n      createdAt: new Date().toISOString()\n    };\n\n    await say(`\u2705 \u8a2d\u5b9a\u6e08\u307f\u30bf\u30b9\u30af\u304c\u4f5c\u6210\u3055\u308c\u307e\u3057\u305f\n*\u30bf\u30b9\u30af:* ${taskType}\n*\u74b0\u5883:* `${environmentId}`\n*cron:* `${cronSchedule}`\n*\u30b8\u30e7\u30d6ID:* `${jobId}`\n\nTo cancel this task, run `\/cancel_task ${jobId}``);\n  } catch (err) {\n    console.error('\u8a2d\u5b9a\u6e08\u307f\u30bf\u30b9\u30af\u306e\u4f5c\u6210\u30a8\u30e9\u30fc:', err);\n    await say(`\u274c \u8a2d\u5b9a\u6e08\u307f\u30bf\u30b9\u30af\u306e\u4f5c\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f: ${err.message}`);\n  }\n});<\/code><\/pre>\n<h3>\u8a2d\u5b9a\u6e08\u307f\u30bf\u30b9\u30af\u306e\u53d6\u308a\u6d88\u3057<\/h3>\n<p>\u4f55\u304b\u5909\u66f4\u304c\u3042\u3063\u305f\u308a\u3001\u30bf\u30b9\u30af\u304c\u4e0d\u8981\u306b\u306a\u3063\u305f\u308a\u3057\u305f\u5834\u5408\u306f\u3001\u4ee5\u4e0b\u306e\u30b3\u30de\u30f3\u30c9\u3067\u30bf\u30b9\u30af\u3092\u53d6\u308a\u6d88\u3059\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-bash\">\/cancel_task<\/code><\/pre>\n<p>\u3053\u306e\u5b9f\u88c5\u306f\u4ee5\u4e0b\u306e\u3068\u304a\u308a\u3067\u3059\u3002<\/p>\n<pre><code class=\"language-js\">app.command('\/cancel_task', async ({ command, ack, say }) =&gt; {\n  await ack();\n\n  const jobId = command.text.trim();\n\n  if (!scheduledJobs[jobId]) {\n    await say(`\u26a0\ufe0f ID ${jobId} \u3067\u30bf\u30b9\u30af\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f`);\n    return;\n  }\n\n  scheduledJobs[jobId].job.cancel();\n  delete scheduledJobs[jobId];\n\n  await say(`\u2705 \u30bf\u30b9\u30af ${jobId} \u3092\u53d6\u308a\u6d88\u3057\u307e\u3057\u305f`);\n});<\/code><\/pre>\n<h3>\u8a2d\u5b9a\u6e08\u307f\u30bf\u30b9\u30af\u306e\u4e00\u89a7\u8868\u793a<\/h3>\n<p>\u8a2d\u5b9a\u6e08\u307f\u306e\u30bf\u30b9\u30af\u3092\u4e00\u89a7\u8868\u793a\u3059\u308b\u3053\u3068\u3082\u53ef\u80fd\u3067\u3059\u3002<\/p>\n<pre><code class=\"language-js\">app.command('\/list_tasks', async ({ command, ack, say }) =&gt; {\n  await ack();\n\n  const tasks = Object.entries(scheduledJobs);\n  if (tasks.length === 0) {\n    await say('\u8a2d\u5b9a\u6e08\u307f\u30bf\u30b9\u30af\u306f\u3042\u308a\u307e\u305b\u3093');\n    return;\n  }\n\n  let message = '*\u8a2d\u5b9a\u6e08\u307f\u30bf\u30b9\u30af:*nn';\n\n  for (const [jobId, job] of tasks) {\n    message += `\u2022 *\u30b8\u30e7\u30d6ID:* `${jobId}`n`;\n    message += `  - \u30bf\u30b9\u30af: ${job.taskType}n`;\n    message += `  - \u74b0\u5883: `${job.environmentId}`n`;\n    message += `  - cron: `${job.cronSchedule}`n`;\n    message += `  - \u4f5c\u6210\u8005: nn`;\n  }\n\n  message += '_Use `\/cancel_task [job_id]` to cancel a task._';\n  await say(message);\n});<\/code><\/pre>\n<p>\u3053\u308c\u306b\u3088\u308a\u3001Slackbot\u306b\u3055\u3089\u306a\u308b\u81ea\u5f8b\u6027\u3092\u4e0e\u3048\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u3001\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u30af\u30ea\u30a2\u3001\u30b9\u30c6\u30fc\u30bf\u30b9\u306e\u78ba\u8a8d\u304c\u5b8c\u5168\u306b\u81ea\u52d5\u5316\u3055\u308c\u3001\u30b9\u30b1\u30b8\u30e5\u30fc\u30eb\u901a\u308a\u306b\u5b9f\u884c\u3055\u308c\u307e\u3059\u3002<\/p>\n<h2>\u5b9a\u671f\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9<\/h2>\n<p>\u6bce\u9031\u306e\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u3084\u65e5\u66dc\u65e5\u306e\u591c\u306b\u884c\u3046\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u30af\u30ea\u30a2\u306a\u3069\u3001\u5b9a\u671f\u7684\u306a\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u30bf\u30b9\u30af\u3092\u5b9f\u884c\u3059\u308b\u306b\u306f\u3001\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u30a6\u30a3\u30f3\u30c9\u30a6\u304c\u5f79\u306b\u7acb\u3061\u307e\u3059\u3002<\/p>\n<p>\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u30a6\u30a3\u30f3\u30c9\u30a6\u3068\u306f\u3001\u30dc\u30c3\u30c8\u304c\u4e8b\u524d\u306b\u5b9a\u7fa9\u3057\u305f\u4ee5\u4e0b\u306e\u3088\u3046\u306a\u30bf\u30b9\u30af\u3092\u5b9f\u884c\u3059\u308b\u6642\u9593\u5e2f\u3092\u610f\u5473\u3057\u307e\u3059\u3002<\/p>\n<ul>\n<li>\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u306e\u4f5c\u6210<\/li>\n<li>\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u30af\u30ea\u30a2<\/li>\n<li>\u958b\u59cb\u901a\u77e5\u3068\u5b8c\u4e86\u901a\u77e5\u306e\u9001\u4fe1<\/li>\n<\/ul>\n<p>\u66f8\u5f0f\u306f\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u30b7\u30f3\u30d7\u30eb\u3067\u3059\u3002<\/p>\n<pre><code class=\"language-bash\">\/maintenance_window [environment_id] [day_of_week] [hour] [duration_hours]<\/code><\/pre>\n<p>\u4f8b\u3048\u3070\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-bash\">\/maintenance_window 12345 Sunday 2 3<\/code><\/pre>\n<p>\u4e0a\u306e\u30b3\u30fc\u30c9\u306f\u3001\u6bce\u9031\u65e5\u66dc\u65e5\u306e\u5348\u524d2\u6642\u304b\u30893\u6642\u9593\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u30bf\u30b9\u30af\u304c\u5b9f\u884c\u3055\u308c\u308b\u4f8b\u3067\u3059\u3002\u5b9f\u88c5\u306f\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">\/\/ \u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u30a6\u30a3\u30f3\u30c9\u30a6\u3092\u4f5c\u6210\u3059\u308b\u30b3\u30de\u30f3\u30c9\u3092\u8ffd\u52a0\napp.command('\/maintenance_window', async ({ command, ack, say }) =&gt; {\n  await ack();\n  \n  \/\/ \u6307\u5b9a\u30d5\u30a9\u30fc\u30de\u30c3\u30c8: environment_id day_of_week hour duration\n  \/\/ \u4f8b: \/maintenance_window 12345 Sunday 2 3\n  const args = command.text.split(' ');\n  \n  if (args.length &lt; 4) {\n    await say('\u5fc5\u8981\u306a\u30d1\u30e9\u30e1\u30fc\u30bf\u3092\u3059\u3079\u3066\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u69cb\u6587: `\/maintenance_window [environment_id] [day_of_week] [hour] [duration_hours]`');\n    return;\n  }\n  \n  const [environmentId, dayOfWeek, hour, duration] = args;\n  \n  \/\/ \u5165\u529b\u3092\u691c\u8a3c\n  const validDays = ['\u65e5\u66dc\u65e5', '\u6708\u66dc\u65e5', '\u706b\u66dc\u65e5', '\u6c34\u66dc\u65e5', '\u6728\u66dc\u65e5', '\u91d1\u66dc\u65e5', '\u571f\u66dc\u65e5'];\n  if (!validDays.includes(dayOfWeek)) {\n    await say(`\u66dc\u65e5\u304c\u7121\u52b9\u3067\u3059\u3002\u6b21\u304b\u3089\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044: ${validDays.join(', ')}`);\n    return;\n  }\n  \n  const hourInt = parseInt(hour, 10);\n  if (isNaN(hourInt) || hourInt  23) {\n    await say('\u6642\u9593\u306f0\u304b\u308923\u307e\u3067\u306e\u6570\u5b57\u3067\u3042\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002');\n    return;\n  }\n  \n  const durationInt = parseInt(duration, 10);\n  if (isNaN(durationInt) || durationInt  12) {\n    await say('\u6240\u8981\u6642\u9593\u306f1\u304b\u308912\u307e\u3067\u306e\u6570\u5b57\u3067\u3042\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002');\n    return;\n  }\n  \n  \/\/ \u66dc\u65e5\u3092cron\u5f62\u5f0f\u306b\u5909\u63db\n  const dayMap = {\n    '\u65e5\u66dc\u65e5': 0,\n    '\u6708\u66dc\u65e5': 1,\n    '\u706b\u66dc\u65e5': 2,\n    '\u6c34\u66dc\u65e5': 3,\n    '\u6728\u66dc\u65e5': 4,\n    '\u91d1\u66dc\u65e5': 5,\n    '\u571f\u66dc\u65e5': 6\n  };\n  \n  const cronDay = dayMap[dayOfWeek];\n  \n  \/\/ \u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u30a6\u30a3\u30f3\u30c9\u30a6\u958b\u59cb\u306e\u305f\u3081\u306ecron\u30b9\u30b1\u30b8\u30e5\u30fc\u30eb\u3092\u4f5c\u6210\n  const cronSchedule = `0 ${hourInt} * * ${cronDay}`;\n  \n  \/\/ \u4e00\u610f\u306e\u30b8\u30e7\u30d6ID\u3092\u751f\u6210\n  const jobId = `maintenance_${environmentId}_${Date.now()}`;\n  \n  \/\/ \u30b8\u30e7\u30d6\u3092\u8a2d\u5b9a\n  try {\n    const job = schedule.scheduleJob(cronSchedule, async function() {\n      \/\/ \u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u30a6\u30a3\u30f3\u30c9\u30a6\u3092\u958b\u59cb\n      await web.chat.postMessage({\n        channel: command.channel_id,\n        text: `\ud83d\udd27 *Maintenance Window Started*n*Environment:* `${environmentId}`n*Duration:* ${durationInt} hoursnn\u81ea\u52d5\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u30bf\u30b9\u30af\u3092\u5b9f\u884c\u4e2d\u3067\u3059\u3002`\n      });\n      \n      \/\/ \u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u30bf\u30b9\u30af\u306e\u5b9f\u884c\n      try {\n        \/\/ 1. \u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u306e\u4f5c\u6210\n        const backupResponse = await kinstaRequest(\n          `\/sites\/environments\/${environmentId}\/manual-backups`,\n          'POST',\n          { tag: `\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u7528\u30d0\u30c3\u30af\u30a2\u30c3\u30d7 ${new Date().toISOString()}` }\n        );\n        \n        if (backupResponse && backupResponse.operation_id) {\n          await web.chat.postMessage({\n            channel: command.channel_id,\n            text: `\u2705 \u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u7528\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u3092\u4f5c\u6210\u3057\u307e\u3057\u305f\u3002\u30aa\u30da\u30ec\u30fc\u30b7\u30e7\u30f3ID: `${backupResponse.operation_id}``\n          });\n        }\n        \n        \/\/ 2. \u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u30af\u30ea\u30a2\n        const cacheResponse = await kinstaRequest(\n          `\/sites\/environments\/${environmentId}\/clear-cache`,\n          'POST'\n        );\n        \n        if (cacheResponse && cacheResponse.operation_id) {\n          await web.chat.postMessage({\n            channel: command.channel_id,\n            text: `\u2705 \u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u30af\u30ea\u30a2\u3057\u307e\u3057\u305f\u3002\u30aa\u30da\u30ec\u30fc\u30b7\u30e7\u30f3ID: `${cacheResponse.operation_id}``\n          });\n        }\n        \n        \/\/ 3. \u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u7d42\u4e86\u901a\u77e5\u3092\u8a2d\u5b9a\n        setTimeout(async () =&gt; {\n          await web.chat.postMessage({\n            channel: command.channel_id,\n            text: `\u2705 *Maintenance Window Completed*n*Environment:* `${environmentId}`nn\u3059\u3079\u3066\u306e\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u30bf\u30b9\u30af\u304c\u5b8c\u4e86\u3057\u307e\u3057\u305f\u3002`\n          });\n        }, durationInt * 60 * 60 * 1000); \/\/ \u6642\u9593\u3092\u30df\u30ea\u79d2\u306b\u5909\u63db\n      } catch (error) {\n        console.error('\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u30bf\u30b9\u30af\u30a8\u30e9\u30fc:', error);\n        await web.chat.postMessage({\n          channel: command.channel_id,\n          text: `\u274c \u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f: ${error.message}`\n        });\n      }\n    });\n    \n    \/\/ \u5f8c\u3067\u53d6\u308a\u6d88\u305b\u308b\u3088\u3046\u306b\u30b8\u30e7\u30d6\u3092\u4fdd\u5b58\n    scheduledJobs[jobId] = {\n      job,\n      taskType: 'maintenance',\n      environmentId,\n      cronSchedule,\n      dayOfWeek,\n      hour: hourInt,\n      duration: durationInt,\n      userId: command.user_id,\n      createdAt: new Date().toISOString()\n    };\n    \n    await say(`\u2705 \u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u30a6\u30a3\u30f3\u30c9\u30a6\u3092\u8a2d\u5b9a\u3057\u307e\u3057\u305f\n*\u74b0\u5883:* `${environmentId}`\n*\u30b9\u30b1\u30b8\u30e5\u30fc\u30eb:* \u6bce\u9031 ${dayOfWeek} \u306e ${hourInt}:00\u304b\u3089 ${durationInt} \u6642\u9593\n*\u30b8\u30e7\u30d6ID:* `${jobId}`\n\nTo cancel this maintenance window, use `\/cancel_task ${jobId}``);\n  } catch (error) {\n    console.error('\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u30a6\u30a3\u30f3\u30c9\u30a6\u306e\u8a2d\u5b9a\u30a8\u30e9\u30fc:', error);\n    await say(`\u274c \u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u30a6\u30a3\u30f3\u30c9\u30a6\u306e\u8a2d\u5b9a\u30a8\u30e9\u30fc: ${error.message}`);\n  }\n});<\/code><\/pre>\n<h3>\u81ea\u52d5\u30ec\u30dd\u30fc\u30c8<\/h3>\n<p>\u6708\u66dc\u65e5\u306e\u671d\u3001WordPress\u30b5\u30a4\u30c8\u304c\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u3055\u308c\u305f\u304b\u3069\u3046\u304b\u3001\u3042\u308b\u3044\u306f\u4f55\u6642\u9593\u3082\u505c\u6b62\u3057\u3066\u3044\u306a\u3044\u304b\u3069\u3046\u304b\u306a\u3069\u3092\u5fc3\u914d\u3057\u306a\u304c\u3089\u76ee\u3092\u899a\u307e\u3059\u306e\u306f\u907f\u3051\u305f\u3044\u3082\u306e\u3067\u3059\u3002\u81ea\u52d5\u30ec\u30dd\u30fc\u30c8\u304c\u3042\u308c\u3070\u3001Slackbot\u306b\u3088\u308b\u30b9\u30b1\u30b8\u30e5\u30fc\u30eb\u306b\u6cbf\u3063\u305f\u30d0\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u306e\u6982\u8981\u3092\u7d20\u65e9\u304f\u78ba\u8a8d\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n<p>\u3053\u306e\u624b\u306e\u30ec\u30dd\u30fc\u30c8\u306f\u3001\u4ee5\u4e0b\u306e\u3088\u3046\u306a\u3053\u3068\u3092\u628a\u63e1\u3059\u308b\u306e\u306b\u9069\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n<ul>\n<li>\u73fe\u5728\u306e\u30b5\u30a4\u30c8\u30b9\u30c6\u30fc\u30bf\u30b9<\/li>\n<li>\u904e\u53bb7\u65e5\u9593\u306e\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u30a2\u30af\u30c6\u30a3\u30d3\u30c6\u30a3<\/li>\n<li>PHP\u30d0\u30fc\u30b8\u30e7\u30f3\u3068\u30d7\u30e9\u30a4\u30de\u30ea\u30c9\u30e1\u30a4\u30f3<\/li>\n<li>\u30d6\u30ed\u30c3\u30af\u3055\u308c\u305f\u74b0\u5883\u3084\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u6f0f\u308c\u306a\u3069\u306e\u30d5\u30e9\u30b0<\/li>\n<\/ul>\n<p>\u3053\u308c\u3092\u81ea\u52d5\u5316\u3059\u308b<code>\/schedule_report<\/code>\u30b3\u30de\u30f3\u30c9\u306f\u3001\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u4f5c\u6210\u3067\u304d\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">\/\/ \u9031\u6b21\u30ec\u30dd\u30fc\u30c8\u3092\u8a2d\u5b9a\u3059\u308b\u30b3\u30de\u30f3\u30c9\u3092\u8ffd\u52a0\napp.command('\/schedule_report', async ({ command, ack, say }) =&gt; {\n  await ack();\n  \n  \/\/ \u6307\u5b9a\u30d5\u30a9\u30fc\u30de\u30c3\u30c8: environment_id day_of_week hour\n  \/\/ \u4f8b: \/schedule_report 12345 Monday 9\n  const args = command.text.split(' ');\n  \n  if (args.length &lt; 3) {\n    await say('\u5fc5\u8981\u306a\u30d1\u30e9\u30e1\u30fc\u30bf\u3092\u3059\u3079\u3066\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u69cb\u6587: `\/schedule_report [environment_id] [day_of_week] [hour]`');\n    return;\n  }\n  \n  const [environmentId, dayOfWeek, hour] = args;\n  \n  \/\/ \u5165\u529b\u3092\u691c\u8a3c\n  const validDays = ['\u65e5\u66dc\u65e5', '\u6708\u66dc\u65e5', '\u706b\u66dc\u65e5', '\u6c34\u66dc\u65e5', '\u6728\u66dc\u65e5', '\u91d1\u66dc\u65e5', '\u571f\u66dc\u65e5'];\n  if (!validDays.includes(dayOfWeek)) {\n    await say(`\u66dc\u65e5\u304c\u7121\u52b9\u3067\u3059\u3002\u6b21\u304b\u3089\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002: ${validDays.join(', ')}`);\n    return;\n  }\n  \n  const hourInt = parseInt(hour, 10);\n  if (isNaN(hourInt) || hourInt  23) {\n    await say('\u6642\u9593\u306f0\u304b\u308923\u307e\u3067\u306e\u6570\u5b57\u3067\u3042\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002');\n    return;\n  }\n  \n  \/\/ \u66dc\u65e5\u3092cron\u5f62\u5f0f\u306b\u5909\u63db\n  const dayMap = {\n    '\u65e5\u66dc\u65e5': 0,\n    '\u6708\u66dc\u65e5': 1,\n    '\u706b\u66dc\u65e5': 2,\n    '\u6c34\u66dc\u65e5': 3,\n    '\u6728\u66dc\u65e5': 4,\n    '\u91d1\u66dc\u65e5': 5,\n    '\u571f\u66dc\u65e5': 6\n  };\n  \n  const cronDay = dayMap[dayOfWeek];\n  \n  \/\/ \u30ec\u30dd\u30fc\u30c8\u306ecron\u30b9\u30b1\u30b8\u30e5\u30fc\u30eb\u3092\u4f5c\u6210\n  const cronSchedule = `0 ${hourInt} * * ${cronDay}`;\n  \n  \/\/ \u4e00\u610f\u306e\u30b8\u30e7\u30d6ID\u3092\u751f\u6210\n  const jobId = `report_${environmentId}_${Date.now()}`;\n  \n  \/\/ \u30b8\u30e7\u30d6\u3092\u8a2d\u5b9a\n  try {\n    const job = schedule.scheduleJob(cronSchedule, async function() {\n      \/\/ \u30ec\u30dd\u30fc\u30c8\u306e\u4f5c\u6210\u3068\u9001\u4fe1\n      await generateWeeklyReport(environmentId, command.channel_id);\n    });\n    \n    \/\/\u5f8c\u3067\u53d6\u308a\u6d88\u305b\u308b\u3088\u3046\u306b\u30b8\u30e7\u30d6\u3092\u4fdd\u5b58\n    scheduledJobs[jobId] = {\n      job,\n      taskType: 'report',\n      environmentId,\n      cronSchedule,\n      dayOfWeek,\n      hour: hourInt,\n      userId: command.user_id,\n      createdAt: new Date().toISOString()\n    };\n    \n    await say(`\u2705 \u9031\u6b21\u30ec\u30dd\u30fc\u30c8\u3092\u8a2d\u5b9a\u3057\u307e\u3057\u305f\n*\u74b0\u5883:* `${environmentId}`\n*\u30b9\u30b1\u30b8\u30e5\u30fc\u30eb:* Every ${dayOfWeek} at ${hourInt}:00\n*\u30b8\u30e7\u30d6ID:* `${jobId}`\n\nTo cancel this report, use `\/cancel_task ${jobId}``);\n  } catch (error) {\n    console.error('\u30ec\u30dd\u30fc\u30c8\u306e\u8a2d\u5b9a\u30a8\u30e9\u30fc:', error);\n    await say(`\u274c \u30ec\u30dd\u30fc\u30c8\u306e\u8a2d\u5b9a\u30a8\u30e9\u30fc: ${error.message}`);\n  }\n});\n\n\/\/ \u9031\u6b21\u30ec\u30dd\u30fc\u30c8\u3092\u4f5c\u6210\u3059\u308b\u6a5f\u80fd\nasync function generateWeeklyReport(environmentId, channelId) {\n  try {\n    \/\/ \u74b0\u5883\u60c5\u5831\u3092\u53d6\u5f97\n    const response = await kinstaRequest(`\/sites\/environments\/${environmentId}`);\n    \n    if (!response || !response.site || !response.site.environments || !response.site.environments.length) {\n      await web.chat.postMessage({\n        channel: channelId,\n        text: `\u26a0\ufe0f \u9031\u6b21\u30ec\u30dd\u30fc\u30c8\u30a8\u30e9\u30fc: ID ${environmentId} \u306e\u74b0\u5883\u304c\u3042\u308a\u307e\u305b\u3093`\n      });\n      return;\n    }\n    \n    const env = response.site.environments[0];\n    \n    \/\/ \u904e\u53bb1\u9031\u9593\u306e\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u3092\u53d6\u5f97\n    const backupsResponse = await kinstaRequest(`\/sites\/environments\/${environmentId}\/backups`);\n    \n    let backupsCount = 0;\n    let latestBackup = null;\n    \n    if (backupsResponse && backupsResponse.environment && backupsResponse.environment.backups) {\n      const oneWeekAgo = new Date();\n      oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);\n      \n      const recentBackups = backupsResponse.environment.backups.filter(backup =&gt; {\n        const backupDate = new Date(backup.created_at);\n        return backupDate &gt;= oneWeekAgo;\n      });\n      \n      backupsCount = recentBackups.length;\n      \n      if (recentBackups.length &gt; 0) {\n        latestBackup = recentBackups.sort((a, b) =&gt; b.created_at - a.created_at)[0];\n      }\n    }\n    \n    \/\/ \u74b0\u5883\u30b9\u30c6\u30fc\u30bf\u30b9\u3092\u53d6\u5f97\n    const statusEmoji = env.is_blocked ? '\ud83d\udd34' : '\ud83d\udfe2';\n    const statusText = env.is_blocked ? 'Blocked' : 'Running';\n    \n    \/\/ \u30ec\u30dd\u30fc\u30c8\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u4f5c\u6210\n    const reportDate = new Date().toLocaleDateString('en-US', {\n      weekday: 'long',\n      year: 'numeric',\n      month: 'long',\n      day: 'numeric'\n    });\n    \n    const reportMessage = `\ud83d\udcca *\u9031\u6b21\u30ec\u30dd\u30fc\u30c8 - ${reportDate}*\n*\u30b5\u30a4\u30c8:* ${env.display_name}\n*\u74b0\u5883ID:* `${environmentId}`\n\n*\u30b9\u30c6\u30fc\u30bf\u30b9\u6982\u8981:*\n\u2022 \u73fe\u5728\u306e\u30b9\u30c6\u30fc\u30bf\u30b9: ${statusEmoji} ${statusText}\n\u2022 PHP\u30d0\u30fc\u30b8\u30e7\u30f3: ${env.container_info?.php_engine_version || 'Unknown'}\n\u2022 \u30d7\u30e9\u30a4\u30de\u30ea\u30c9\u30e1\u30a4\u30f3: ${env.primaryDomain?.name || env.domains?.[0]?.name || 'N\/A'}\n\n*\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u6982\u8981:*\n\u2022 \u7dcf\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u6570\uff08\u904e\u53bb7\u65e5\u9593\uff09: ${backupsCount}\n\u2022 \u6700\u65b0\u306e\u30d0\u30c3\u30af\u30a2\u30c3\u30d7: ${latestBackup ? new Date(latestBackup.created_at).toLocaleString() : 'N\/A'}\n\u2022 \u6700\u65b0\u306e\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u30bf\u30a4\u30d7: ${latestBackup ? latestBackup.type : 'N\/A'}\n\n*\u63a8\u5968\u4e8b\u9805:*\n\u2022 ${backupsCount === 0 ? '\u26a0\ufe0f \u6700\u8fd1\u306e\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002\u624b\u52d5\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u306e\u4f5c\u6210\u3092\u691c\u8a0e\u3057\u3066\u304f\u3060\u3055\u3044\u3002' : '\u2705 \u5b9a\u671f\u7684\u306a\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u304c\u4f5c\u6210\u3055\u308c\u3066\u3044\u307e\u3059\u3002'}\n\u2022 ${env.is_blocked ? '\u26a0\ufe0f \u30b5\u30a4\u30c8\u306f\u73fe\u5728\u30d6\u30ed\u30c3\u30af\u3055\u308c\u3066\u3044\u307e\u3059\u3002\u554f\u984c\u304c\u306a\u3044\u304b\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002' : '\u2705 \u30b5\u30a4\u30c8\u306f\u6b63\u5e38\u306b\u7a3c\u52d5\u3057\u3066\u3044\u307e\u3059\u3002'}\n\n_\u3053\u308c\u306f\u81ea\u52d5\u30ec\u30dd\u30fc\u30c8\u3067\u3059\u3002\u8a73\u7d30\u60c5\u5831\u3092\u78ba\u8a8d\u3059\u308b\u306b\u306f\u3001\/site_status ${environmentId} \u30b3\u30de\u30f3\u30c9\u3092\u4f7f\u7528\u3057\u3066\u304f\u3060\u3055\u3044;\n    \n    await web.chat.postMessage({\n      channel: channelId,\n      text: reportMessage\n    });\n  } catch (error) {\n    console.error('Report generation error:', error);\n    await web.chat.postMessage({\n      channel: channelId,\n      text: `\u274c \u9031\u6b21\u30ec\u30dd\u30fc\u30c8\u306e\u4f5c\u6210\u30a8\u30e9\u30fc: ${error.message}`\n    });\n  }\n}<\/code><\/pre>\n<h2>\u30a8\u30e9\u30fc\u51e6\u7406\u3068\u76e3\u8996<\/h2>\n<p>\u30dc\u30c3\u30c8\u304c\u74b0\u5883\u3092\u5909\u66f4\u3057\u305f\u308a\u3001\u8a2d\u5b9a\u6e08\u307f\u306e\u30bf\u30b9\u30af\u3092\u8d77\u52d5\u3057\u305f\u308a\u3068\u3044\u3063\u305f\u64cd\u4f5c\u3092\u884c\u3046\u3088\u3046\u306b\u306a\u308b\u3068\u3001<code>console.log()<\/code>\u4ee5\u4e0a\u306e\u3082\u306e\u304c\u5fc5\u8981\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n<p>\u3053\u308c\u3092\u4ee5\u4e0b\u30af\u30ea\u30fc\u30f3\u304b\u3064\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u53ef\u80fd\u306a\u30ec\u30a4\u30e4\u30fc\u306b\u5206\u89e3\u3057\u3066\u307f\u307e\u3059\u3002<\/p>\n<h3>Winston\u306b\u3088\u308b\u69cb\u9020\u5316\u30ed\u30b0<\/h3>\n<p>\u30b3\u30f3\u30bd\u30fc\u30eb\u306b\u30ed\u30b0\u3092\u51fa\u529b\u3059\u308b\u4ee3\u308f\u308a\u306b <code><a href=\"https:\/\/www.npmjs.com\/package\/winston\" target=\"_blank\" rel=\"noopener noreferrer\">winston<\/a><\/code>\u3092\u4f7f\u3063\u3066\u3001\u69cb\u9020\u5316\u3055\u308c\u305f\u30ed\u30b0\u3092\u30d5\u30a1\u30a4\u30eb\u3001\u307e\u305f\u306f\u5fc5\u8981\u306b\u5fdc\u3058\u3066<a href=\"https:\/\/www.loggly.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">Loggly<\/a>\u3084<a href=\"https:\/\/www.datadoghq.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">Datadog<\/a>\u306e\u3088\u3046\u306a\u30b5\u30fc\u30d3\u30b9\u306b\u9001\u4fe1\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002\u4ee5\u4e0b\u306e\u30b3\u30de\u30f3\u30c9\u3067\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u53ef\u80fd\u3067\u3059\u3002<\/p>\n<pre><code class=\"language-bash\">npm install winston<\/code><\/pre>\n<p>\u6b21\u306b<code>logger.js<\/code>\u3092\u8a2d\u5b9a\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">const winston = require('winston');\nconst fs = require('fs');\nconst path = require('path');\n\nconst logsDir = path.join(__dirname, '..\/logs');\nif (!fs.existsSync(logsDir)) fs.mkdirSync(logsDir);\n\nconst logger = winston.createLogger({\n  level: 'info',\n  format: winston.format.combine(\n    winston.format.timestamp(),\n    winston.format.json()\n  ),\n  defaultMeta: { service: 'wordpress-slack-bot' },\n  transports: [\n    new winston.transports.Console({ format: winston.format.simple() }),\n    new winston.transports.File({ filename: path.join(logsDir, 'error.log'), level: 'error' }),\n    new winston.transports.File({ filename: path.join(logsDir, 'combined.log') })\n  ]\n});\n\nmodule.exports = logger;<\/code><\/pre>\n<p>\u6b21\u306b<code>app.js<\/code>\u3067\u3001<code>console.log<\/code>\u307e\u305f\u306f<code>console.error<\/code>\u306e\u547c\u3073\u51fa\u3057\u3092\u6b21\u306e\u3088\u3046\u306b\u7f6e\u304d\u63db\u3048\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">const logger = require('.\/logger');\n\nlogger.info('\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u30af\u30ea\u30a2\u3092\u958b\u59cb', { userId: command.user_id });\nlogger.error('API\u30a8\u30e9\u30fc', { error: err.message });<\/code><\/pre>\n<h3>Slack\u7d4c\u7531\u3067\u7ba1\u7406\u8005\u306b\u901a\u77e5\u3092\u9001\u4fe1\u3059\u308b<\/h3>\n<p>\u3059\u3067\u306b\u74b0\u5883\u5909\u6570<code>ADMIN_USERS<\/code>\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u308b\u305f\u3081\u3001\u4f55\u304b\u91cd\u8981\u306a\u969c\u5bb3\u304c\u767a\u751f\u3057\u305f\u969b\u306f\u3001Slack\u7d4c\u7531\u3067\u30c1\u30fc\u30e0\u306b\u76f4\u63a5\u901a\u77e5\u3059\u308b\u305f\u3081\u306b\u4f7f\u7528\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">async function alertAdmins(message, metadata = {}) {\n  for (const userId of ADMIN_USERS) {\n    const dm = await web.conversations.open({ users: userId });\n    const channel = dm.channel.id;\n\n    let alert = `\ud83d\udea8 *${message}*n`;\n    for (const [key, value] of Object.entries(metadata)) {\n      alert += `\u2022 *${key}:* ${value}n`;\n    }\n\n    await web.chat.postMessage({ channel, text: alert });\n  }\n}<\/code><\/pre>\n<p>\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u4f7f\u7528\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">await alertAdmins('Backup Failed', {\n  environmentId,\n  error: error.message,\n  user: ``\n});<\/code><\/pre>\n<h3>\u7c21\u5358\u306a\u6307\u6a19\u3067\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3092\u8ffd\u8de1<\/h3>\n<p>\u30dc\u30c3\u30c8\u306e\u5065\u5168\u6027\u3092\u78ba\u8a8d\u3059\u308b\u3060\u3051\u3067\u3042\u308c\u3070\u3001<a href=\"https:\/\/prometheus.io\/docs\/guides\/query-log\/\" target=\"_blank\" rel=\"noopener noreferrer\">Prometheus<\/a>\u3092\u672c\u683c\u7684\u306b\u4f7f\u7528\u3059\u308b\u5fc5\u8981\u306f\u306a\u304f\u3001\u3088\u308a\u8efd\u91cf\u306a\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u7528\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3067\u5341\u5206\u3067\u3059\u3002<\/p>\n<pre><code class=\"language-js\">const metrics = {\n  apiCalls: 0,\n  errors: 0,\n  commands: 0,\n  totalTime: 0,\n  get avgResponseTime() {\n    return this.apiCalls === 0 ? 0 : this.totalTime \/ this.apiCalls;\n  }\n};<\/code><\/pre>\n<p><code>kinstaRequest()<\/code>\u30d8\u30eb\u30d1\u30fc\u306e\u4e2d\u3067\u4ee5\u4e0b\u3092\u5909\u66f4\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">const start = Date.now();\ntry {\n  metrics.apiCalls++;\n  const res = await fetch(...);\n  return await res.json();\n} catch (err) {\n  metrics.errors++;\n  throw err;\n} finally {\n  metrics.totalTime += Date.now() - start;\n}<\/code><\/pre>\n<p><code>\/bot_performance<\/code>\u306e\u3088\u3046\u306a\u30b3\u30de\u30f3\u30c9\u3067\u516c\u958b\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">app.command('\/bot_performance', async ({ command, ack, say }) =&gt; {\n  await ack();\n\n  if (!ADMIN_USERS.includes(command.user_id)) {\n    return await say('\u26d4 \u8a31\u53ef\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002');\n  }\n\n  const msg = `\ud83d\udcca *Bot Metrics*\n\u2022 API Calls: ${metrics.apiCalls}\n\u2022 Errors: ${metrics.errors}\n\u2022 Avg Response Time: ${metrics.avgResponseTime.toFixed(2)}ms\n\u2022 Commands Run: ${metrics.commands}`;\n\n  await say(msg);\n});<\/code><\/pre>\n<h3>\u5fa9\u65e7\u624b\u9806\u306e\u5b9a\u7fa9\uff08\u4efb\u610f\uff09<\/h3>\n<p><a href=\"https:\/\/kinsta.com\/jp\/blog\/how-to-use-ssh\/\">SSH<\/a>\u7d4c\u7531\u3067\u30ad\u30e3\u30c3\u30b7\u30e5\u30af\u30ea\u30a2\u3092\u518d\u8a66\u884c\u3059\u308b\u3088\u3046\u306a\u5fa9\u65e7\u30ed\u30b8\u30c3\u30af\u3092\u5b9f\u88c5\u3059\u308b\u306b\u306f\u3001\u4ee5\u4e0b\u306e\u3088\u3046\u306a\u30d8\u30eb\u30d1\u30fc\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"language-js\">async function attemptRecovery(environmentId, issue) {\n  logger.warn('Attempting recovery', { environmentId, issue });\n\n  if (issue === 'cache_clear_failure') {\n    \/\/ \u3053\u3053\u306b\u30d5\u30a9\u30fc\u30eb\u30d0\u30c3\u30af\u30ed\u30b8\u30c3\u30af\n  }\n\n  \/\/ \u5fa9\u65e7\u30b9\u30c6\u30fc\u30bf\u30b9\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u8fd4\u3059\n  return { success: true, message: 'Fallback ran.' };\n}<\/code><\/pre>\n<p>\u30af\u30ea\u30c6\u30a3\u30ab\u30eb\u30d1\u30b9\u3067\u306a\u3044\u9650\u308a\u3001\u30e1\u30a4\u30f3\u306e\u30b3\u30de\u30f3\u30c9\u30ed\u30b8\u30c3\u30af\u304b\u3089\u306f\u5916\u3057\u3066\u304a\u304f\u3053\u3068\u3092\u304a\u3059\u3059\u3081\u3057\u307e\u3059\u3002\u901a\u5e38\u306f\u30a8\u30e9\u30fc\u3092\u30ed\u30b0\u306b\u8a18\u9332\u3057\u3001\u7ba1\u7406\u8005\u306b\u8b66\u544a\u3092\u9001\u4fe1\u3057\u3066\u3001\u62c5\u5f53\u8005\u304c\u3069\u3046\u3059\u3079\u304d\u304b\u3092\u5224\u65ad\u3059\u308b\u306e\u304c\u8ce2\u660e\u3067\u3059\u3002<\/p>\n<h2>Slackbot\u306e\u30c7\u30d7\u30ed\u30a4\u3068\u7ba1\u7406<\/h2>\n<p>\u30dc\u30c3\u30c8\u306e\u6a5f\u80fd\u3092\u4f5c\u6210\u3057\u305f\u3089\u3001\u672c\u756a\u74b0\u5883\u306b\u30c7\u30d7\u30ed\u30a4\u3057\u307e\u3057\u3087\u3046\u3002<\/p>\n<p>Kinsta\u304c\u63d0\u4f9b\u3059\u308b<a href=\"https:\/\/sevalla.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">Sevalla<\/a>\u306f\u3001\u3053\u306e\u3088\u3046\u306a\u30dc\u30c3\u30c8\u3092\u30db\u30b9\u30c6\u30a3\u30f3\u30b0\u3059\u308b\u306e\u306b\u9069\u3057\u305f\u30b5\u30fc\u30d0\u30fc\u3067\u3059\u3002Node.js\u30a2\u30d7\u30ea\u3001\u74b0\u5883\u5909\u6570\u3001\u30ed\u30b0\u3001\u30b9\u30b1\u30fc\u30e9\u30d6\u30eb\u306a\u30c7\u30d7\u30ed\u30a4\u30e1\u30f3\u30c8\u3092\u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n<p><a href=\"https:\/\/kinsta.com\/jp\/blog\/what-is-docker\/\">Docker<\/a>\u3092\u4f7f\u3063\u3066\u30dc\u30c3\u30c8\u3092\u30b3\u30f3\u30c6\u30ca\u5316\u3057\u305f\u308a\u3001Node.js\u3068\u30d0\u30c3\u30af\u30b0\u30e9\u30a6\u30f3\u30c9\u30b5\u30fc\u30d3\u30b9\u3092\u30b5\u30dd\u30fc\u30c8\u3059\u308b\u30af\u30e9\u30a6\u30c9\u30d7\u30e9\u30c3\u30c8\u30d5\u30a9\u30fc\u30e0\u306b\u30c7\u30d7\u30ed\u30a4\u3059\u308b\u3053\u3068\u3082\u53ef\u80fd\u3067\u3059\u3002<\/p>\n<p>\u6700\u5f8c\u306b\u3001\u672c\u756a\u7a3c\u52d5\u524d\u306b\u306f\u4ee5\u4e0b\u306e\u70b9\u306b\u6ce8\u610f\u3057\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n<ul>\n<li>\u3059\u3079\u3066\u306e\u30b7\u30fc\u30af\u30ec\u30c3\u30c8\uff08Slack\u30c8\u30fc\u30af\u30f3\u3001Kinsta API\u30ad\u30fc\u3001SSH\u30ad\u30fc\uff09\u306b\u74b0\u5883\u5909\u6570\u3092\u4f7f\u7528\u3059\u308b\u3002<\/li>\n<li>\u30ed\u30b0\u3068\u7a3c\u50cd\u72b6\u6cc1\u76e3\u8996\u3092\u8a2d\u5b9a\u3057\u3066\u3001\u4f55\u304b\u304c\u58ca\u308c\u305f\u3068\u304d\u306b\u628a\u63e1\u3067\u304d\u308b\u3088\u3046\u306b\u3059\u308b\u3002<\/li>\n<li>PM2\u3084Docker\u306e<code>restart: always<\/code>\u30dd\u30ea\u30b7\u30fc\u306e\u3088\u3046\u306a\u30d7\u30ed\u30bb\u30b9\u30de\u30cd\u30fc\u30b8\u30e3\u30fc\u3067\u30dc\u30c3\u30c8\u3092\u5b9f\u884c\u3057\u3001\u30af\u30e9\u30c3\u30b7\u30e5\u3084\u518d\u8d77\u52d5\u5f8c\u3082\u30dc\u30c3\u30c8\u3092\u5b58\u7d9a\u3055\u305b\u308b\u3002<\/li>\n<li>\u7279\u306b\u81ea\u52d5\u5316\u306bSSH\u30ad\u30fc\u3092\u4f7f\u3063\u3066\u3044\u308b\u5834\u5408\u306f\u3001SSH\u30ad\u30fc\u3092\u5b89\u5168\u306b\u4fdd\u7ba1\u3059\u308b\u3002<\/li>\n<\/ul>\n<h2>\u307e\u3068\u3081<\/h2>\n<p>Slackbot\u3092\u30b7\u30f3\u30d7\u30eb\u306a\u30b3\u30de\u30f3\u30c9\u30cf\u30f3\u30c9\u30e9\u304b\u3089\u3001\u672c\u683c\u7684\u306a\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u6a5f\u80fd\u3001\u81ea\u52d5\u5316\u3001\u76e3\u8996\u6a5f\u80fd\u3092\u5099\u3048\u305f\u5f37\u529b\u306a\u30c4\u30fc\u30eb\u306b\u5909\u8eab\u3055\u305b\u308b\u65b9\u6cd5\u3092\u3054\u7d39\u4ecb\u3057\u307e\u3057\u305f\u3002\u3053\u308c\u3089\u306e\u6a5f\u80fd\u306b\u3088\u308a\u3001\u30dc\u30c3\u30c8\u306e\u5229\u4fbf\u6027\u3068\u4fe1\u983c\u6027\u304c\u9ad8\u307e\u308a\u3001\u4f55\u3088\u308a\u683c\u6bb5\u306b\u4f7f\u3044\u3084\u3059\u304f\u306a\u308a\u307e\u3059\u3002\u8907\u6570\u306eWordPress\u30b5\u30a4\u30c8\u3092\u7ba1\u7406\u3057\u3066\u3044\u308b\u4f01\u696d\u306b\u7279\u306b\u5f79\u7acb\u3064\u306f\u305a\u3067\u3059\u3002<\/p>\n<p>\u3055\u3089\u306b\u3001<a href=\"https:\/\/kinsta.com\/jp\/docs\/kinsta-api\/\">Kinsta API<\/a>\u306e\u30d1\u30ef\u30fc\u3068<a href=\"https:\/\/kinsta.com\/jp\/wordpress-hosting\/\">Kinsta\u306e\u30b9\u30c8\u30ec\u30b9\u30d5\u30ea\u30fc\u306a\u30af\u30e9\u30a6\u30c9\u30b5\u30fc\u30d0\u30fc<\/a>\u3068\u4f75\u7528\u3059\u308b\u3053\u3068\u3067\u3001\u30b9\u30b1\u30fc\u30e9\u30d6\u30eb\u3067\u4fe1\u983c\u6027\u306e\u9ad8\u3044\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u3092\u5b9f\u73fe\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Slackbot\u3092\u9069\u5207\u306b\u8a2d\u5b9a\u3059\u308c\u3070\u3001Slack\u4e0a\u3067\u30dc &#8230;<\/p>\n","protected":false},"author":287,"featured_media":64993,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kinsta_gated_content":false,"_kinsta_gated_content_redirect":"","footnotes":""},"tags":[],"topic":[792],"class_list":["post-64992","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","topic-node-js"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v24.6 (Yoast SEO v24.6) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>WordPress\u7ba1\u7406\u7528\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u306aSlackbot\u306e\u4f5c\u308a\u65b9<\/title>\n<meta name=\"description\" content=\"\u5f37\u529b\u306aSlackbot\u3067WordPress\u7ba1\u7406\u3092\u81ea\u52d5\u5316\u3057\u307e\u305b\u3093\u304b\uff1fNode.js\u3068Kinsta API\u3067\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u6027\u3001\u81ea\u52d5\u5316\u3001\u76e3\u8996\u6a5f\u80fd\u3092\u8ffd\u52a0\u3059\u308b\u65b9\u6cd5\u3092\u3054\u7d39\u4ecb\u3057\u307e\u3059\u3002\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/\" \/>\n<meta property=\"og:locale\" content=\"ja_JP\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"WordPress\u7ba1\u7406\u7528Slackbot\u306b\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u6027\u3001\u81ea\u52d5\u5316\u3001\u76e3\u8996\u6a5f\u80fd\u3092\u8ffd\u52a0\u3059\u308b\u65b9\u6cd5\" \/>\n<meta property=\"og:description\" content=\"\u5f37\u529b\u306aSlackbot\u3067WordPress\u7ba1\u7406\u3092\u81ea\u52d5\u5316\u3057\u307e\u305b\u3093\u304b\uff1fNode.js\u3068Kinsta API\u3067\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u6027\u3001\u81ea\u52d5\u5316\u3001\u76e3\u8996\u6a5f\u80fd\u3092\u8ffd\u52a0\u3059\u308b\u65b9\u6cd5\u3092\u3054\u7d39\u4ecb\u3057\u307e\u3059\u3002\" \/>\n<meta property=\"og:url\" content=\"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/\" \/>\n<meta property=\"og:site_name\" content=\"Kinsta\u00ae\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/Kinsta-Japan-334616080691171\/\" \/>\n<meta property=\"article:published_time\" content=\"2025-05-16T07:47:07+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-05-16T13:32:31+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/kinsta.com\/jp\/wp-content\/uploads\/sites\/6\/2025\/05\/implement-interactivity-scheduling-and-monitoring-in-slackbots-for-managing-wordpress-sites.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1470\" \/>\n\t<meta property=\"og:image:height\" content=\"735\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Joel Olawanle\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:description\" content=\"\u5f37\u529b\u306aSlackbot\u3067WordPress\u7ba1\u7406\u3092\u81ea\u52d5\u5316\u3057\u307e\u305b\u3093\u304b\uff1fNode.js\u3068Kinsta API\u3067\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u6027\u3001\u81ea\u52d5\u5316\u3001\u76e3\u8996\u6a5f\u80fd\u3092\u8ffd\u52a0\u3059\u308b\u65b9\u6cd5\u3092\u3054\u7d39\u4ecb\u3057\u307e\u3059\u3002\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/kinsta.com\/jp\/wp-content\/uploads\/sites\/6\/2025\/05\/implement-interactivity-scheduling-and-monitoring-in-slackbots-for-managing-wordpress-sites.png\" \/>\n<meta name=\"twitter:creator\" content=\"@olawanle_joel\" \/>\n<meta name=\"twitter:site\" content=\"@Kinsta_JP\" \/>\n<meta name=\"twitter:label1\" content=\"\u57f7\u7b46\u8005\" \/>\n\t<meta name=\"twitter:data1\" content=\"Joel Olawanle\" \/>\n\t<meta name=\"twitter:label2\" content=\"\u63a8\u5b9a\u8aad\u307f\u53d6\u308a\u6642\u9593\" \/>\n\t<meta name=\"twitter:data2\" content=\"13\u5206\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/\"},\"author\":{\"name\":\"Joel Olawanle\",\"@id\":\"https:\/\/kinsta.com\/jp\/#\/schema\/person\/efa7de30245ca15be5ce1dcacff89c07\"},\"headline\":\"WordPress\u7ba1\u7406\u7528Slackbot\u306b\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u6027\u3001\u81ea\u52d5\u5316\u3001\u76e3\u8996\u6a5f\u80fd\u3092\u8ffd\u52a0\u3059\u308b\u65b9\u6cd5\",\"datePublished\":\"2025-05-16T07:47:07+00:00\",\"dateModified\":\"2025-05-16T13:32:31+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/\"},\"wordCount\":99,\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/jp\/#organization\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/jp\/wp-content\/uploads\/sites\/6\/2025\/05\/implement-interactivity-scheduling-and-monitoring-in-slackbots-for-managing-wordpress-sites.png\",\"inLanguage\":\"ja\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/\",\"url\":\"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/\",\"name\":\"WordPress\u7ba1\u7406\u7528\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u306aSlackbot\u306e\u4f5c\u308a\u65b9\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/jp\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/jp\/wp-content\/uploads\/sites\/6\/2025\/05\/implement-interactivity-scheduling-and-monitoring-in-slackbots-for-managing-wordpress-sites.png\",\"datePublished\":\"2025-05-16T07:47:07+00:00\",\"dateModified\":\"2025-05-16T13:32:31+00:00\",\"description\":\"\u5f37\u529b\u306aSlackbot\u3067WordPress\u7ba1\u7406\u3092\u81ea\u52d5\u5316\u3057\u307e\u305b\u3093\u304b\uff1fNode.js\u3068Kinsta API\u3067\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u6027\u3001\u81ea\u52d5\u5316\u3001\u76e3\u8996\u6a5f\u80fd\u3092\u8ffd\u52a0\u3059\u308b\u65b9\u6cd5\u3092\u3054\u7d39\u4ecb\u3057\u307e\u3059\u3002\",\"breadcrumb\":{\"@id\":\"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/#breadcrumb\"},\"inLanguage\":\"ja\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"ja\",\"@id\":\"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/#primaryimage\",\"url\":\"https:\/\/kinsta.com\/jp\/wp-content\/uploads\/sites\/6\/2025\/05\/implement-interactivity-scheduling-and-monitoring-in-slackbots-for-managing-wordpress-sites.png\",\"contentUrl\":\"https:\/\/kinsta.com\/jp\/wp-content\/uploads\/sites\/6\/2025\/05\/implement-interactivity-scheduling-and-monitoring-in-slackbots-for-managing-wordpress-sites.png\",\"width\":1470,\"height\":735},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/kinsta.com\/jp\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Node.js\",\"item\":\"https:\/\/kinsta.com\/jp\/topics\/node-js\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"WordPress\u7ba1\u7406\u7528Slackbot\u306b\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u6027\u3001\u81ea\u52d5\u5316\u3001\u76e3\u8996\u6a5f\u80fd\u3092\u8ffd\u52a0\u3059\u308b\u65b9\u6cd5\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/kinsta.com\/jp\/#website\",\"url\":\"https:\/\/kinsta.com\/jp\/\",\"name\":\"Kinsta\u00ae\",\"description\":\"\u9ad8\u901f\u304b\u3064\u5805\u7262\u306a\u30d7\u30ec\u30df\u30a2\u30e0\u30b5\u30fc\u30d0\u30fc\u30b5\u30fc\u30d3\u30b9\",\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/jp\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/kinsta.com\/jp\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"ja\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/kinsta.com\/jp\/#organization\",\"name\":\"Kinsta\",\"url\":\"https:\/\/kinsta.com\/jp\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ja\",\"@id\":\"https:\/\/kinsta.com\/jp\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/kinsta.com\/jp\/wp-content\/uploads\/sites\/6\/2023\/12\/kinsta-logo.jpeg\",\"contentUrl\":\"https:\/\/kinsta.com\/jp\/wp-content\/uploads\/sites\/6\/2023\/12\/kinsta-logo.jpeg\",\"width\":500,\"height\":500,\"caption\":\"Kinsta\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/jp\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/Kinsta-Japan-334616080691171\/\",\"https:\/\/x.com\/Kinsta_JP\",\"https:\/\/www.instagram.com\/kinstahosting\/\",\"https:\/\/www.linkedin.com\/company\/kinsta\/\",\"https:\/\/www.pinterest.com\/kinstahosting\/\",\"https:\/\/www.youtube.com\/c\/Kinsta\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/kinsta.com\/jp\/#\/schema\/person\/efa7de30245ca15be5ce1dcacff89c07\",\"name\":\"Joel Olawanle\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ja\",\"@id\":\"https:\/\/kinsta.com\/jp\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/051bf577ce2c837846a1db9eef184758?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/051bf577ce2c837846a1db9eef184758?s=96&d=mm&r=g\",\"caption\":\"Joel Olawanle\"},\"description\":\"Joel is a Frontend developer working at Kinsta as a Technical Editor. He is a passionate teacher with love for open source and has written over 300 technical articles majorly around JavaScript and it's frameworks.\",\"sameAs\":[\"https:\/\/joelolawanle.com\/\",\"https:\/\/www.linkedin.com\/in\/olawanlejoel\/\",\"https:\/\/x.com\/olawanle_joel\",\"https:\/\/www.youtube.com\/@joelolawanle\"],\"gender\":\"male\",\"knowsAbout\":[\"JavaScript\",\"React\",\"Next.js\"],\"knowsLanguage\":[\"English\"],\"jobTitle\":\"Technical Editor\",\"worksFor\":\"Kinsta\",\"url\":\"https:\/\/kinsta.com\/jp\/blog\/author\/joelolawanle\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"WordPress\u7ba1\u7406\u7528\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u306aSlackbot\u306e\u4f5c\u308a\u65b9","description":"\u5f37\u529b\u306aSlackbot\u3067WordPress\u7ba1\u7406\u3092\u81ea\u52d5\u5316\u3057\u307e\u305b\u3093\u304b\uff1fNode.js\u3068Kinsta API\u3067\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u6027\u3001\u81ea\u52d5\u5316\u3001\u76e3\u8996\u6a5f\u80fd\u3092\u8ffd\u52a0\u3059\u308b\u65b9\u6cd5\u3092\u3054\u7d39\u4ecb\u3057\u307e\u3059\u3002","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/","og_locale":"ja_JP","og_type":"article","og_title":"WordPress\u7ba1\u7406\u7528Slackbot\u306b\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u6027\u3001\u81ea\u52d5\u5316\u3001\u76e3\u8996\u6a5f\u80fd\u3092\u8ffd\u52a0\u3059\u308b\u65b9\u6cd5","og_description":"\u5f37\u529b\u306aSlackbot\u3067WordPress\u7ba1\u7406\u3092\u81ea\u52d5\u5316\u3057\u307e\u305b\u3093\u304b\uff1fNode.js\u3068Kinsta API\u3067\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u6027\u3001\u81ea\u52d5\u5316\u3001\u76e3\u8996\u6a5f\u80fd\u3092\u8ffd\u52a0\u3059\u308b\u65b9\u6cd5\u3092\u3054\u7d39\u4ecb\u3057\u307e\u3059\u3002","og_url":"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/","og_site_name":"Kinsta\u00ae","article_publisher":"https:\/\/www.facebook.com\/Kinsta-Japan-334616080691171\/","article_published_time":"2025-05-16T07:47:07+00:00","article_modified_time":"2025-05-16T13:32:31+00:00","og_image":[{"width":1470,"height":735,"url":"https:\/\/kinsta.com\/jp\/wp-content\/uploads\/sites\/6\/2025\/05\/implement-interactivity-scheduling-and-monitoring-in-slackbots-for-managing-wordpress-sites.png","type":"image\/png"}],"author":"Joel Olawanle","twitter_card":"summary_large_image","twitter_description":"\u5f37\u529b\u306aSlackbot\u3067WordPress\u7ba1\u7406\u3092\u81ea\u52d5\u5316\u3057\u307e\u305b\u3093\u304b\uff1fNode.js\u3068Kinsta API\u3067\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u6027\u3001\u81ea\u52d5\u5316\u3001\u76e3\u8996\u6a5f\u80fd\u3092\u8ffd\u52a0\u3059\u308b\u65b9\u6cd5\u3092\u3054\u7d39\u4ecb\u3057\u307e\u3059\u3002","twitter_image":"https:\/\/kinsta.com\/jp\/wp-content\/uploads\/sites\/6\/2025\/05\/implement-interactivity-scheduling-and-monitoring-in-slackbots-for-managing-wordpress-sites.png","twitter_creator":"@olawanle_joel","twitter_site":"@Kinsta_JP","twitter_misc":{"\u57f7\u7b46\u8005":"Joel Olawanle","\u63a8\u5b9a\u8aad\u307f\u53d6\u308a\u6642\u9593":"13\u5206"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/#article","isPartOf":{"@id":"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/"},"author":{"name":"Joel Olawanle","@id":"https:\/\/kinsta.com\/jp\/#\/schema\/person\/efa7de30245ca15be5ce1dcacff89c07"},"headline":"WordPress\u7ba1\u7406\u7528Slackbot\u306b\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u6027\u3001\u81ea\u52d5\u5316\u3001\u76e3\u8996\u6a5f\u80fd\u3092\u8ffd\u52a0\u3059\u308b\u65b9\u6cd5","datePublished":"2025-05-16T07:47:07+00:00","dateModified":"2025-05-16T13:32:31+00:00","mainEntityOfPage":{"@id":"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/"},"wordCount":99,"publisher":{"@id":"https:\/\/kinsta.com\/jp\/#organization"},"image":{"@id":"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/jp\/wp-content\/uploads\/sites\/6\/2025\/05\/implement-interactivity-scheduling-and-monitoring-in-slackbots-for-managing-wordpress-sites.png","inLanguage":"ja"},{"@type":"WebPage","@id":"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/","url":"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/","name":"WordPress\u7ba1\u7406\u7528\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u306aSlackbot\u306e\u4f5c\u308a\u65b9","isPartOf":{"@id":"https:\/\/kinsta.com\/jp\/#website"},"primaryImageOfPage":{"@id":"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/#primaryimage"},"image":{"@id":"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/jp\/wp-content\/uploads\/sites\/6\/2025\/05\/implement-interactivity-scheduling-and-monitoring-in-slackbots-for-managing-wordpress-sites.png","datePublished":"2025-05-16T07:47:07+00:00","dateModified":"2025-05-16T13:32:31+00:00","description":"\u5f37\u529b\u306aSlackbot\u3067WordPress\u7ba1\u7406\u3092\u81ea\u52d5\u5316\u3057\u307e\u305b\u3093\u304b\uff1fNode.js\u3068Kinsta API\u3067\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u6027\u3001\u81ea\u52d5\u5316\u3001\u76e3\u8996\u6a5f\u80fd\u3092\u8ffd\u52a0\u3059\u308b\u65b9\u6cd5\u3092\u3054\u7d39\u4ecb\u3057\u307e\u3059\u3002","breadcrumb":{"@id":"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/#breadcrumb"},"inLanguage":"ja","potentialAction":[{"@type":"ReadAction","target":["https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/"]}]},{"@type":"ImageObject","inLanguage":"ja","@id":"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/#primaryimage","url":"https:\/\/kinsta.com\/jp\/wp-content\/uploads\/sites\/6\/2025\/05\/implement-interactivity-scheduling-and-monitoring-in-slackbots-for-managing-wordpress-sites.png","contentUrl":"https:\/\/kinsta.com\/jp\/wp-content\/uploads\/sites\/6\/2025\/05\/implement-interactivity-scheduling-and-monitoring-in-slackbots-for-managing-wordpress-sites.png","width":1470,"height":735},{"@type":"BreadcrumbList","@id":"https:\/\/kinsta.com\/jp\/blog\/add-interactivity-scheduling-monitoring-slackbot\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/kinsta.com\/jp\/"},{"@type":"ListItem","position":2,"name":"Node.js","item":"https:\/\/kinsta.com\/jp\/topics\/node-js\/"},{"@type":"ListItem","position":3,"name":"WordPress\u7ba1\u7406\u7528Slackbot\u306b\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u6027\u3001\u81ea\u52d5\u5316\u3001\u76e3\u8996\u6a5f\u80fd\u3092\u8ffd\u52a0\u3059\u308b\u65b9\u6cd5"}]},{"@type":"WebSite","@id":"https:\/\/kinsta.com\/jp\/#website","url":"https:\/\/kinsta.com\/jp\/","name":"Kinsta\u00ae","description":"\u9ad8\u901f\u304b\u3064\u5805\u7262\u306a\u30d7\u30ec\u30df\u30a2\u30e0\u30b5\u30fc\u30d0\u30fc\u30b5\u30fc\u30d3\u30b9","publisher":{"@id":"https:\/\/kinsta.com\/jp\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/kinsta.com\/jp\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"ja"},{"@type":"Organization","@id":"https:\/\/kinsta.com\/jp\/#organization","name":"Kinsta","url":"https:\/\/kinsta.com\/jp\/","logo":{"@type":"ImageObject","inLanguage":"ja","@id":"https:\/\/kinsta.com\/jp\/#\/schema\/logo\/image\/","url":"https:\/\/kinsta.com\/jp\/wp-content\/uploads\/sites\/6\/2023\/12\/kinsta-logo.jpeg","contentUrl":"https:\/\/kinsta.com\/jp\/wp-content\/uploads\/sites\/6\/2023\/12\/kinsta-logo.jpeg","width":500,"height":500,"caption":"Kinsta"},"image":{"@id":"https:\/\/kinsta.com\/jp\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/Kinsta-Japan-334616080691171\/","https:\/\/x.com\/Kinsta_JP","https:\/\/www.instagram.com\/kinstahosting\/","https:\/\/www.linkedin.com\/company\/kinsta\/","https:\/\/www.pinterest.com\/kinstahosting\/","https:\/\/www.youtube.com\/c\/Kinsta"]},{"@type":"Person","@id":"https:\/\/kinsta.com\/jp\/#\/schema\/person\/efa7de30245ca15be5ce1dcacff89c07","name":"Joel Olawanle","image":{"@type":"ImageObject","inLanguage":"ja","@id":"https:\/\/kinsta.com\/jp\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/051bf577ce2c837846a1db9eef184758?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/051bf577ce2c837846a1db9eef184758?s=96&d=mm&r=g","caption":"Joel Olawanle"},"description":"Joel is a Frontend developer working at Kinsta as a Technical Editor. He is a passionate teacher with love for open source and has written over 300 technical articles majorly around JavaScript and it's frameworks.","sameAs":["https:\/\/joelolawanle.com\/","https:\/\/www.linkedin.com\/in\/olawanlejoel\/","https:\/\/x.com\/olawanle_joel","https:\/\/www.youtube.com\/@joelolawanle"],"gender":"male","knowsAbout":["JavaScript","React","Next.js"],"knowsLanguage":["English"],"jobTitle":"Technical Editor","worksFor":"Kinsta","url":"https:\/\/kinsta.com\/jp\/blog\/author\/joelolawanle\/"}]}},"acf":[],"_links":{"self":[{"href":"https:\/\/kinsta.com\/jp\/wp-json\/wp\/v2\/posts\/64992","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kinsta.com\/jp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kinsta.com\/jp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kinsta.com\/jp\/wp-json\/wp\/v2\/users\/287"}],"replies":[{"embeddable":true,"href":"https:\/\/kinsta.com\/jp\/wp-json\/wp\/v2\/comments?post=64992"}],"version-history":[{"count":5,"href":"https:\/\/kinsta.com\/jp\/wp-json\/wp\/v2\/posts\/64992\/revisions"}],"predecessor-version":[{"id":65002,"href":"https:\/\/kinsta.com\/jp\/wp-json\/wp\/v2\/posts\/64992\/revisions\/65002"}],"alternate":[{"embeddable":true,"hreflang":"en","title":"English","href":"https:\/\/kinsta.com\/jp\/wp-json\/kinsta\/v1\/posts\/64992\/translations\/en"},{"embeddable":true,"hreflang":"it","title":"Italian","href":"https:\/\/kinsta.com\/jp\/wp-json\/kinsta\/v1\/posts\/64992\/translations\/it"},{"embeddable":true,"hreflang":"pt","title":"Portuguese","href":"https:\/\/kinsta.com\/jp\/wp-json\/kinsta\/v1\/posts\/64992\/translations\/pt"},{"embeddable":true,"hreflang":"fr","title":"French","href":"https:\/\/kinsta.com\/jp\/wp-json\/kinsta\/v1\/posts\/64992\/translations\/fr"},{"embeddable":true,"hreflang":"de","title":"German","href":"https:\/\/kinsta.com\/jp\/wp-json\/kinsta\/v1\/posts\/64992\/translations\/de"},{"embeddable":true,"hreflang":"ja","title":"Japanese","href":"https:\/\/kinsta.com\/jp\/wp-json\/kinsta\/v1\/posts\/64992\/translations\/jp"},{"embeddable":true,"hreflang":"nl","title":"Dutch","href":"https:\/\/kinsta.com\/jp\/wp-json\/kinsta\/v1\/posts\/64992\/translations\/nl"},{"embeddable":true,"hreflang":"es","title":"Spanish","href":"https:\/\/kinsta.com\/jp\/wp-json\/kinsta\/v1\/posts\/64992\/translations\/es"},{"href":"https:\/\/kinsta.com\/jp\/wp-json\/kinsta\/v1\/posts\/64992\/tree"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/kinsta.com\/jp\/wp-json\/wp\/v2\/media\/64993"}],"wp:attachment":[{"href":"https:\/\/kinsta.com\/jp\/wp-json\/wp\/v2\/media?parent=64992"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kinsta.com\/jp\/wp-json\/wp\/v2\/tags?post=64992"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/kinsta.com\/jp\/wp-json\/wp\/v2\/topic?post=64992"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}