メインコンテンツへスキップ
見出し画像

FileMakerでナレッジDBをつくるよ!Part 5

    こんにちは!いちごいぬです🐶
    今回でナレッジDBは完結しました☺️✨
    末尾に今回作成したファイルがダウンロードできるので
    もしよろしければ、ご覧下さい🍀

    ⏬️前回の記事

    今回は、
    ・画像の保存ができるのか?
    ・WebDirectで動作するのか?
    を確認します。

    その後、ペンディングした堅牢化の処理を入れたいと思います。


    画像は保存できるのか?

    やってみましょう!

    新しいレコード(3レコード目)を作成して画像と文字を貼り付けました。
    「保存」ボタンをクリックします。

    画像
    保存は問題なく実行できました

    「ツール」→「データビューア」から「knowledgeDB::HTML_Content」の値を見てみます。

    画像

    内容を貼り付けます。
    画像はBase64で保存されていますね!

    <p> </p>
    <p> </p>
    <p><img src="data:image/png;base64,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y/h+9P/cTH8Tgf/7C4fF39nlvdIZjceZmFjCi9ctCnsmFRTSP1iEi3b+rSpQ1eHgC8J0lPQ+c9qvdaUK1OKv2PzlLT5eWpzMt/D5qMUMnphq0FvzHqwffQcGxW8AWiuu213tn4UUMN+pI3MvSwDlE0ABoG4D8Yz8A4LbL5/lmyigLi5XGEe23uqqdVu+3tUgHI3WTnpZQm3kyrhzUoCr/QPs7R+IAddtRE2Zxq5FwDVzH3WaW9tAsh5wzZJH5tfKepMalIdNmcYzoS2Vdgk363k1tM4RF0eQdKyf7zAePDeOVrm/VzpDG9EtX3/GSatGMy0N64so1EottAUXwg4Xzno94EJ/nx3qI/iHyD/vwCqEgQxrK67ljhs9a68vUK5dlWjRJNfafIN2BFxf5naB21vrrZyVf7rPJM2vSX3TAy51TBeH3HYZR2JC27ysFuhGWflJ70NrUZZQdxejFpfEEjZlCF40aiA9XtJS0ti1CbjdRllprNzUWClO/qkupHyLRblP8/IG8kcBZ8kHpMymtRKYrSUkjzy8Vzqmc2FPWdF6y2YdVhQjZ8rsNObqW3efkHqiDENRhrXn06L3pVzLnljeQDkC/cyJOqXLyhV6h1os1RvwxxVppNaTClRhouhwx0JPnVqpd21Q6t0hiIiordQSCurdlp8cOJcrJICkl6Gfj8CeYxFsxIX3Ot2yXCF0DLlERER9yDnkUrsx5IaP5QpEREREFDkdH8kdGuIZJBERERGFK3b75XNHQi4RERERUauwXIGIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgihyGXiIiIiCKHIZeIiIiIIochl4iIiIgi5/8BXCwmd0DgtfIAAAAASUVORK5CYII="></p>
    <p>画像貼り付けのテストです。</p>
    <p> </p>
    <p> </p>

    Pythonでバイト数を計算してみました。

    >>> len(txt.encode("shift_jis") )
    11260
    >>> len(txt.encode("shift_jis") ) / 1024
    10.99609375

    10KBほどですね!

    レコードを切り替えて、再読み込みをしても画像はそのまま!
    実装問題なさそうです☺️

    ・・・

    TIP💡:img src="data:image/png;base64,..." ってなに?

    img src="data:image/png;base64,..." は、画像ファイルのURLを指定する代わりに、画像データそのものをHTMLに直接埋め込む書き方です。
    data: は埋め込みデータ、image/png はPNG形式、base64 は画像を文字列化した形式を表します。

    通常の <img src="logo.png"> が「画像ファイルを読み込む」のに対し、
    <img src="data:image/png;base64,..."> は「画像そのものをHTML内に持たせる」イメージです。

    外部ファイルなしで完結できるのが利点ですが、HTMLが長く重くなりやすい点には注意が必要です。

    ・・・

    WebDirectで動作するのか?

    動作しませんでした・・・
    本来なら保存されている文字が表示されて欲しいところですが、
    何も表示されません。
    スクリプトは動いているようなのですが、なぜだ。

    画像
    一筋縄ではいかないです。


    とりあえず、カスタムダイアログでGet( 最終エラー ) を表示してみます。
    これで、直前の「WebビューアでJavaScriptを実行」でエラーが発生しているかが分かります。

    画像
    最後に「カスタムダイアログを表示」を追加

    実行すると「0」。エラーは発生していないとのことです。

    画像

    $json に値が入っていないのか?
    Get( 最終エラー ) から $json に変えました。

    画像

    $json の値も問題なく入っています。

    画像

    Wait が足りない?
    10秒にしてみました。

    画像

    現象変わらず。

    これはFileMaker(WebDirect)からJavaScriptが実行できていないのではないか?

    ・・・

    ChatGPTに対策をお願いしました。
    FileMakerから実行すると変更されないので、JavaScript側からスクリプトを実行することにしました。

    • http://<サーバIPアドレス>/editor/editor.html

    • http://<サーバIPアドレス>/editor/bridge.js

    • http://<サーバIPアドレス>/editor/tinymce/tinymce.min.js


    • TinyMCE 初期化完了時に EditorReady を FileMaker に返す

    • 本文は FMBridge.loadFromFM(...) で後から流し込む

    • 保存は FMBridge.saveToFM() で SaveHTML スクリプトへ返す


    editor.html

    <!doctype html>
    <html lang="ja">
    <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>TinyMCE Editor</title>
    
      <script src="./tinymce/tinymce.min.js"></script>
      <script src="./bridge.js"></script>
    
      <style>
        html, body {
          height: 100%;
          margin: 0;
          padding: 0;
          background: #ffffff;
          font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
          overflow: hidden;
        }
    
        #app {
          height: 100vh;
          display: flex;
          flex-direction: column;
        }
    
        #topbar {
          flex: 0 0 auto;
          display: flex;
          align-items: center;
          gap: 8px;
          padding: 8px 10px;
          border-bottom: 1px solid #dcdcdc;
          background: #f7f7f7;
          box-sizing: border-box;
        }
    
        #topbar button {
          appearance: none;
          border: 1px solid #c8c8c8;
          background: #fff;
          padding: 6px 12px;
          border-radius: 6px;
          cursor: pointer;
          font-size: 13px;
        }
    
        #topbar button:hover {
          background: #f0f0f0;
        }
    
        #status {
          margin-left: auto;
          font-size: 12px;
          color: #666;
          white-space: nowrap;
        }
    
        #debug {
          margin-left: 8px;
          font-size: 12px;
          color: #999;
          white-space: nowrap;
        }
    
        #editor-wrap {
          flex: 1 1 auto;
          min-height: 0;
          display: flex;
          flex-direction: column;
        }
    
        #editor {
          width: 100%;
          height: 100%;
        }
    
        .tox.tox-tinymce {
          border: 0 !important;
          border-radius: 0 !important;
          flex: 1 1 auto;
        }
    
        noscript {
          display: block;
          padding: 12px;
          color: #a00;
          background: #fff4f4;
          border-top: 1px solid #f0cccc;
        }
      </style>
    </head>
    <body>
      <div id="app">
        <div id="topbar">
          <button type="button" onclick="FMBridge.saveToFM()">保存</button>
          <button type="button" onclick="FMBridge.reloadFromFM()">再読込</button>
          <span id="status">loading...</span>
          <span id="debug"></span>
        </div>
    
        <div id="editor-wrap">
          <textarea id="editor"></textarea>
        </div>
      </div>
    
      <noscript>
        このアプリケーションを使用するにはブラウザで JavaScript を有効にします。
      </noscript>
    
      <script>
        (function () {
          function setStatus(message) {
            var el = document.getElementById('status');
            if (el) {
              el.textContent = message;
            }
          }
    
          function setDebug(message) {
            var el = document.getElementById('debug');
            if (el) {
              el.textContent = message;
            }
          }
    
          function callFileMaker(scriptName, param) {
            if (window.FileMaker && typeof window.FileMaker.PerformScript === 'function') {
              try {
                window.FileMaker.PerformScript(scriptName, param || '');
                return true;
              } catch (e) {
                console.error('FileMaker.PerformScript error:', e);
                return false;
              }
            }
            return false;
          }
    
          // デバッグ確認用
          setDebug(
            'tinymce=' + typeof tinymce +
            ' / FMBridge=' + typeof FMBridge
          );
    
          // readyフラグ
          window.__fmEditorReady = false;
    
          tinymce.init({
            selector: '#editor',
            license_key: 'gpl',
            base_url: './tinymce',
            promotion: false,
            menubar: true,
            statusbar: true,
            branding: false,
    
            plugins: [
              'lists', 'link', 'table', 'code', 'wordcount',
              'autolink', 'charmap', 'fullscreen', 'image',
              'preview', 'searchreplace'
            ],
    
            toolbar:
              'undo redo | blocks | bold italic underline forecolor backcolor | ' +
              'alignleft aligncenter alignright alignjustify | ' +
              'bullist numlist outdent indent | ' +
              'link image table | code preview fullscreen',
    
            height: '100%',
    
            content_style:
              'body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; font-size: 14px; line-height: 1.6; margin: 1rem; }',
    
            setup: function (editor) {
              editor.on('init', function () {
                window.__fmEditorReady = true;
                setStatus('ready');
                setDebug(
                  'tinymce=' + typeof tinymce +
                  ' / FMBridge=' + typeof FMBridge +
                  ' / ready=' + window.__fmEditorReady
                );
    
                // FileMakerへ準備完了通知
                callFileMaker('EditorReady', '');
              });
    
              editor.on('change input undo redo setcontent', function () {
                if (window.FMBridge) {
                  window.FMBridge.dirty = true;
                }
                setStatus('edited');
              });
            }
          });
    
          // 念のためグローバル側にも置いておく
          window.fmPing = function (param) {
            console.log('fmPing called:', param);
            callFileMaker('JSPing', param || 'ping');
            return 'ok';
          };
    
          window.fmLoadFromFM = function (param) {
            if (window.FMBridge && typeof window.FMBridge.loadFromFM === 'function') {
              return window.FMBridge.loadFromFM(param);
            }
            console.error('FMBridge.loadFromFM is not available');
            return null;
          };
    
          window.fmSaveToFM = function () {
            if (window.FMBridge && typeof window.FMBridge.saveToFM === 'function') {
              return window.FMBridge.saveToFM();
            }
            console.error('FMBridge.saveToFM is not available');
            return null;
          };
        })();
      </script>
    </body>
    </html>

    bridge.js

    • FileMaker から
      FMBridge.loadFromFM(json文字列)
      を呼んで本文を流し込む

    • 保存時は
      FileMaker.PerformScript("SaveHTML", payload)
      を呼ぶ

    • 再読込時は
      FileMaker.PerformScript("EditorReloadRequest", "")
      を呼ぶ

    • WebDirect / Pro の両方で動かしやすいように、editor ready 待ち を入れる

    window.FMBridge = (function () {
      let lastLoadedHtml = "";
      let dirty = false;
    
      function getEditor() {
        if (!window.tinymce) return null;
        return tinymce.get("editor");
      }
    
      function setStatus(message) {
        const el = document.getElementById("status");
        if (el) {
          el.textContent = message;
        }
      }
    
      function setDebug(message) {
        const el = document.getElementById("debug");
        if (el) {
          el.textContent = message;
        }
      }
    
      function safeJsonParse(value) {
        try {
          return JSON.parse(value);
        } catch (e) {
          return null;
        }
      }
    
      function callFileMaker(scriptName, param) {
        if (window.FileMaker && typeof window.FileMaker.PerformScript === "function") {
          try {
            window.FileMaker.PerformScript(scriptName, param || "");
            return true;
          } catch (e) {
            console.error("FileMaker.PerformScript error:", e);
            return false;
          }
        }
        console.warn("FileMaker.PerformScript is not available");
        return false;
      }
    
      function waitEditor(callback, maxRetry, interval) {
        let count = 0;
        const retryMax = typeof maxRetry === "number" ? maxRetry : 100;
        const waitMs = typeof interval === "number" ? interval : 100;
    
        function tick() {
          const ed = getEditor();
    
          if (ed && window.__fmEditorReady === true) {
            callback(ed);
            return;
          }
    
          count += 1;
    
          if (count >= retryMax) {
            console.warn("waitEditor timeout");
            setStatus("editor wait timeout");
            return;
          }
    
          setTimeout(tick, waitMs);
        }
    
        tick();
      }
    
      function normalizeInput(param) {
        if (typeof param === "string") {
          const parsed = safeJsonParse(param);
          if (parsed && typeof parsed === "object") {
            return parsed;
          }
          return { html: param };
        }
    
        if (param && typeof param === "object") {
          return param;
        }
    
        return { html: "" };
      }
    
      function loadFromFM(param) {
        const data = normalizeInput(param);
        const html = data.html || "";
    
        setStatus("loading from FileMaker...");
    
        waitEditor(function (ed) {
          try {
            ed.setContent(html);
            lastLoadedHtml = html;
            dirty = false;
            FMBridge.dirty = false;
    
            setStatus("loaded");
            setDebug(
              "loaded / length=" + html.length +
              " / ready=" + window.__fmEditorReady
            );
          } catch (e) {
            console.error("loadFromFM error:", e);
            setStatus("load error");
          }
        });
      }
    
      function getHtml() {
        const ed = getEditor();
        if (!ed) return "";
        try {
          return ed.getContent();
        } catch (e) {
          console.error("getHtml error:", e);
          return "";
        }
      }
    
      function saveToFM() {
        const html = getHtml();
    
        const payload = JSON.stringify({
          html: html,
          dirty: dirty || FMBridge.dirty
        });
    
        const ok = callFileMaker("SaveHTML", payload);
    
        if (ok) {
          lastLoadedHtml = html;
          dirty = false;
          FMBridge.dirty = false;
          setStatus("saved");
          setDebug("saved / length=" + html.length);
        } else {
          setStatus("save failed");
        }
      }
    
      function reloadFromFM() {
        const ok = callFileMaker("EditorReloadRequest", "");
    
        if (ok) {
          setStatus("reload requested");
        } else {
          setStatus("reload failed");
        }
      }
    
      function isDirty() {
        return dirty || FMBridge.dirty;
      }
    
      function markDirty(flag) {
        dirty = !!flag;
        FMBridge.dirty = !!flag;
        setStatus(dirty ? "edited" : "clean");
      }
    
      function getState() {
        return {
          ready: !!window.__fmEditorReady,
          dirty: isDirty(),
          htmlLength: getHtml().length,
          lastLoadedLength: lastLoadedHtml.length
        };
      }
    
      return {
        dirty: false,
        loadFromFM: loadFromFM,
        saveToFM: saveToFM,
        reloadFromFM: reloadFromFM,
        getHtml: getHtml,
        isDirty: isDirty,
        markDirty: markDirty,
        getState: getState
      };
    })();
    
    // FileMaker から呼びやすいグローバル関数も用意
    window.fmLoadFromFM = function (param) {
      return window.FMBridge.loadFromFM(param);
    };
    
    window.fmSaveToFM = function () {
      return window.FMBridge.saveToFM();
    };
    
    window.fmReloadFromFM = function () {
      return window.FMBridge.reloadFromFM();
    };
    
    window.fmPing = function (param) {
      console.log("fmPing called:", param);
    
      if (window.FileMaker && typeof window.FileMaker.PerformScript === "function") {
        try {
          window.FileMaker.PerformScript("JSPing", param || "ping");
        } catch (e) {
          console.error(e);
        }
      }
    
      return "ok";
    };

    WebCacheKey を数字タイプに変更します。
    「オプション」をクリックします。

    画像

    データ格納タブのグローバル格納をクリックします。

    画像

    名前を WebCacheKey_G に変更します。

    画像


    Webビューアの計算式を以下のように変更します

    画像
    Let ([
    
      cacheKey = Master::EditorVersion ;
      cacheKey2 = knowledgeDB::WebCacheKey_G ;
      serverHost = Get ( ホスト IP アドレス ) ;
      editorPath = "/editor/editor.html" ;
      
      URL = "http://" & serverHost & editorPath & "?v=" & cacheKey & "&c=" & cacheKey2
    ] ;
      URL
    )
    


    EditorReady のスクリプトを以下のようにします。
    Editor_Open の内容をコピペして、「WebビューアでJavaScriptを実行」の関数名を変更しています。
    また、一時停止も無効化しています。

    画像

    Editor_Open スクリプトを以下のように変更します。

    画像


    これでどうだ!!!


    画像
    画像
    画像

    やったー☺️
    成功です!!
    左上の「<」「>」ボタンでレコードを切り替えると
    自動的にHTMLエディタの内容も変わるようになりました!

    ・HTMLエディタを準備したときに「HTML_Content」の
     内容を読み込むように変更したこと。

    ・WebCacheKey_G をWebビューアの表示に追加し、
     レコードの切り替えなどでURLを毎回変更させるようにした

    この2点が大きかったと思います☺️

    それにしてもWebDirectでここまでハマるとは思わなかったです💦


    TIP💡:スクリプトステップの無効化

    スクリプトを作成していたときにグレーアウトしていたと思います。
    コメントアウトしてスクリプトステップを実行されないようにしています。

    無効化したいスクリプトステップを選択し、Ctrl + / (スラッシュ)で無効化できるようになっています☺️


    堅牢化は不要

    堅牢化はHTMLエディタが準備中にJavaScriptを実行しないようにする処理でした。
    今回はFileMakerからJavaScriptを呼ばなくなったので、
    そもそも不要な処理になりました。


    WebDirectでの動作検証

    ようやく正常に表示されるようになったので、
    動作検証をしていきたいと思います。

    まず、保存ができるのか。

    画像
    ドキドキ。

    「保存」をクリックして、レコードを切り替え、
    このレコードに戻って来ると保存されていました☺️✨

    次は画像を保存できるか。

    画像
    ドキドキ。

    こちらも「保存」をクリックして、レコードを切り替え、
    このレコードに戻って来ると保存されていました☺️✨

    これで基本的な動作は問題なさそうです☺️✨

    ・・・

    これでHTMLエディタ側のページは一旦完成です!
    次は、参照用のレイアウトを作成しましょう!

    といってもとても簡単です☺️


    参照画面作成

    今まで「knowledgeDB」と言う名前のレイアウトでしたが、
    「knowledgeDB_Editor」に名前を変更します。
    「レイアウト」→「レイアウト設定」

    画像
    レイアウト名を変更します

    「レイアウト」をクリックすると、
    「knowledgeDB_Editor コピー」というレイアウトが一番下にできているので「knowledgeDB_Viewer」という名前に変更してください。

    画像
    すでに名前を変えてしまいました💦

    「レイアウト」→「レイアウトの設定」→「スクリプトトリガ」で
    OnRecordLoad と OnLayoutEnter のチェックを外してください。

    画像

    左上の文字を「参照画面」に変え、
    Webビューアの計算式を以下に変更してください。

    画像
    Let ( [
      html = knowledgeDB::HTML_Content ;
      src =
        "<html>" &
        "<head>" &
        "<meta charset='utf-8'>" &
        "<style>" &
        "body{font-family:'Meiryo','Yu Gothic',sans-serif;padding:16px;line-height:1.6;}" &
        "img{max-width:100%;height:auto;}" &
        "</style>" &
        "</head>" &
        "<body>" & html & "</body></html>"
    ] ;
      "data:text/html;base64," & Base64Encode ( src )
    )
    
    


    これで参照ができるようになりました☺️✨

    画像
    やったー!

    右側に「knowledgeDB::HTML_Content」を検索用に表示しました。
    フィールド入力のところの「ブラウズ」のチェックを外し、
    「検索モード」だけにします。

    ここにはHTMLの内容がそのまま入っているため、
    ここで検索すると全文検索ができるようになります。

    画像

    WebDirectでも文字化けせず表示されているのか?


    画像
    文字化けしていました…

    ChatGPTに相談しました。
    WebDirectはこの charset=UTF-8 の有無で挙動が変わることがあるとのこと。

    参照用のWebビューアの計算式を以下のように変更します。

    Let ( [
      html = knowledgeDB::HTML_Content ;
      src =
        "<html>" &
        "<head>" &
        "<meta charset='utf-8'>" &
        "<style>" &
        "body{font-family:'Meiryo','Yu Gothic',sans-serif;padding:16px;line-height:1.6;}" &
        "img{max-width:100%;height:auto;}" &
        "</style>" &
        "</head>" &
        "<body>" & html & "</body></html>"
    ] ;
      "data:text/html;charset=UTF-8;base64," & Base64Encode ( src )
    )

    下に、「charset=UTF-8;」が追加されただけですね。

     "data:text/html;charset=UTF-8;base64," & Base64Encode ( src )

    これを追加すると、文字化けが解消されました☺️
    FileMaker側での表示も問題ありません!


    これで完成です!

    全5回の『FileMakerでナレッジDBをつくるよ!』でしたが、
    いかがでしたでしょうか。

    FileMakerというプラットフォームは、
    案外、社内システムで使われていたり、
    病院内部のシステムで使われていたします。

    でも、あまり実際に開発をどのようにしているのか、
    載せてる人は少ないのではないかと思い、
    このような企画を考えました。
    (そもそも需要が少ないとも言えますが💦)

    誰かの礎になれたらいいなという思いました。
    また、せっかく作ったので誰かに使用してもらいたいとも思いました。

    ここまで長い間お付き合いいただきありがとうございました。
    もし不明点などありましたら、お気軽にコメントでお知らせください。

    では、みなさま、失礼いたします☺️

    いちごいぬ🐶


    今回の生成物

    以下からダウンロードできます☺️
    ご利用前に、免責事項と利用条件をご確認ください。

    Tinymceは含まれていませんので、README.txtを確認し、
    同じフォルダ構造になるように配置してください。

    FileMakerのID/Password
    admin/admin

    免責事項
    本データは、個人または所属組織内での利用を前提として公開しています。著作権は作者に帰属します。
    無断での再配布、販売、改変後の配布・販売、作者の許可のない第三者提供は禁止します。
    本データは現状有姿で提供しており、動作保証・完全性・特定目的への適合性は保証しません。
    本データの利用または利用不能により生じた損害について、作者は一切の責任を負いません。
    同梱または関連する第三者ソフトウェアには、それぞれのライセンスが適用されます。



    #FileMaker #社内ナレッジ #ナレッジベース #ナレッジマネジメント #業務改善 #社内DX #情報整理 #ドキュメント管理 #FAQ #RAG #生成AI #ローカルLLM #ベクトルDB #セマンティック検索 #OCR #OneNote #Python #TinyMCE #JavaScript #WebViewer #WebView2 #DataAPI #FileMakerServer #WebDirect #システム設計 #保守運用 #内製開発 #検証ログ #連載企画



     
     
    「ちょっと疲れた心に、やさしいAIの居場所を。」 現代の孤独や生きにくさをAIの力で少しでも和らげたい。 そんな想いから、“ゆるこみ”プロジェクトを始動しました。 もし共感してもらえたら、固定記事を読んでみてください😊

    あなたへのおすすめ