<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>tsono-about</title><link>https://about.tsono.org</link><description>tsono-aboutの記事一覧</description><lastBuildDate>Mon, 21 Sep 2026 00:00:00 GMT</lastBuildDate><item><title>AIが作ったレシピ　やきうどん</title><link>https://about.tsono.org/articles/ai-yaki-udon</link><guid isPermaLink="true">https://about.tsono.org/articles/ai-yaki-udon</guid><pubDate>Mon, 21 Sep 2026 00:00:00 GMT</pubDate><description>やきうどん</description><content:encoded><![CDATA[<p>またAIにレシピ依頼してみた</p>
<h2 id="プロンプト"><a href="https://about.tsono.org/articles/ai-yaki-udon#%E3%83%97%E3%83%AD%E3%83%B3%E3%83%97%E3%83%88">プロンプト</a></h2>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>人参、ネギ、ピーマンと豚肉と冷凍うどんを使った焼きうどんのレシピを教えてください。肉は豚で豚こまなんで柔らかくしたいです。</span></span></code></pre>
<h2 id="回答"><a href="https://about.tsono.org/articles/ai-yaki-udon#%E5%9B%9E%E7%AD%94">回答</a></h2>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>大人2人分で、**豚こま220g・冷凍うどん2玉**を想定します。豚こまは「酒＋片栗粉」で下処理すると、パサつきにくく柔らかくなります。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>## 豚こまと野菜の醤油焼きうどん</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>### 材料（2人分）</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- 冷凍うどん：2玉</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- 豚こま肉：220g</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- にんじん：1/2本</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- 長ネギ：1/2〜1本</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- ピーマン：2個</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- サラダ油：小さじ1</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- かつお節：あれば</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>**豚肉の下味**</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- 酒：大さじ1</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- 片栗粉：小さじ2</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- 塩：ひとつまみ</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>**合わせ調味料**</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- 醤油：大さじ1と1/2</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- めんつゆ（2倍濃縮）：大さじ1</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- みりん：大さじ1</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- 酒：大さじ1</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- 和風だしの素：小さじ1/2</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>### ① 豚こまを柔らかくする</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>豚こまに、</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>**酒 大さじ1 → 塩ひとつまみ → 片栗粉 小さじ2**</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>の順で揉み込みます。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>そのまま**10〜15分**置いてください。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>片栗粉が肉の表面を薄く覆うので、加熱したときに水分が抜けにくくなります。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>### ② 野菜を切る</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- にんじん → **細切り**</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- 長ネギ → **斜め切り**</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- ピーマン → **細切り**</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>合わせ調味料も先に混ぜておきます。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>### ③ 冷凍うどんをレンジ加熱</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>冷凍うどん2玉を、**商品の表示どおりに電子レンジで温めます**。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>完全に解凍してほぐしておいて大丈夫です。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>### ④ 豚肉を焼く</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>フライパンに油小さじ1を入れて、**強めの中火**。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>豚肉を広げて入れ、最初はあまり動かさず焼き色をつけます。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>裏返して炒め、**ほぼ火が通ったところ**で次へ進みます。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>### ⑤ 野菜を炒める</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>豚肉が入ったまま、</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>**にんじん → ネギ → ピーマン**</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>の順に加えます。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>にんじんとネギを1〜2分炒めてからピーマンを入れ、さらに1分ほど。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>野菜はクタクタにせず、少し食感を残します。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>### ⑥ うどんを投入</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>レンジで温めたうどん2玉を加えます。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>豚肉・野菜とうどんをざっくり混ぜ合わせます。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>### ⑦ 味付けして仕上げる</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>合わせ調味料を回しかけます。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>ここから**強めの中火〜強火で1分程度**。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>汁気を飛ばしながら全体を炒めます。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>最後にフライパンの底で醤油が少し焼けて、**香ばしい匂いがしてきたら完成**です。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>味見して薄ければ、醤油を小さじ1/2程度追加してください。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>仕上げに**かつお節＋黒こしょう**がおすすめです。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>**豚肉の下処理 → 野菜を切る → うどんレンチン → 豚肉 → にんじん → ネギ → ピーマン → うどん → 合わせ調味料**</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>この順番で作ればOKです。</span></span></code></pre>
<h2 id="作ってみた"><a href="https://about.tsono.org/articles/ai-yaki-udon#%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%9F">作ってみた</a></h2>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/a2ee35f7cd5e72c9/640.avif 640w, https://about.tsono.org/images/generated/a2ee35f7cd5e72c9/960.avif 960w, https://about.tsono.org/images/generated/a2ee35f7cd5e72c9/1280.avif 1280w, https://about.tsono.org/images/generated/a2ee35f7cd5e72c9/1920.avif 1920w, https://about.tsono.org/images/generated/a2ee35f7cd5e72c9/4032.avif 4032w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/a2ee35f7cd5e72c9/640.webp 640w, https://about.tsono.org/images/generated/a2ee35f7cd5e72c9/960.webp 960w, https://about.tsono.org/images/generated/a2ee35f7cd5e72c9/1280.webp 1280w, https://about.tsono.org/images/generated/a2ee35f7cd5e72c9/1920.webp 1920w, https://about.tsono.org/images/generated/a2ee35f7cd5e72c9/4032.webp 4032w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/ai-yaki-udon/meal.jpg" alt="豚こまと野菜の焼きうどんの写真" width="4032" height="3024" loading="lazy" decoding="async"></picture>
<p>好みで勝手にニンニクスライスを入れてみた、めちゃくちゃうまい</p>
<h2 id="感想"><a href="https://about.tsono.org/articles/ai-yaki-udon#%E6%84%9F%E6%83%B3">感想</a></h2>
<p>うまい。</p><p><a href="https://about.tsono.org/articles/ai-yaki-udon">元の記事を読む</a></p>]]></content:encoded></item><item><title>AIが作ったレシピ　豚肉トマトチーズ丼</title><link>https://about.tsono.org/articles/ai-recipe</link><guid isPermaLink="true">https://about.tsono.org/articles/ai-recipe</guid><pubDate>Sat, 19 Sep 2026 00:00:00 GMT</pubDate><description>豚肉トマトチーズ丼</description><content:encoded><![CDATA[<p>最近、ChatGPTにレシピを聞いてそのまま夕飯を作ることが多いんですが、なかなか美味しいのでメモ</p>
<h2 id="プロンプト"><a href="https://about.tsono.org/articles/ai-recipe#%E3%83%97%E3%83%AD%E3%83%B3%E3%83%97%E3%83%88">プロンプト</a></h2>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>夕飯</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>ご飯350g</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>豚肉200グラム</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>とろけるチーズ</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>たまねぎ</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>たまご</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>とまと大きいの1つ</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>がある、おとなふたりぶん、なにがいいかな？</span></span></code></pre>
<h2 id="回答"><a href="https://about.tsono.org/articles/ai-recipe#%E5%9B%9E%E7%AD%94">回答</a></h2>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>その材料なら、**豚肉とトマトのチーズ卵丼**が一番まとまりやすいです。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>ご飯350gなら大人2人分にちょうどよく、豚肉200gもしっかり使えます。トマトの酸味とチーズがかなり合います。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>### 豚肉とトマトのチーズ卵丼</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>**2人分**</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- ご飯：350g</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- 豚肉：200g</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- 玉ねぎ：1/2〜1個</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- 大きいトマト：1個</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- 卵：2〜3個</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- とろけるチーズ：50〜70gくらい</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- 油：少量</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>味付けは、</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- 醤油：大さじ1.5</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- みりん：大さじ1</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- 砂糖：小さじ1</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- 酒：大さじ1</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>- ※酒がなければ水でもOK</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>**作り方**</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>1. 玉ねぎを薄切り、トマトを2cmくらいの角切り、豚肉を食べやすい大きさにする。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>2. フライパンで豚肉を炒める。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>3. 豚肉に火が通ってきたら玉ねぎを加え、しんなりするまで炒める。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>4. 醤油・みりん・砂糖・酒を加えて1〜2分煮る。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>5. トマトを加えて、崩しすぎない程度に1分ほど加熱。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>6. 溶き卵を全体に流し入れる。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>7. すぐにチーズを散らして蓋をし、弱火で1〜2分。卵が半熟くらいになったら火を止める。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>8. ご飯175gずつにのせて完成。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>ポイントは**トマトを最後の方に入れること**です。早く入れると水分がかなり出ます。</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>昨日のチーズオムライス系とは少し方向を変えつつ、**豚丼＋親子丼＋チーズトマト**の中間みたいな感じになります。黒こしょうがあれば最後に振るとかなり合います。</span></span></code></pre>
<h2 id="作ってみた"><a href="https://about.tsono.org/articles/ai-recipe#%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%9F">作ってみた</a></h2>
<p>なお卵は入れてないのと、好みで薄切りにんにくを入れた</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/a118c7b11493f18c/640.avif 640w, https://about.tsono.org/images/generated/a118c7b11493f18c/960.avif 960w, https://about.tsono.org/images/generated/a118c7b11493f18c/1280.avif 1280w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/a118c7b11493f18c/640.webp 640w, https://about.tsono.org/images/generated/a118c7b11493f18c/960.webp 960w, https://about.tsono.org/images/generated/a118c7b11493f18c/1280.webp 1280w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/ai-recipe/meal.jpg" alt="豚肉トマトチーズ丼の写真" width="1280" height="960" loading="lazy" decoding="async"></picture>
<h2 id="感想"><a href="https://about.tsono.org/articles/ai-recipe#%E6%84%9F%E6%83%B3">感想</a></h2>
<p>うまい。ゴロゴロトマトが甘くて、酸味もあってうまい。とろけるチーズもうまい。</p><p><a href="https://about.tsono.org/articles/ai-recipe">元の記事を読む</a></p>]]></content:encoded></item><item><title>macOSアプリの開発ワークフロー 2026年8月版</title><link>https://about.tsono.org/articles/ai-development-workflow-ugen</link><guid isPermaLink="true">https://about.tsono.org/articles/ai-development-workflow-ugen</guid><pubDate>Thu, 27 Aug 2026 00:00:00 GMT</pubDate><description>macOSアプリ開発のワークフロー。</description><content:encoded><![CDATA[<h2 id="前提"><a href="https://about.tsono.org/articles/ai-development-workflow-ugen#%E5%89%8D%E6%8F%90">前提</a></h2>
<p>マインドマップのmacOSネイティブアプリケーションを作っています。</p>
<h2 id="意識していること"><a href="https://about.tsono.org/articles/ai-development-workflow-ugen#%E6%84%8F%E8%AD%98%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E3%81%93%E3%81%A8">意識していること</a></h2>
<ul>
<li>決定論的な操作はスクリプトにして、Codexに使ってもらう。</li>
<li>判断基準はMarkdownに書き、Codexに判断してもらう。</li>
</ul>
<h2 id="流れ"><a href="https://about.tsono.org/articles/ai-development-workflow-ugen#%E6%B5%81%E3%82%8C">流れ</a></h2>
<ol>
<li>新しい機能を思いつく</li>
<li>自分で仕様の方針を決める（ときにはCodexとアイデア壁打ち）</li>
<li>自分で仕様の各ケースを思いつく限り列挙する</li>
<li><a href="https://github.com/tsonobe1/agent-skills/tree/main/skills/grill-with-docs"><code>grill-with-docs</code></a> スキルを使って仕様詰めを行う</li>
<li>詰め切ったら <a href="https://github.com/tsonobe1/agent-skills/tree/main/skills/to-tickets"><code>to-tickets</code></a> スキルと <a href="https://github.com/tsonobe1/agent-skills/tree/main/skills/group-feature"><code>group-feature</code></a> スキルでGitHubのイシューにする（<a href="https://about.tsono.org/articles/ai-development-workflow-ugen#1-issue%E3%81%A7%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E7%AE%A1%E7%90%86%E3%82%92%E3%81%99%E3%82%8B">※1</a>）</li>
<li>イシューの内容・粒度をレビューする（<a href="https://about.tsono.org/articles/ai-development-workflow-ugen#1-issue%E3%81%A7%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E7%AE%A1%E7%90%86%E3%82%92%E3%81%99%E3%82%8B">※1</a>）</li>
<li>レビュー内容を反映したイシューを作ってもらう（<a href="https://about.tsono.org/articles/ai-development-workflow-ugen#1-issue%E3%81%A7%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E7%AE%A1%E7%90%86%E3%82%92%E3%81%99%E3%82%8B">※1</a>）</li>
<li>初手のissueを <a href="https://github.com/tsonobe1/agent-skills/tree/main/skills/implement"><code>implement</code></a>スキルで専用ワークツリーを作って実装開始（<a href="https://about.tsono.org/articles/ai-development-workflow-ugen#2-%E5%AE%9F%E8%A3%85%E3%82%92%E9%80%B2%E3%82%81%E3%82%8B%E3%81%A8%E3%81%8D">※2</a>）</li>
<li>Implementからレビュー用スキルを読んでレビュー&#x26;修正（<a href="https://about.tsono.org/articles/ai-development-workflow-ugen#2-%E5%AE%9F%E8%A3%85%E3%82%92%E9%80%B2%E3%82%81%E3%82%8B%E3%81%A8%E3%81%8D">※2</a>）</li>
<li>ユニットテスト（<a href="https://about.tsono.org/articles/ai-development-workflow-ugen#3-%E3%83%86%E3%82%B9%E3%83%88%E3%81%AE%E5%AE%9F%E8%A1%8C%E7%92%B0%E5%A2%83">※3</a>）</li>
<li>E2Eテスト（<a href="https://about.tsono.org/articles/ai-development-workflow-ugen#3-%E3%83%86%E3%82%B9%E3%83%88%E3%81%AE%E5%AE%9F%E8%A1%8C%E7%92%B0%E5%A2%83">※3</a>）</li>
<li>Swift Format, SwiftLint, コードの重複確認(jscpd), 未使用コード確認(Perriphery)</li>
<li>追加した機能の打鍵（<a href="https://about.tsono.org/articles/ai-development-workflow-ugen#4-%E5%AE%9F%E3%82%A2%E3%83%97%E3%83%AA%E3%81%A7%E3%81%AE%E7%A2%BA%E8%AA%8D">※4</a>）</li>
<li>指摘があれば修正。なければCommit → Push → PRを作る（<a href="https://about.tsono.org/articles/ai-development-workflow-ugen#5-pr%E3%81%AE%E8%AA%AC%E6%98%8E%E3%81%A8%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC">※5</a>）</li>
<li>@codex review を投げて15分ごと（最大10回）に指摘を確認するようCodexに監視依頼（<a href="https://about.tsono.org/articles/ai-development-workflow-ugen#5-pr%E3%81%AE%E8%AA%AC%E6%98%8E%E3%81%A8%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC">※5</a>）</li>
<li>指摘があれば自動で修正を開始→テスト→コミット→プッシュ→@codex review を投稿→監視（<a href="https://about.tsono.org/articles/ai-development-workflow-ugen#5-pr%E3%81%AE%E8%AA%AC%E6%98%8E%E3%81%A8%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC">※5</a>）</li>
<li>指摘が仕様の変更に伴う場合は開発者に判断を委ねる（<a href="https://about.tsono.org/articles/ai-development-workflow-ugen#5-pr%E3%81%AE%E8%AA%AC%E6%98%8E%E3%81%A8%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC">※5</a>）</li>
<li>指摘がなくなるまで繰り返す（<a href="https://about.tsono.org/articles/ai-development-workflow-ugen#5-pr%E3%81%AE%E8%AA%AC%E6%98%8E%E3%81%A8%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC">※5</a>）</li>
<li>指摘がなくなったら、変更内容に関する資料を投稿（<a href="https://about.tsono.org/articles/ai-development-workflow-ugen#5-pr%E3%81%AE%E8%AA%AC%E6%98%8E%E3%81%A8%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC">※5</a>）</li>
<li>打鍵をしてからマージ（<a href="https://about.tsono.org/articles/ai-development-workflow-ugen#4-%E5%AE%9F%E3%82%A2%E3%83%97%E3%83%AA%E3%81%A7%E3%81%AE%E7%A2%BA%E8%AA%8D">※4</a>）</li>
<li>ワークツリーを閉じる（機能開発のために作成されたビルドやキャッシュ関連も削除する）（<a href="https://about.tsono.org/articles/ai-development-workflow-ugen#6-%E3%83%9E%E3%83%BC%E3%82%B8%E5%BE%8C%E3%81%AE%E7%89%87%E3%81%A5%E3%81%91">※6</a>）</li>
<li>次の issueを implement開始（<a href="https://about.tsono.org/articles/ai-development-workflow-ugen#2-%E5%AE%9F%E8%A3%85%E3%82%92%E9%80%B2%E3%82%81%E3%82%8B%E3%81%A8%E3%81%8D">※2</a>）</li>
</ol>
<h3 id="工夫"><a href="https://about.tsono.org/articles/ai-development-workflow-ugen#%E5%B7%A5%E5%A4%AB">工夫</a></h3>
<h4 id="1-issueでプロジェクト管理をする"><a href="https://about.tsono.org/articles/ai-development-workflow-ugen#1-issue%E3%81%A7%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E7%AE%A1%E7%90%86%E3%82%92%E3%81%99%E3%82%8B">※1 Issueでプロジェクト管理をする</a></h4>
<p><a href="https://github.com/tsonobe1/agent-skills/tree/main/skills/group-feature"><code>group-feature</code></a>は、to-tickets で作ったIssueをSub Issueとしてまとめた親Issueを作るスキル。親Issueにはfeatureラベルをつけるため、GitHub のProjectでラベル絞り込みをすることで、機能単位と作業単位で分けて進捗管理ができる</p>
<p>Feature Issue = 機能管理</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/251b0ee1570b03a1/640.avif 640w, https://about.tsono.org/images/generated/251b0ee1570b03a1/960.avif 960w, https://about.tsono.org/images/generated/251b0ee1570b03a1/1280.avif 1280w, https://about.tsono.org/images/generated/251b0ee1570b03a1/1669.avif 1669w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/251b0ee1570b03a1/640.webp 640w, https://about.tsono.org/images/generated/251b0ee1570b03a1/960.webp 960w, https://about.tsono.org/images/generated/251b0ee1570b03a1/1280.webp 1280w, https://about.tsono.org/images/generated/251b0ee1570b03a1/1669.webp 1669w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/ai-development-workflow-ugen/feature-board.png" alt="Feature" width="1669" height="942" loading="lazy" decoding="async"></picture>
<p>Sub issue = 作業単位</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/05358ad59e17b937/640.avif 640w, https://about.tsono.org/images/generated/05358ad59e17b937/960.avif 960w, https://about.tsono.org/images/generated/05358ad59e17b937/1280.avif 1280w, https://about.tsono.org/images/generated/05358ad59e17b937/1577.avif 1577w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/05358ad59e17b937/640.webp 640w, https://about.tsono.org/images/generated/05358ad59e17b937/960.webp 960w, https://about.tsono.org/images/generated/05358ad59e17b937/1280.webp 1280w, https://about.tsono.org/images/generated/05358ad59e17b937/1577.webp 1577w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/ai-development-workflow-ugen/sub-issue-board.png" alt="Sub issue" width="1577" height="997" loading="lazy" decoding="async"></picture>
<h4 id="2-実装を進めるとき"><a href="https://about.tsono.org/articles/ai-development-workflow-ugen#2-%E5%AE%9F%E8%A3%85%E3%82%92%E9%80%B2%E3%82%81%E3%82%8B%E3%81%A8%E3%81%8D">※2 実装を進めるとき</a></h4>
<h5 id="依存関係のないissueは並列で実装する"><a href="https://about.tsono.org/articles/ai-development-workflow-ugen#%E4%BE%9D%E5%AD%98%E9%96%A2%E4%BF%82%E3%81%AE%E3%81%AA%E3%81%84issue%E3%81%AF%E4%B8%A6%E5%88%97%E3%81%A7%E5%AE%9F%E8%A3%85%E3%81%99%E3%82%8B">依存関係のないIssueは並列で実装する</a></h5>
<p>to-ticketsは依存関係でIssueを分割してくれるので、依存がなければ並列でimplementする</p>
<h5 id="作業の競合を確認する"><a href="https://about.tsono.org/articles/ai-development-workflow-ugen#%E4%BD%9C%E6%A5%AD%E3%81%AE%E7%AB%B6%E5%90%88%E3%82%92%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B">作業の競合を確認する</a></h5>
<p>複数のworktreeで作業するため、着手前でbranchや変更ファイルの重なりを確認する。情報収集はスクリプトを用意しており、その判断はMarkdownでルールを決めている。Codexはそれらを使って情報収集及び判断を行う。</p>
<h4 id="3-テストの実行環境"><a href="https://about.tsono.org/articles/ai-development-workflow-ugen#3-%E3%83%86%E3%82%B9%E3%83%88%E3%81%AE%E5%AE%9F%E8%A1%8C%E7%92%B0%E5%A2%83">※3 テストの実行環境</a></h4>
<h5 id="テストは副作用に応じてホストとvmを分ける"><a href="https://about.tsono.org/articles/ai-development-workflow-ugen#%E3%83%86%E3%82%B9%E3%83%88%E3%81%AF%E5%89%AF%E4%BD%9C%E7%94%A8%E3%81%AB%E5%BF%9C%E3%81%98%E3%81%A6%E3%83%9B%E3%82%B9%E3%83%88%E3%81%A8vm%E3%82%92%E5%88%86%E3%81%91%E3%82%8B">テストは副作用に応じてホストとVMを分ける</a></h5>
<p>ロジックだけを確認するテストはホストPCで実行し、アプリの前面化、キーボード入力、Pasteboardの操作など、ホストPCに影響するテストは <a href="https://github.com/openai/tart">Tart</a> のVMで実行している。これにより、ホストPCの操作への干渉を防ぐ。</p>
<p>どのテストをホストPCとVMのどちらで実行するか、同時に何件まで実行するかという判断基準はMarkdownにルールを書いている。</p>
<p>VMへのソースの転送、VMの起動、テスト、結果の回収、停止はスクリプトを用意しているので、Codexは実行するテストを選び、決まった手順はスクリプトに任せる。</p>
<h5 id="ビルドの同時実行数を制限する"><a href="https://about.tsono.org/articles/ai-development-workflow-ugen#%E3%83%93%E3%83%AB%E3%83%89%E3%81%AE%E5%90%8C%E6%99%82%E5%AE%9F%E8%A1%8C%E6%95%B0%E3%82%92%E5%88%B6%E9%99%90%E3%81%99%E3%82%8B">ビルドの同時実行数を制限する</a></h5>
<p>ビルドやVMを使ったUIテストなどは、共通のスクリプトを通すことで同時実行数を管理している（同時に行われるとPCがアチアチになってしまうので）。実行要求は共通のFIFOキューに入り、順番が来るのを待つ。</p>
<h4 id="4-実アプリでの確認"><a href="https://about.tsono.org/articles/ai-development-workflow-ugen#4-%E5%AE%9F%E3%82%A2%E3%83%97%E3%83%AA%E3%81%A7%E3%81%AE%E7%A2%BA%E8%AA%8D">※4 実アプリでの確認</a></h4>
<p>複数のworktreeで開発していると、別のbranchや古いビルドのアプリを確認してしまうことがあるため、起動用スクリプトを使い、識別用のラベルを表示する。設定とSQLiteも分け、どのコードを打鍵したのかを明確にしている。</p>
<p>起動中のアプリには、アプリ名とbranch名を表示する。</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/efc9043961008464/640.avif 640w, https://about.tsono.org/images/generated/efc9043961008464/960.avif 960w, https://about.tsono.org/images/generated/efc9043961008464/1280.avif 1280w, https://about.tsono.org/images/generated/efc9043961008464/1324.avif 1324w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/efc9043961008464/640.webp 640w, https://about.tsono.org/images/generated/efc9043961008464/960.webp 960w, https://about.tsono.org/images/generated/efc9043961008464/1280.webp 1280w, https://about.tsono.org/images/generated/efc9043961008464/1324.webp 1324w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/ai-development-workflow-ugen/manual-check-identity.png" alt="起動中のアプリのタイトルバーに表示したアプリ名とbranch名" width="1324" height="132" loading="lazy" decoding="async"></picture>
<h4 id="5-prの説明とレビュー"><a href="https://about.tsono.org/articles/ai-development-workflow-ugen#5-pr%E3%81%AE%E8%AA%AC%E6%98%8E%E3%81%A8%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC">※5 PRの説明とレビュー</a></h4>
<h5 id="prに変更内容を説明する資料を載せる"><a href="https://about.tsono.org/articles/ai-development-workflow-ugen#pr%E3%81%AB%E5%A4%89%E6%9B%B4%E5%86%85%E5%AE%B9%E3%82%92%E8%AA%AC%E6%98%8E%E3%81%99%E3%82%8B%E8%B3%87%E6%96%99%E3%82%92%E8%BC%89%E3%81%9B%E3%82%8B">PRに変更内容を説明する資料を載せる</a></h5>
<p>PRには、何を変えたか、どのように確認したか、まだ人が確認する項目があるかをまとめる。変更の構造が伝わりにくいときは、図も載せる。</p>
<h5 id="prレビューを監視する"><a href="https://about.tsono.org/articles/ai-development-workflow-ugen#pr%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC%E3%82%92%E7%9B%A3%E8%A6%96%E3%81%99%E3%82%8B">PRレビューを監視する</a></h5>
<p>PRを作ったセッションに、PRごとに1つのheartbeat監視を紐づけるスクリプトを作って、それをCodexに実行させている。いつ確認し、どの指摘なら自動で直してよいかという監視ルールはMarkdownに書いている。</p>
<ul>
<li>15分ごと、最大10回繰り返す</li>
<li>監視によりレビュー指摘を発見したら自動で修正に入る</li>
<li>新しいcommitをpushしたら@codex reviewを投稿して、再び監視</li>
</ul>
<h5 id="直せる指摘は自動で修正する"><a href="https://about.tsono.org/articles/ai-development-workflow-ugen#%E7%9B%B4%E3%81%9B%E3%82%8B%E6%8C%87%E6%91%98%E3%81%AF%E8%87%AA%E5%8B%95%E3%81%A7%E4%BF%AE%E6%AD%A3%E3%81%99%E3%82%8B">直せる指摘は自動で修正する</a></h5>
<p>仕様変更を伴わない指摘は、再現→修正→テスト→commit→push→スレッド返信→再レビュー依頼まで自動で行う。</p>
<h5 id="仕様変更を伴う指摘は開発者が判断する"><a href="https://about.tsono.org/articles/ai-development-workflow-ugen#%E4%BB%95%E6%A7%98%E5%A4%89%E6%9B%B4%E3%82%92%E4%BC%B4%E3%81%86%E6%8C%87%E6%91%98%E3%81%AF%E9%96%8B%E7%99%BA%E8%80%85%E3%81%8C%E5%88%A4%E6%96%AD%E3%81%99%E3%82%8B">仕様変更を伴う指摘は開発者が判断する</a></h5>
<p>Issueや仕様変更を伴う指摘は自動修正せず、開発者に判断を委ねる。</p>
<h4 id="6-マージ後の片づけ"><a href="https://about.tsono.org/articles/ai-development-workflow-ugen#6-%E3%83%9E%E3%83%BC%E3%82%B8%E5%BE%8C%E3%81%AE%E7%89%87%E3%81%A5%E3%81%91">※6 マージ後の片づけ</a></h4>
<p>マージ後のworktreeはすぐに削除せず、退役用スクリプトでキューに入れる。未commitの変更や使用中のprocessなど、削除してよい条件はMarkdownに書き、安全なものだけを削除する。</p><p><a href="https://about.tsono.org/articles/ai-development-workflow-ugen">元の記事を読む</a></p>]]></content:encoded></item><item><title>GitHubでPRが勝手にクローズされる現象</title><link>https://about.tsono.org/articles/github-pr-auto-close</link><guid isPermaLink="true">https://about.tsono.org/articles/github-pr-auto-close</guid><pubDate>Sat, 22 Aug 2026 00:00:00 GMT</pubDate><description>GitHubのClosing keywordsが、独自タスク番号とIssue・PR番号の偶然の一致によって、関係のないPRを自動的にクローズしていた原因と対策。</description><content:encoded><![CDATA[<p>自分の意図と異なるPRが勝手にクローズされていたので調べた。</p>
<h2 id="前提"><a href="https://about.tsono.org/articles/github-pr-auto-close#%E5%89%8D%E6%8F%90">前提</a></h2>
<h3 id="タスク管理の方法"><a href="https://about.tsono.org/articles/github-pr-auto-close#%E3%82%BF%E3%82%B9%E3%82%AF%E7%AE%A1%E7%90%86%E3%81%AE%E6%96%B9%E6%B3%95">タスク管理の方法</a></h3>
<p>今のPJでは、GitHub Issueとは別に独自のタスクリストを管理している。</p>
<p>各タスクには、次のように番号が振られており、基本的にこのタスクをもとに作業してPRを作っている。</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>No.998</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>No.999</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>No.1000</span></span></code></pre>
<h3 id="prタイトルの付け方"><a href="https://about.tsono.org/articles/github-pr-auto-close#pr%E3%82%BF%E3%82%A4%E3%83%88%E3%83%AB%E3%81%AE%E4%BB%98%E3%81%91%E6%96%B9">PRタイトルの付け方</a></h3>
<p>PRを作成するときは、どのタスクに対する対応なのか分かるように、タイトルへタスクNo.を記載している。</p>
<p>例えば、次のようなタイトルにしている。</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>fix #999 ○○を修正</span></span></code></pre>
<p>ここでの <code>#999</code> はGitHubのIssueやPRを表しているわけではなく、PJ独自のタスクNo.999という意図だった。</p>
<h3 id="発生した事象"><a href="https://about.tsono.org/articles/github-pr-auto-close#%E7%99%BA%E7%94%9F%E3%81%97%E3%81%9F%E4%BA%8B%E8%B1%A1">発生した事象</a></h3>
<p>あるPRをマージしたタイミングで、関係のないOpen中のPRがCloseされた。</p>
<p>自分ではCloseしていないはずなのに、GitHub上では自分がCloseしたことになっていた。</p>
<h2 id="原因"><a href="https://about.tsono.org/articles/github-pr-auto-close#%E5%8E%9F%E5%9B%A0">原因</a></h2>
<h3 id="githubのclosing-keywords"><a href="https://about.tsono.org/articles/github-pr-auto-close#github%E3%81%AEclosing-keywords">GitHubのClosing keywords</a></h3>
<p>GitHubには、PRやコミットからIssueを自動的にCloseするための <strong>Closing keywords</strong> という仕組みがある。</p>
<p><a href="https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests">Using keywords in issues and pull requests</a></p>
<p>例えば、次のような表現がClosing keywordsとして認識される。</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>fix #999</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>fixes #999</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>close #999</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>closes #999</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>resolve #999</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>resolves #999</span></span></code></pre>
<p>このように書かれたPRやコミットが <strong>デフォルトブランチ</strong> へマージされると、参照されている <code>#999</code> を自動的にCloseできる。</p>
<p>通常であれば、</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>fix #999</span></span></code></pre>
<p>と書くことで、</p>
<blockquote>
<p>この変更によってGitHub Issue #999が解決する</p>
</blockquote>
<p>という意味になる。</p>
<p>ただし、GitHubの <code>#999</code> はIssueだけではなくPull Requestを指す場合もある。</p>
<p><code>#999</code> がOpen中のPRだった場合、そのPR自体がCloseされる。</p>
<h3 id="タスクnoとpr番号の一致"><a href="https://about.tsono.org/articles/github-pr-auto-close#%E3%82%BF%E3%82%B9%E3%82%AFno%E3%81%A8pr%E7%95%AA%E5%8F%B7%E3%81%AE%E4%B8%80%E8%87%B4">タスクNo.とPR番号の一致</a></h3>
<p>今回のPJでは、次の番号がそれぞれ別に採番されている。</p>
<ul>
<li>PJ独自のタスクNo.</li>
<li>GitHubのIssue / PR番号</li>
</ul>
<p>そして、両者の番号が近くなっていた。</p>
<p>例えば、次のような状態だった。</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>PJ独自のタスク: No.999</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>GitHub上のPR:   #999</span></span></code></pre>
<p>この状態で、タスクNo.999に対応したPRへ、次のように記載した。</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>fix #999</span></span></code></pre>
<p>こちらの意図は、</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>タスク No.999 を修正</span></span></code></pre>
<p>というものだったが、GitHubは、</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>GitHub上の #999 を修正</span></span></code></pre>
<p>と解釈する。</p>
<p>その結果、次の流れでPRがCloseされていた。</p>
<ol>
<li><code>fix #999</code> と書かれたPRをマージする</li>
<li>GitHubがClosing keywordとして認識する</li>
<li>GitHubがGitHub上の <code>#999</code> を参照する</li>
<li><code>#999</code> がOpen中のPRだった場合、PR #999がCloseされる</li>
</ol>
<p>つまり、<strong>PJ独自のタスクNo.とGitHub上のIssue / PR番号が偶然一致したことで、自動Closeが発生していた</strong>。</p>
<h2 id="対応策"><a href="https://about.tsono.org/articles/github-pr-auto-close#%E5%AF%BE%E5%BF%9C%E7%AD%96">対応策</a></h2>
<h3 id="タスクnoの表記方法"><a href="https://about.tsono.org/articles/github-pr-auto-close#%E3%82%BF%E3%82%B9%E3%82%AFno%E3%81%AE%E8%A1%A8%E8%A8%98%E6%96%B9%E6%B3%95">タスクNo.の表記方法</a></h3>
<p>独自の番号をPRへ記載する場合は、GitHubのIssue / PR参照と誤認されない形式にするとよい。</p>
<p>例えば、次のように <code>#</code> を付けない形にする。</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>fix 課題999</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>fix 999</span></span></code></pre>
<p>GitHubのClosing keywordsは、IssueやPR番号と組み合わせて使われるため、独自タスク番号には <code>#</code> を付けないようにする。</p>
<h2 id="まとめ"><a href="https://about.tsono.org/articles/github-pr-auto-close#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2>
<p>GitHubのPRタイトルやコミットメッセージに <code>fix #999</code> のような表現を書くと、意図せずClosing keywordsとして解釈されることがある。</p>
<p>独自のタスク番号を表すために <code>#</code> を使っている場合は、GitHubのIssue / PR番号と衝突する可能性がある。</p>
<p>Closing keywords、知らなかったぜ...</p><p><a href="https://about.tsono.org/articles/github-pr-auto-close">元の記事を読む</a></p>]]></content:encoded></item><item><title>JetBrains の File Structure でテストコードを俯瞰する</title><link>https://about.tsono.org/articles/jetbrains-file-structure</link><guid isPermaLink="true">https://about.tsono.org/articles/jetbrains-file-structure</guid><pubDate>Sat, 28 Feb 2026 00:00:00 GMT</pubDate><description>File structure が テストコードを俯瞰するときに便利。</description><content:encoded><![CDATA[<p>最近はAIにテストコードを書かせている。大量にかつフラットに書かれてしまったテストコードを見るのは辛い。</p>
<p>処理の種類・正常/準正常/異常系などで階層を作ることで読みやすく・理解しやすくリファクタリングしたいタイミングが来る。</p>
<p>そんなときに JetBrains 系 IDE で <code>command + 7</code> を押すと表示できる File structure が便利。</p>
<p>構造化前</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/a3aac2c0170bc0b8/640.avif 640w, https://about.tsono.org/images/generated/a3aac2c0170bc0b8/960.avif 960w, https://about.tsono.org/images/generated/a3aac2c0170bc0b8/1210.avif 1210w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/a3aac2c0170bc0b8/640.webp 640w, https://about.tsono.org/images/generated/a3aac2c0170bc0b8/960.webp 960w, https://about.tsono.org/images/generated/a3aac2c0170bc0b8/1210.webp 1210w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/jetbrains-file-structure/before.webp" alt="構造化前" width="1210" height="510" loading="lazy" decoding="async"></picture>
<p>構造化後</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/52935bac8826b062/575.avif 575w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/52935bac8826b062/575.webp 575w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/jetbrains-file-structure/after.webp" alt="構造化後" width="575" height="298" loading="lazy" decoding="async"></picture>
<p>キーボードの矢印で移動すれば右側で開いているファイル内も追従するので、中身の確認もできる。</p>
<p>シンプルに行数が多いファイル内での作業をするときにも便利そうだ.</p>
<p>存在には気がついていたけど、実際使うシーンがなかったので、こういう場面で役に立つのか〜という発見。</p><p><a href="https://about.tsono.org/articles/jetbrains-file-structure">元の記事を読む</a></p>]]></content:encoded></item><item><title>WebStormでプロジェクトを開くと既存ウインドウが置き換わってしまう挙動を変える</title><link>https://about.tsono.org/articles/webstorm-new-window</link><guid isPermaLink="true">https://about.tsono.org/articles/webstorm-new-window</guid><pubDate>Fri, 27 Feb 2026 00:00:00 GMT</pubDate><description>別プロジェクトを開いたときに既存ウインドウが置き換わる問題の解決策。</description><content:encoded><![CDATA[<p>JetBrains系IDE ですでにプロジェクトを開いている状態で新しく Open すると、いま開いているウインドウがそのまま置き換わってしまうことがある。</p>
<p>新規ウインドウで開きたい場合は、<code>Open project in</code> の設定を確認する。</p>
<ol>
<li><code>Settings</code> を開く</li>
<li>検索欄で <code>project opening</code> と入力する</li>
<li><code>Open project in</code> を <code>New Window</code> にする</li>
</ol>
<p>これで次からは、別プロジェクトを新しいウインドウで開ける。</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/42673bab1886ec24/640.avif 640w, https://about.tsono.org/images/generated/42673bab1886ec24/960.avif 960w, https://about.tsono.org/images/generated/42673bab1886ec24/1073.avif 1073w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/42673bab1886ec24/640.webp 640w, https://about.tsono.org/images/generated/42673bab1886ec24/960.webp 960w, https://about.tsono.org/images/generated/42673bab1886ec24/1073.webp 1073w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/webstorm-new-window/image.webp" alt="WebStorm の Project Opening 設定" width="1073" height="834" loading="lazy" decoding="async"></picture>
<p>仕事用PCだと新規ウィンドウで開くのに、私用PCでは置き換わってしまっていた。解決。</p><p><a href="https://about.tsono.org/articles/webstorm-new-window">元の記事を読む</a></p>]]></content:encoded></item><item><title>シン・エヴァンゲリオン劇場版 3.0＋1.01</title><link>https://about.tsono.org/articles/eva-shin</link><guid isPermaLink="true">https://about.tsono.org/articles/eva-shin</guid><pubDate>Sun, 22 Feb 2026 00:00:00 GMT</pubDate><description>先週見た。月一エヴァ、最高な5ヶ月でした</description><content:encoded><![CDATA[<p>先週見た。月一エヴァ、最高な5ヶ月でした</p>
<p>見終わって一週間しても熱が冷めやらない</p>
<p>eva EXTRAEX（通称薄い本）を見返したり、エヴァフェスのニュースなどを見ている</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/25b8e8963093485d/640.avif 640w, https://about.tsono.org/images/generated/25b8e8963093485d/960.avif 960w, https://about.tsono.org/images/generated/25b8e8963093485d/1280.avif 1280w, https://about.tsono.org/images/generated/25b8e8963093485d/1920.avif 1920w, https://about.tsono.org/images/generated/25b8e8963093485d/4032.avif 4032w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/25b8e8963093485d/640.webp 640w, https://about.tsono.org/images/generated/25b8e8963093485d/960.webp 960w, https://about.tsono.org/images/generated/25b8e8963093485d/1280.webp 1280w, https://about.tsono.org/images/generated/25b8e8963093485d/1920.webp 1920w, https://about.tsono.org/images/generated/25b8e8963093485d/4032.webp 4032w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/eva-shin/cards.webp" alt="これまでの入場特典" width="4032" height="3024" loading="lazy" decoding="async"></picture><p><a href="https://about.tsono.org/articles/eva-shin">元の記事を読む</a></p>]]></content:encoded></item><item><title>理解度と速度のバランスを取ったAI駆動の開発ワークフロー</title><link>https://about.tsono.org/articles/workflow-2026-02</link><guid isPermaLink="true">https://about.tsono.org/articles/workflow-2026-02</guid><pubDate>Fri, 20 Feb 2026 00:00:00 GMT</pubDate><description>2026/02/20時点で良い感触のワークフロー。</description><content:encoded><![CDATA[<p>AIが大量に生成するコードに圧倒されることなく、コードへの理解を保ちながら、人間が主導権を握り続けるためのワークフロー。<br>
2026/02/20時点で感触が良いものをメモしておく。<br>
（あくまでも個人開発や厳密さをそこまで要求されない部分での運用）</p>
<h2 id="最初の要件定義"><a href="https://about.tsono.org/articles/workflow-2026-02#%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E4%BB%B6%E5%AE%9A%E7%BE%A9">最初の要件定義</a></h2>
<ol>
<li>システムが満たすべき要件をリストとして列挙する
<ul>
<li>ここは自分で考えて手で書く。漏れや重複を少なく、エッジケースや分岐も細かく考える</li>
<li>出来上がったアプリの動きを妄想する楽しいフェーズ</li>
</ul>
</li>
<li><code>Codex CLI</code>の plan mode で、要件定義したい旨・システムを作る目的・想定ユーザ・1.のリストを投げる
<ul>
<li>ディスカッションをしてヌケモレ重複を解消する</li>
</ul>
</li>
<li>作ってもらった plan を <code>/docs/plan</code> 内に配置してもらう</li>
</ol>
<h2 id="機能設計"><a href="https://about.tsono.org/articles/workflow-2026-02#%E6%A9%9F%E8%83%BD%E8%A8%AD%E8%A8%88">機能設計</a></h2>
<ol>
<li>plan内から1機能（フェーズ1）をピックアップし、詳細度を高めた plan を、plan mode で作成する
<ul>
<li>実装に近い話をディスカッションして決めていく</li>
</ul>
</li>
</ol>
<h2 id="開発"><a href="https://about.tsono.org/articles/workflow-2026-02#%E9%96%8B%E7%99%BA">開発</a></h2>
<ol>
<li>Codex CLI に フェーズ1 に対する TDD用の TODO リストを作成してもらい、<code>.md</code> に追加する
<ul>
<li>TODOリストは自分で作ってもいい</li>
</ul>
</li>
<li>TODO リストをレビューする</li>
<li>TDDのループで実装を進める
<ol>
<li>TODOリストから1件選ぶ</li>
<li>Red: そのケースに対する失敗するテストを1つ追加 or 修正する</li>
<li>Green: テストを通すための最小限の実装を行う</li>
<li>Refactor: テストがグリーンの状態を維持したままリファクタリングする</li>
<li>lint, format, knip を実行</li>
<li>plan を更新する</li>
<li>コミットする</li>
<li>問題なければ別のTODOに進む。</li>
</ol>
</li>
<li>☝のシーケンス内では都度、質問、要件・機能・TODOのブラッシュアップを行う</li>
<li>定期的にテストケースの構造化を行う</li>
</ol>
<h2 id="繰り替えす"><a href="https://about.tsono.org/articles/workflow-2026-02#%E7%B9%B0%E3%82%8A%E6%9B%BF%E3%81%88%E3%81%99">繰り替えす</a></h2>
<ol>
<li>次のフェーズのPlanを作成して開発 -> 次のフェーズの... を繰り返す</li>
</ol>
<h2 id="新しいセッションに入ったとき"><a href="https://about.tsono.org/articles/workflow-2026-02#%E6%96%B0%E3%81%97%E3%81%84%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AB%E5%85%A5%E3%81%A3%E3%81%9F%E3%81%A8%E3%81%8D">新しいセッションに入ったとき</a></h2>
<ul>
<li>上述のTDDの指示を毎回打ち込むのはめんどくさい</li>
<li>また、context が圧迫してきたら plan を更新させた後 <code>/compact</code>するが、<code>/compact</code> 後はワークフローが崩れる</li>
<li>そのため、上述のフローを <a href="https://about.tsono.org/articles/workflow-2026-02#%E5%8F%82%E8%80%83-skills">skills</a>に登録している
<ul>
<li>実装中の plan と次タスクを明示して指示している</li>
</ul>
</li>
</ul>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC"># 指示の例</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">$workflow docs/implementation_plan_phase1-3.md の phase1.5 Case5 の続きを実装する</span></span></code></pre>
<h3 id="参考-skills"><a href="https://about.tsono.org/articles/workflow-2026-02#%E5%8F%82%E8%80%83-skills">参考: skills</a></h3>
<p>大まかに言うと、古典学派・TDDで実装してこうねという話</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line"><span style="--shiki-light:#023B95;--shiki-light-font-weight:bold;--shiki-dark:#91CBFF;--shiki-dark-font-weight:bold">---</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">name: workflow</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">description: Shared collaboration workflow for implementing one TODO case at a time (t-wada style classical TDD). Assumes plan and TODO list are already agreed. Includes explicit review gates and pre-commit quality checks (lint/format/knip).</span></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-light-font-weight:bold;--shiki-dark:#91CBFF;--shiki-dark-font-weight:bold">---</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-light-font-weight:bold;--shiki-dark:#91CBFF;--shiki-dark-font-weight:bold"># Workflow</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-light-font-weight:bold;--shiki-dark:#91CBFF;--shiki-dark-font-weight:bold">## Objective</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">Execute implementation with a strict one-case TDD cadence, using explicit review gates and deterministic diffs.</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-light-font-weight:bold;--shiki-dark:#91CBFF;--shiki-dark-font-weight:bold">## Preconditions</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Plan and TDD TODO list are already agreed.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> We will start from an existing TODO item.</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-light-font-weight:bold;--shiki-dark:#91CBFF;--shiki-dark-font-weight:bold">## Invocation</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">When starting work, the user says:</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> `$workflow に従って、{XX} の {YY} を実装していこう`</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-light-font-weight:bold;--shiki-dark:#91CBFF;--shiki-dark-font-weight:bold">## TDD Loop (One Case Only)</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">1.</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Pick exactly one TODO case (state the TODO id/title explicitly).</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">2.</span><span style="--shiki-light:#0E1116;--shiki-light-font-weight:bold;--shiki-dark:#F0F3F6;--shiki-dark-font-weight:bold"> **Red**</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">: add or adjust one failing test for the case.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">3.</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Ask the user to review the test intent and failing result.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">4.</span><span style="--shiki-light:#0E1116;--shiki-light-font-weight:bold;--shiki-dark:#F0F3F6;--shiki-dark-font-weight:bold"> **Green**</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">: implement the minimum code required to pass the test.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">5.</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Ask the user to review the implementation.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">6.</span><span style="--shiki-light:#0E1116;--shiki-light-font-weight:bold;--shiki-dark:#F0F3F6;--shiki-dark-font-weight:bold"> **Refactor**</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> while keeping tests green.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">7.</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Ask the user to review the refactor.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">8.</span><span style="--shiki-light:#0E1116;--shiki-light-font-weight:bold;--shiki-dark:#F0F3F6;--shiki-dark-font-weight:bold"> **Plan Update (before commit)**</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">:</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">   -</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Reflect the implemented behavior in the plan.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">   -</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Mark the TODO case as completed.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">   -</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Adjust acceptance criteria if clarified during implementation.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">   -</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Record any design decision discovered during the case.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">9.</span><span style="--shiki-light:#0E1116;--shiki-light-font-weight:bold;--shiki-dark:#F0F3F6;--shiki-dark-font-weight:bold"> **Quality Gate (before commit)**</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">:</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">   -</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> run </span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">`lint`</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">   -</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> run </span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">`format`</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">   -</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> run </span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">`knip`</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">   -</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> if any fail: fix minimally, keep scope constrained to the same TODO case.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">10.</span><span style="--shiki-light:#0E1116;--shiki-light-font-weight:bold;--shiki-dark:#F0F3F6;--shiki-dark-font-weight:bold"> **Commit the case**</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">11.</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Move to the next TODO case.</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-light-font-weight:bold;--shiki-dark:#91CBFF;--shiki-dark-font-weight:bold">## Guardrails</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Do not batch multiple TODO cases in one cycle.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> TODO must follow t-wada style, classical style TDD.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">  -</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Behavior-first.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">  -</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Outside-in thinking only when needed.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">  -</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Prefer state verification over interaction verification.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">  -</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> No unnecessary mocking.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Each TODO must represent a single observable behavior.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Test cases must be written structurally.</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">  Use the following structure:</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">  -</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> XXをするYY</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">    -</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> XX のとき YY となる</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Test case names must be written in Japanese.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Test names must describe behavior (condition + result), not method names.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> One test = one behavior.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Do not test multiple branches in a single test.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Avoid implementation detail assertions.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Keep each step observable and explain why the change is needed.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Prefer minimal deterministic diffs.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Pause coding and return to discussion if disagreement appears.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> If scope changes, stop and re-align TODO/acceptance before continuing.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Do not use English identifiers in test names unless domain terminology requires it.</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> The plan must be updated before every commit.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Implementation and plan must remain consistent.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> No commit without plan alignment.</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-light-font-weight:bold;--shiki-dark:#91CBFF;--shiki-dark-font-weight:bold">## Commit Rules</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Commit only after completing Red → Green → Refactor and passing the Quality Gate.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Use short imperative commit messages with prefixes such as </span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">`test`</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">, </span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">`fix`</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">, </span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">`refactor`</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">, </span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">`docs`</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">, </span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">`add`</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">.</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">-</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Keep unrelated changes out of the commit.</span></span></code></pre>
<p>効果的だと感じる文面は、<code>TODO must follow t-wada style, classical style TDD.</code>。</p>
<h2 id="意識してること"><a href="https://about.tsono.org/articles/workflow-2026-02#%E6%84%8F%E8%AD%98%E3%81%97%E3%81%A6%E3%82%8B%E3%81%93%E3%81%A8">意識してること</a></h2>
<ol>
<li>粒度の異なる計画書を作成して、コミット前に更新する
<ul>
<li>進捗把握がしやすくなる</li>
</ul>
</li>
<li>1テストケース単位でコミットすることでPR粒度を小さくする
<ul>
<li>やりとりの頻度は増えるが、レビュー負荷が少なくなる</li>
</ul>
</li>
<li>テストコードを重点的にレビューする
<ul>
<li>テストコードを正しいガードレールに仕上げることを意識する</li>
</ul>
</li>
<li>最初にシステムが満たすべき要件を自分で書いておく
<ul>
<li>一番重要</li>
<li>事前に考えて抜いておくと、AIが書いたコードの妥当性をスムーズに判断できる</li>
<li>都度planで計画を立てるときにも、自分の手である程度要件を書いてからplanに投げる</li>
</ul>
</li>
</ol>
<h2 id="悩み"><a href="https://about.tsono.org/articles/workflow-2026-02#%E6%82%A9%E3%81%BF">悩み</a></h2>
<ul>
<li>計画書はすぐ陳腐化する
<ul>
<li>作業完了までは計画書を削除し、その際に意思決定をADRとして残すほうがいいかも</li>
<li>AIに読ませたり更新させる場合は少ない文章のほうがいいし</li>
</ul>
</li>
<li>業務では実践できていない
<ul>
<li>お金関係や規模の大きいシステム・チーム開発では上述のワークフローは使えていない
<ul>
<li>プロダクションコードめちゃくちゃレビューしてる</li>
</ul>
</li>
<li>あくまでも個人での開発や厳密さを要求されない部分でのフロー</li>
</ul>
</li>
</ul><p><a href="https://about.tsono.org/articles/workflow-2026-02">元の記事を読む</a></p>]]></content:encoded></item><item><title>Codex CLI が git操作できないと言ってくる</title><link>https://about.tsono.org/articles/codex-cli-has-not-xcode-lisence</link><guid isPermaLink="true">https://about.tsono.org/articles/codex-cli-has-not-xcode-lisence</guid><pubDate>Thu, 12 Feb 2026 00:00:00 GMT</pubDate><description>Codex CLIがXcodeライセンス未同意のためgit操作できないと言ってくる。</description><content:encoded><![CDATA[<p>Codex CLIが</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">•</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> Ran</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> git</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> status</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> --short</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">  └</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> You</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> have</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> not</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> agreed</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> to</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> the</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> Xcode</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> license</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> agreements.</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> Please</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> run</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> 'sudo</span></span>
<span class="line"><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">    xcodebuild -license'</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> from</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> within</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> a</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> Terminal</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> window</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> to</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> review</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> and</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> agree</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">    to</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> the</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> Xcode</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> and</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> Apple</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> SDKs</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> license.</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">───────────────────────────────────────────────────────────────────────────</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">•</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> 今はコミットできません。git</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> 実行時に以下で止まっています。</span></span></code></pre>
<p>と言ってくる</p>
<h2 id="解決"><a href="https://about.tsono.org/articles/codex-cli-has-not-xcode-lisence#%E8%A7%A3%E6%B1%BA">解決</a></h2>
<p>Xcode を開いて</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/b7662be6e444ff3b/640.avif 640w, https://about.tsono.org/images/generated/b7662be6e444ff3b/960.avif 960w, https://about.tsono.org/images/generated/b7662be6e444ff3b/1230.avif 1230w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/b7662be6e444ff3b/640.webp 640w, https://about.tsono.org/images/generated/b7662be6e444ff3b/960.webp 960w, https://about.tsono.org/images/generated/b7662be6e444ff3b/1230.webp 1230w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/codex-cli-has-not-xcode-lisence/xcode.webp" alt="Xcode" width="1230" height="1080" loading="lazy" decoding="async"></picture>
<p>Agree すればいい</p>
<p>多分、Xcode のアップデートをしたのが原因</p><p><a href="https://about.tsono.org/articles/codex-cli-has-not-xcode-lisence">元の記事を読む</a></p>]]></content:encoded></item><item><title>Codex CLI が web_search 設定が非推奨と言っていくる</title><link>https://about.tsono.org/articles/duplicate-web-search</link><guid isPermaLink="true">https://about.tsono.org/articles/duplicate-web-search</guid><pubDate>Tue, 10 Feb 2026 00:00:00 GMT</pubDate><description>Codex CLIでweb_search設定が非推奨になった警告への対処法</description><content:encoded><![CDATA[<p>2026/02/10時点でCodex CLIが</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>[tools].web_search` is deprecated. Use `web_search` instead</span></span></code></pre>
<p>と言ってくる</p>
<h2 id="原因"><a href="https://about.tsono.org/articles/duplicate-web-search#%E5%8E%9F%E5%9B%A0">原因</a></h2>
<p>かつて <code>.codex/config.toml</code> に設定した <code>[tools] web_search = true</code> が非推奨になった模様</p>
<p>最新を見てみると...</p>
<p><a href="https://developers.openai.com/codex/config-reference/#configtoml">config.toml</a></p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/7b405d9a34c1e210/640.avif 640w, https://about.tsono.org/images/generated/7b405d9a34c1e210/960.avif 960w, https://about.tsono.org/images/generated/7b405d9a34c1e210/1280.avif 1280w, https://about.tsono.org/images/generated/7b405d9a34c1e210/1920.avif 1920w, https://about.tsono.org/images/generated/7b405d9a34c1e210/2066.avif 2066w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/7b405d9a34c1e210/640.webp 640w, https://about.tsono.org/images/generated/7b405d9a34c1e210/960.webp 960w, https://about.tsono.org/images/generated/7b405d9a34c1e210/1280.webp 1280w, https://about.tsono.org/images/generated/7b405d9a34c1e210/1920.webp 1920w, https://about.tsono.org/images/generated/7b405d9a34c1e210/2066.webp 2066w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/duplicate-web-search/image.webp" alt="config.toml設定値一覧" width="2066" height="1484" loading="lazy" decoding="async"></picture>
<p><code>features.</code> や <code>tools.</code> が非推奨となっている。</p>
<p>最下部の <code>web_search</code> が最新。stringで <code>cached</code> or <code>live</code> を指定してねとのこと。</p>
<h2 id="解決"><a href="https://about.tsono.org/articles/duplicate-web-search#%E8%A7%A3%E6%B1%BA">解決</a></h2>
<p>新鮮なデータが欲しいので <code>live</code> を設定</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">web_search = </span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'live'</span></span></code></pre>
<p>CLIも無事警告が出ずに起動。</p><p><a href="https://about.tsono.org/articles/duplicate-web-search">元の記事を読む</a></p>]]></content:encoded></item><item><title>🔥Honoにはまってる</title><link>https://about.tsono.org/articles/hono</link><guid isPermaLink="true">https://about.tsono.org/articles/hono</guid><pubDate>Fri, 06 Feb 2026 00:00:00 GMT</pubDate><description>🔥</description><content:encoded><![CDATA[<p><a href="https://about.tsono.org/articles/do">Durable Object で遊んでる</a> でいろいろ試した後、 hono で書き直している</p>
<p><a href="https://hono.dev/">https://hono.dev/</a></p>
<p>めっちゃいい</p>
<p>apiがシンプルに書けるし、便利なミドルウェアが豊富<br>
zodとの連携も強くてバリデーションを書きやすい</p>
<p>自分が作っているものは規模が小さいといいつつ、Cloudflare D1 と Durable Object（アラームが使いたい）も触る。乱雑に作るとまずいので以下のアーキテクチャにしてる</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">├──</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> index.ts</span><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC"> # 入口</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">├──</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> 機能名</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">│  </span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> ├──</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> controller</span><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC"> # APIのふりわけ</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">│  </span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> ├──</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> domain</span><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC"> # 型など</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">│  </span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> ├──</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> durable-object</span><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC"> #  durable object alarm が呼ばれるときに処理（仮）</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">│  </span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> ├──</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> repository</span><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC"> # D1クエリ（生）</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">│  </span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> └──</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> service</span><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC"> # controllerから呼ばれるメソッド</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">└──</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> web</span><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC"> # クライアント</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">    ├──</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> controller</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">    ├──</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> csr</span><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC"> # CSRする部分 </span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">    └──</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> ssr</span><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC"> # ssrで返すベースのhtml</span></span></code></pre>
<p>serviceとrepositoryはクラスじゃなくて純粋な関数にしている。規模が大きくなって辛くなってきたら考える。</p>
<p>クライアント側は、正直 pages にformをおいてworkerのapiを叩くのでもいいけど、<a href="https://hono.dev/docs/guides/jsx-dom">jsx-dom</a>を試したくてこういう構造にしている。</p>
<p>楽しいなぁ、もっと深く触りたい</p><p><a href="https://about.tsono.org/articles/hono">元の記事を読む</a></p>]]></content:encoded></item><item><title>ペイロードを見る</title><link>https://about.tsono.org/articles/dev-tool-payload</link><guid isPermaLink="true">https://about.tsono.org/articles/dev-tool-payload</guid><pubDate>Mon, 02 Feb 2026 00:00:00 GMT</pubDate><description>開発者ツールのネットワークタブって便利だなって話</description><content:encoded><![CDATA[<p>コードベースが大きい機能のデバッグをしていていると、バグがフロントとバックのどちらにあるのかを素早く判断したくなる。<br>
<code>print</code> や <code>console.log</code> のようなログだと局所的な情報だけになる。また、コードは設計や処理フローであって、実際に入ってくる値そのものは見えない。「ここにどんな値が入るかな？」を想像しながら推測する必要がある。</p>
<p>ブラウザのネットワークタブであれば、1つの通信に対するペイロードとレスポンスが確認できる。値そのものとパラメータ名がセットで表示されるのでわかりやすい。</p>
<p>なので、めちゃくちゃ使うようになった。<br>
デベロッパーツール、もっと使ったほうがいい機能たくさんありそう</p><p><a href="https://about.tsono.org/articles/dev-tool-payload">元の記事を読む</a></p>]]></content:encoded></item><item><title>Durable Object で遊んでる</title><link>https://about.tsono.org/articles/do</link><guid isPermaLink="true">https://about.tsono.org/articles/do</guid><pubDate>Wed, 28 Jan 2026 00:00:00 GMT</pubDate><description>遊んでるというか、Alert が必要なものを作る条件に合致しているので作りながら勉強している。</description><content:encoded><![CDATA[<p>遊んでるというか、Alert が必要なものを作る条件に合致しているので作りながら勉強している。</p>
<p>ワーカーとD1と比べて何が違うのかよくわからなかったけど、わかってきた</p>
<p>DOのnameってssh key gen するときのパスフレーズみたいなものなのか？</p>
<p>生成したDOのインスタンスとかアラームを一覧で取得する方法、ないっぽい?</p>
<p>わかってきてない... あ〜おもしろいなぁ</p><p><a href="https://about.tsono.org/articles/do">元の記事を読む</a></p>]]></content:encoded></item><item><title>開発環境現状確認 2026</title><link>https://about.tsono.org/articles/dev-env-2026</link><guid isPermaLink="true">https://about.tsono.org/articles/dev-env-2026</guid><pubDate>Sun, 18 Jan 2026 00:00:00 GMT</pubDate><description>2026年時点での開発環境メモ。</description><content:encoded><![CDATA[<h2 id="os"><a href="https://about.tsono.org/articles/dev-env-2026#os">OS</a></h2>
<p>仕事は Windows と Ubuntu（WSL2） 。プライベートで macOS と Rasbian。</p>
<p>Windows 環境で開発していたが、昨年 WSL に移行した。docker も Ubuntu の docker engine を使うようになった。
使い慣れた Linuxコマンドも使えるし、エイリアスも使いまわせるしで快適に。
ファイルシステムの都合か、動作も早い。</p>
<p>ラズパイ は <a href="https://about.tsono.org/articles/raspi-immich-home-photos">immich</a> で写真を管理したり、ファイル共有のハブとして使用。
その他、プライベートにまつわる全ては M1 の MacBook Air で完結。後続の Apple シリコンも気になるが、M1 で快適に使えてしまっている。</p>
<h2 id="エディタ"><a href="https://about.tsono.org/articles/dev-env-2026#%E3%82%A8%E3%83%87%E3%82%A3%E3%82%BF">エディタ</a></h2>
<p>JetBrainIDEを使っている。
オールインワンで揃っているので開発のとっかかりが楽でいい。
DataGrid すき。</p>
<h2 id="ai"><a href="https://about.tsono.org/articles/dev-env-2026#ai">AI</a></h2>
<p>CodexCLI はプライベートな開発用。GeminiCLIはコードリーディングに使用。ChatGPTは汎用。
仕事では ChatGPT にコンテキストと目的を投げてコピペ。疑問があれば更問して納得してからコピペ。そして手直し。
自分が説明できる状態でPRを出したいのでそんな感じの使い方。使わないほうが早いこともしばしば。</p>
<p>プライベートでは CodexCLI に書かせてから手動で修正。CodeRabbit CLI でレビューして...という感じ。MCPは全解除してしまった。</p>
<p>CodeRabbit、すき</p>
<p>また、NotebookLM を Podcast 生成用に使用。知りたいことを放り込んで音声化しておけば、育児や家事の合間に聞けるので重宝している。
子供ができてからまとまった時間が取れなくなってきたので、暇な耳に流し込む情報を自分で増やせるのはありがたい。
2025年末の月980円で使えるキャンペーンに乗っかったので、たくさん生成できてうれしい。</p>
<h2 id="シェル"><a href="https://about.tsono.org/articles/dev-env-2026#%E3%82%B7%E3%82%A7%E3%83%AB">シェル</a></h2>
<p>windows は powershell。mac は fish shell を使っている。
fish は昔いれたままなんの手入れもしておらず。Bash互換じゃない点に不便を感じることもあるので、zsh にしようか悩み中。</p>
<h2 id="ターミナル"><a href="https://about.tsono.org/articles/dev-env-2026#%E3%82%BF%E3%83%BC%E3%83%9F%E3%83%8A%E3%83%AB">ターミナル</a></h2>
<p>iTerm2、色々試したが変わらず。tmuxと共に使用。
ホットキーで開いたり隠したり。</p>
<h2 id="dotfile"><a href="https://about.tsono.org/articles/dev-env-2026#dotfile">dotfile</a></h2>
<p>まったく手入れができていない。
iMac → Intel Mac → M1 という遍歴だが、毎回初期化して新規一点環境を作り直してしまうので...</p>
<h2 id="ランチャー"><a href="https://about.tsono.org/articles/dev-env-2026#%E3%83%A9%E3%83%B3%E3%83%81%E3%83%A3%E3%83%BC">ランチャー</a></h2>
<p>Raycast 。ランチャー兼クリップボード管理ツールとして使っている
quicktimeのエクステンションも便利</p>
<p><a href="https://www.raycast.com/core-features/clipboard-history">Clipboard History for Mac</a><br>
<a href="https://www.raycast.com/pradeepb28/quicktime">QuickTime Recording</a></p>
<h2 id="todo管理"><a href="https://about.tsono.org/articles/dev-env-2026#todo%E7%AE%A1%E7%90%86">TODO管理</a></h2>
<p>Emacs の orgモード。
事前にタスク分割をガッツリやるタイプの人間。毎タスクを時間計測している。見積もりを設定しておき、タスクを <code>DONE</code> にした時の差分が前後10分ある場合は、要因の入力を求めるようにカスタマイズまでしている。</p>
<p>大幅に差がある時は、だいたい設計理解や達成条件が甘いことが多い。</p>
<p>また、ストーリーポイントによる見積もりができるよう設定をいじっている。</p>
<h2 id="日報"><a href="https://about.tsono.org/articles/dev-env-2026#%E6%97%A5%E5%A0%B1">日報</a></h2>
<p>Emacs。 <code>clocktable</code> で 1日の終わりにその日の実行タスクを列挙する。
社内日報に書くネタを拾い、そのまま org mode で記述 → markdown にエクスポートしてSlackに提出するワークフローになっている。</p>
<h2 id="ノートテイキング"><a href="https://about.tsono.org/articles/dev-env-2026#%E3%83%8E%E3%83%BC%E3%83%88%E3%83%86%E3%82%A4%E3%82%AD%E3%83%B3%E3%82%B0">ノートテイキング</a></h2>
<p>Emacs の <a href="https://www.orgroam.com">Org-roam</a> を使っている。</p>
<p>いわゆる Zettelkasten<sup><a href="https://about.tsono.org/articles/dev-env-2026#user-content-fn-zettelkasten" id="user-content-fnref-zettelkasten" data-footnote-ref="" aria-describedby="footnote-label">1</a></sup> でメモが取れるプラグイン。2024年にエンジニアに転職した時から愛用。
勉強やら仕事やらプライベートやらの全てをぶちこんでいる。</p>
<p>ちなみに Emacs の設定は 2024年初頭の ChatGPT によるバイブコーディングによるものなので、酷い有様。いつか手を入れたい。</p>
<h2 id="pc間でのデータ共有"><a href="https://about.tsono.org/articles/dev-env-2026#pc%E9%96%93%E3%81%A7%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E5%85%B1%E6%9C%89">PC間でのデータ共有</a></h2>
<p>Syncthingを利用。前述のEmacsによるノート、タスクなどの諸々を同期。仕事に関するものは共有しないよう除外設定をしている。
常にラズパイがハブとなっているため、WindowsとMac の片方だけ開いている状態でも問題なく同期可能。データにコンフリクトは起きない。</p>
<h2 id="キーボードマウス"><a href="https://about.tsono.org/articles/dev-env-2026#%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89%E3%83%9E%E3%82%A6%E3%82%B9">キーボード・マウス</a></h2>
<p>2020年6月4日に購入した <a href="https://keychron.co.jp/products/keychron-k2-wireless-mechanical-keyboard?srsltid=AfmBOoof9j6ujHbCFJSEyFoaCraTkC9bViAujTojQ9qhnacrcTYElYeI">Keychron K2</a> を愛用中。アルミフレームの茶軸です。
転職前は自前の Macbook に繋いでいたが、今はほぼ Windows 専属に。</p>
<p>kinesis advantage 360 がほしい。
マウスは Logicool の M575 を使用。</p>
<h2 id="モニター"><a href="https://about.tsono.org/articles/dev-env-2026#%E3%83%A2%E3%83%8B%E3%82%BF%E3%83%BC">モニター</a></h2>
<p>LG 27MP89HM-S をメインに使用。右側に <a href="https://www.amazon.co.jp/dp/B07H774Q42?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_4">BoYata</a> のノートPCスタンドを置き、その上に Windows を置いている。<br>
左側には モバイルディスプレイを縦置きしているので 3画面状態。<br>
<a href="https://www.amazon.co.jp/dp/B083RFYZGW?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_2&#x26;th=1">cocopar15.6インチ</a><br>
<a href="https://www.amazon.co.jp/dp/B0CMTQ51H2?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_2">KUUVAN タブレット スタンド</a></p>
<section data-footnotes="" class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes</h2>
<ol>
<li id="user-content-fn-zettelkasten">
<p>ノートテイキングの手法の一つ。情報を小さな単位で分割し、それらを相互にリンクさせることで知識のネットワークを構築する方法論。<a href="https://dev.classmethod.jp/articles/intro-zettelkasten-and-emacs-org-roam/">参考</a> <a href="https://about.tsono.org/articles/dev-env-2026#user-content-fnref-zettelkasten" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section><p><a href="https://about.tsono.org/articles/dev-env-2026">元の記事を読む</a></p>]]></content:encoded></item><item><title>どうぶつの森+, e+</title><link>https://about.tsono.org/articles/animal-crossing-e-plus</link><guid isPermaLink="true">https://about.tsono.org/articles/animal-crossing-e-plus</guid><pubDate>Tue, 13 Jan 2026 00:00:00 GMT</pubDate><description>スイッチ版どうぶつの森のアップデートのPVのスクショか、ファミコンっぽいゲームが写ってる画面をちらっと見た。 ファミコンが追加されるんだろうか</description><content:encoded><![CDATA[<p>スイッチ版どうぶつの森のアップデートのPVのスクショか、ファミコンっぽいゲームが写ってる画面をちらっと見た。
ファミコンが追加されるんだろうか</p>
<p>小学生の時にどうぶつの森+を散々プレイしてたのが懐かしい。</p>
<p>クルクルランドとかバルーンファイトを散々やった。 ファミコンを終わりにすると、画面がけけソングが流れた自室に戻ってくる。コンポの位置によって音量が変わるから、音が大きかったり小さかったり。</p>
<p>あの静けさ居心地良かったな〜。ゲーム内時間も夕方で、実時間も夕方だった。</p>
<p>そういえば e+ だとGBAと連携できて、カードをスラッシュするとミニゲームができたな</p>
<p>あの時のどうぶつの森じゃないと感じられない世界観がある気がする。</p>
<p>ただノスタルジーを感じてるだけかな？</p><p><a href="https://about.tsono.org/articles/animal-crossing-e-plus">元の記事を読む</a></p>]]></content:encoded></item><item><title>ヱヴァンゲリヲン新劇場版：Ｑ　（ｖｅｒ．３．３３３）</title><link>https://about.tsono.org/articles/evaq</link><guid isPermaLink="true">https://about.tsono.org/articles/evaq</guid><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><description>新劇場版エヴァンゲリヲンQ 3.333を見てきた。</description><content:encoded><![CDATA[<p>新劇場版エヴァンゲリヲンQ 3.333を見てきた。</p>
<p>ここ最近恒例の月一エヴァ。
旧劇から全て見てきたけど、トップクラスに面白かった。序の次に好きかも。</p>
<p>昔見た時はキャラの心情もストーリーもよくわからなかったけど、 <code>シン</code>を見てキャラクターの気持ちを知っていたので、「あ〜ミサトさん、本当はシンジ君が心配だけど、ヴィレクルーに示しがつかないからわざと冷たくしてるのかな〜」とか「綾波はマジで別人だから、綾波から見たらシンジ君がヒスってるの全く意味わからないだろうな〜」とか、いっぱい想像できた。</p>
<p>昔見たときは、話についていくのがやっと（カヲルくんが13番目に堕とされた云々あたりは今もついて行けていない）だったけど、視聴済みなのでキャラの心情を想像する余裕ができていたのかもしれない。
特にシンジ君の気持ちがかなりわかった。シンジ君からしてみたらめちゃくちゃだな...</p>
<ul>
<li>起きたらなんか14年経ってる</li>
<li>みんな冷たい</li>
<li>綾波救えてない</li>
<li>救えてるじゃん...（救えてない</li>
<li>綾波の様子がおかしい</li>
<li>カヲルくんが優しい</li>
<li>そんなカヲルくんに、地上をめちゃくちゃにしたきっかけがアナタとか言われる</li>
<li>冬月に、綾波はママのクローンだぞって言われる</li>
<li>頭ぐわんぐわん</li>
</ul>
<p>こんな状態でカヲルくんに「世界を戻せる」とか言われて希望を持っちゃって、「やっぱやめよう」なんて急にはしご外れたら、そりゃ強行突破しちゃいます</p>
<p>そして最後の予告はやっぱり最高ですね。</p>
<p>その後食べたマックのドラクエバーガー「ザク切りポテト&#x26;肉厚ビーフ やみつきコンソメペッパーマヨ」がとても美味しかった。
前のエヴァコラボの綾波バーガーも同じくポテトパティが使われていて美味しかった記憶。ポテトパティ、ハズレ無し</p><p><a href="https://about.tsono.org/articles/evaq">元の記事を読む</a></p>]]></content:encoded></item><item><title>TDDを実践してみて感じたこと</title><link>https://about.tsono.org/articles/tdd</link><guid isPermaLink="true">https://about.tsono.org/articles/tdd</guid><pubDate>Fri, 09 Jan 2026 00:00:00 GMT</pubDate><description>TDDを初めてやってみた短い感想。</description><content:encoded><![CDATA[<p>マインドマップのアプリをTDDで作成している。
私にとって、TDD も テストコードを書きながらの開発もこれが初。
実践前に以下動画を参考にした。（今でも見ている）</p>
<p><a href="https://www.youtube.com/watch?v=Q-FJ3XmFlT8&amp;t=2515">YouTubeで動画を再生</a></p>
<h2 id="todoリスト作成が大事"><a href="https://about.tsono.org/articles/tdd#todo%E3%83%AA%E3%82%B9%E3%83%88%E4%BD%9C%E6%88%90%E3%81%8C%E5%A4%A7%E4%BA%8B">TODOリスト作成が大事</a></h2>
<p>TDDの最初のステップとして、システムが満たすべき要件を列挙していく</p>
<p>例: マインドマップのノード操作</p>
<pre><code>- [ ] ノードをクリックすることで選択状態になる
- [ ] ノードを選択状態で Tabキー を押下することで、子ノードを追加する
- [ ] ノードを選択状態で Enterキー を押下することで、兄弟ノードを追加する
- [ ] ノードを選択状態で Deleteキー を押下することで、対象ノードを削除する
- [ ] ルートノードを選択状態で Enterキー を押下しても、兄弟ノードが追加されない
...etc
</code></pre>
<p>思いつく限りのケースを列挙した後、テスト容易性・重要性を高めるようブラッシュアップする。 具体的にはテストしにくい要素（入出力やUI操作）を切り離した表現に直していく。</p>
<p>すると、以下のように表現できる。</p>
<pre><code>- [ ] ルートノードに対する追加・削除操作
  - [ ] ルートノードを選択状態にできる
  - [ ] ルートノードを解除状態にできる
  - [ ] 選択状態を変更したとき、更新日時はこうしんしない
  - [ ] 子ノードを新規追加できる
  - [ ] 兄弟ノードを新規追加できない
  - [ ] 削除できない
- [ ] 通常ノードに対する追加・削除操作
  - [ ] 選択状態にできる
  - [ ] 解除状態にできる
  - [ ] 対象ノードの子ノードを新規作成できる
  - [ ] 対象ノードの兄弟ノードを新規作成できる
  - [ ] 対象ノードを削除できる
... etc
</code></pre>
<p>ドメインロジックじゃん。</p>
<p>Vue.jsを使っているので、ノード操作を<code>useNode</code>というComposablesに切り出した。</p>
<p>テスト容易なTODOを作成する過程で、UIとロジックを強制的に切り離さざるを得なくなるのが嬉しい。 AIにコードを書かせてもUIとロジックが混じらないし、1つのTODOごとに開発ないしはレビューができるので、品質が担保しやすい。</p>
<p>プロジェクトをコントロールできている感があって良い。気持ちが良い。最高、楽しすぎる。</p>
<p>ちなみに今は UI側って TDD でどうやるんだよ...ﾄﾎﾎ... というところで立ち往生している。</p>
<h3 id="参考にしている資料"><a href="https://about.tsono.org/articles/tdd#%E5%8F%82%E8%80%83%E3%81%AB%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E8%B3%87%E6%96%99">参考にしている資料</a></h3>
<p><a href="https://www.youtube.com/watch?v=Q-FJ3XmFlT8">TDD Boot Camp 2020 Online #1 基調講演/ライブコーディング</a><br>
<a href="https://www.amazon.co.jp/%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95%E9%96%8B%E7%99%BA-Kent-Beck/dp/4274217884?tag=googhydr-22&#x26;source=dsa&#x26;hvcampaign=books&#x26;gad_source=1">テスト駆動開発</a><br>
<a href="https://www.amazon.co.jp/%E5%8D%98%E4%BD%93%E3%83%86%E3%82%B9%E3%83%88%E3%81%AE%E8%80%83%E3%81%88%E6%96%B9-%E4%BD%BF%E3%81%84%E6%96%B9-Vladimir-Khorikov/dp/4839981728?tag=googhydr-22&#x26;source=dsa&#x26;hvcampaign=books&#x26;gad_source=1">単体テストの考え方/使い方</a></p><p><a href="https://about.tsono.org/articles/tdd">元の記事を読む</a></p>]]></content:encoded></item><item><title>target=&apos;_blank&apos;なリンクが開かない</title><link>https://about.tsono.org/articles/target-blank-not-working-with-disqus</link><guid isPermaLink="true">https://about.tsono.org/articles/target-blank-not-working-with-disqus</guid><pubDate>Sun, 24 Aug 2025 00:00:00 GMT</pubDate><description>結論よくわからないけど勉強になった話</description><content:encoded><![CDATA[<h2 id="結論"><a href="https://about.tsono.org/articles/target-blank-not-working-with-disqus#%E7%B5%90%E8%AB%96">結論</a></h2>
<ul>
<li>外部リンクを新規タブで開く場合、aタグに <strong>noreferrer</strong>, <strong>noopener</strong> 属性を付ける必要はない</li>
<li>Disqusの Affiliate link のチェックを外す</li>
</ul>
<h2 id="経緯-target_blank-のリンクが開かない"><a href="https://about.tsono.org/articles/target-blank-not-working-with-disqus#%E7%B5%8C%E7%B7%AF-target_blank-%E3%81%AE%E3%83%AA%E3%83%B3%E3%82%AF%E3%81%8C%E9%96%8B%E3%81%8B%E3%81%AA%E3%81%84">経緯: target="_blank" のリンクが開かない</a></h2>
<p>このブログでは、外部リンクに <code>target="_blank"</code> を付けることで、デフォルトで新しいタブを開くようにしている。</p>
<blockquote>
<p><strong>注記</strong>
2026/01/17時点では Nuxt Content でブログを書いていますが、当時は Hugo で作成していました。</p>
</blockquote>
<p>ところが、本番環境に記事を公開して閲覧していたところ、外部リンクが正しく開かない現象に遭遇した。
具体的には、リンク押下後に Google Chrome ではアドレスバーに <code>about:blank</code> と表示され、新規タブで真っ白なページが開く。</p>
<p>Safari では、アドレスバーに遷移元のURLが表示され、新規タブで真っ白なページが表示される。</p>
<p>さらに奇妙なのは、この挙動が一定ではない点。
例えば「1回目は正しくリンク先が開くのに、2回目以降は真っ白なタブになってしまう」場合もあれば、「最初のクリックから真っ白なタブが開く」場合もある。</p>
<p>ただ、新規タブを開くを押下 or Command + クリックすると正常に開く。</p>
<p>まとめると👇️</p>
<ul>
<li><code>target="_blank"</code> なリンクをクリックすると、真っ白なページが開く</li>
<li>新規タブのアドレスバーの値がブラウザによって異なる</li>
<li>真っ白なタブが開くタイミングにばらつきがある</li>
<li><code>新しいタブで開く</code> は問題ない</li>
</ul>
<p>🤔????</p>
<p>なんだこれ...</p>
<h2 id="原因"><a href="https://about.tsono.org/articles/target-blank-not-working-with-disqus#%E5%8E%9F%E5%9B%A0">原因</a></h2>
<p>クリックイベントを補足しているスクリプトを調べたところ、Disqus の一部スクリプトが関係していそうだった。
Disqus はウェブサイトやブログにコメントを追加できるサービス。
2007年頃の立ち上げから2013年頃に向けてバズった模様。それ移行も「Disqus導入してみた」系の記事は散見され、私も Hugo で作成している本ブログに導入した。
それが 2024年8月初旬頃。</p>
<p>Disqus には、外部リンクを自動的にアフィリエイトリンクに差し替える <em>Affiliate Links</em> 機能がある。これにより収益を得ている模様。
<a href="https://tuhrig.de/the-disqus-affiliated-links-program/?utm_source=chatgpt.com">The Disqus Affiliated Links Program</a></p>
<p>Disqusで新しいサイトを作成するとデフォルトで有効化されている。</p>
<p>これが有効だと、記事内リンクのクリックをスクリプトで捕捉し、アフィリエイトリンク先にリダイレクトする。
この機能を無効化することでスクリプトが読み込まれなくなり、正常に新規タブで外部リンクを開けるようになる。</p>
<p>おそらく新規タブを開いた後に非同期で取得したリンクにリダイレクトをさせる処理があり、それが何らかの理由で、うまくいってなかったっぽい。</p>
<p><code>opener</code> で新規タブの <code>location</code> をアフィリエイトサイトのリンクに変更しているが、<code>nopener</code> 属性のせいでうまくいかない...というストーリーかと思ったが、それだとすべての <code>target="_blank"</code> なリンクが開けなくなるし、そもそも元タブから新規タブのURLを変更するのはlocationじゃない気がするし...</p>
<p>うーん、よくわからない</p>
<h2 id="解決方法"><a href="https://about.tsono.org/articles/target-blank-not-working-with-disqus#%E8%A7%A3%E6%B1%BA%E6%96%B9%E6%B3%95">解決方法</a></h2>
<p>とりあえずDisqusのアフィリエイトリンク設定を無効にすること</p>
<ol>
<li><a href="https://%3Cdisqus%E3%81%AE%E8%87%AA%E3%82%B5%E3%82%A4%E3%83%88%3E.disqus.com/admin/settings/advanced/">Disqus Advanced Settings</a> にアクセス</li>
<li><code>affiliate links</code> のチェックを外す</li>
</ol>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/40aad8e16a9ee3cf/640.avif 640w, https://about.tsono.org/images/generated/40aad8e16a9ee3cf/960.avif 960w, https://about.tsono.org/images/generated/40aad8e16a9ee3cf/1280.avif 1280w, https://about.tsono.org/images/generated/40aad8e16a9ee3cf/1920.avif 1920w, https://about.tsono.org/images/generated/40aad8e16a9ee3cf/2136.avif 2136w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/40aad8e16a9ee3cf/640.webp 640w, https://about.tsono.org/images/generated/40aad8e16a9ee3cf/960.webp 960w, https://about.tsono.org/images/generated/40aad8e16a9ee3cf/1280.webp 1280w, https://about.tsono.org/images/generated/40aad8e16a9ee3cf/1920.webp 1920w, https://about.tsono.org/images/generated/40aad8e16a9ee3cf/2136.webp 2136w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/target-blank-not-working-with-disqus/disable-disqus-affiliate-link.png" alt="Disqusのアフィリエイトリンクを無効にする" width="2136" height="714" loading="lazy" decoding="async"></picture>
<h3 id="追記-2025-09-14"><a href="https://about.tsono.org/articles/target-blank-not-working-with-disqus#%E8%BF%BD%E8%A8%98-2025-09-14">追記 2025-09-14</a></h3>
<p>今動作を確認したところ、</p>
<ul>
<li>アフィリエイトリンク機能が有効</li>
<li><code>target="_blank"</code> なリンク</li>
</ul>
<p>でも問題なく遷移できた。</p>
<h4 id="テスト用ページ"><a href="https://about.tsono.org/articles/target-blank-not-working-with-disqus#%E3%83%86%E3%82%B9%E3%83%88%E7%94%A8%E3%83%9A%E3%83%BC%E3%82%B8">テスト用ページ</a></h4>
<p><a href="https://tsonobe1.github.io/gisqus_link_test/">Disqus Affiliate Links テスト</a></p>
<p>執筆時は確かに記事冒頭の動作だった気がするけど...</p>
<h2 id="新規タブで開きたい-aタグ-の属性はどうすべきか"><a href="https://about.tsono.org/articles/target-blank-not-working-with-disqus#%E6%96%B0%E8%A6%8F%E3%82%BF%E3%83%96%E3%81%A7%E9%96%8B%E3%81%8D%E3%81%9F%E3%81%84-a%E3%82%BF%E3%82%B0-%E3%81%AE%E5%B1%9E%E6%80%A7%E3%81%AF%E3%81%A9%E3%81%86%E3%81%99%E3%81%B9%E3%81%8D%E3%81%8B">新規タブで開きたい <code>&#x3C;a>タグ</code> の属性はどうすべきか</a></h2>
<p>良い機会なので調べ直してみた。</p>
<ul>
<li><code>noreferrer</code>
<ul>
<li>ページA → ページB の遷移時に、 <code>HTTP Referer</code> ヘッダの送信を省略する</li>
</ul>
</li>
<li><code>noopener</code>
<ul>
<li>ページA → ページB の遷移時に、 <code>window.opener</code> を <code>null</code> に設定する</li>
<li><code>HTTP Referer</code> ヘッダは送信される</li>
</ul>
</li>
<li><code>noreferrer</code> を設定すると、 <code>noopener</code> の設定が自動付与される</li>
<li><code>window.opener.location = "&#x3C;URL>"</code> のように書き換えると、ページAのタブを任意のページCに遷移できる
<ul>
<li>この仕様を用いた攻撃を <code>Tabnabbing</code> という</li>
<li><a href="https://owasp.org/www-community/attacks/Reverse_Tabnabbing?utm_source=chatgpt.com">Tabnabbing</a></li>
</ul>
</li>
<li>今のモダンなブラウザでは <code>target="_blank"</code> なタグには暗黙的に <code>noopener</code> 相当の処理が自動付与される
<ul>
<li><a href="https://www.stefanjudis.com/today-i-learned/target-blank-implies-rel-noopener/?utm_source=chatgpt.com">Target=_blank implies rel=noopener | Stefan Judis Web Development</a></li>
<li>つまり、<code>window.opener</code> が null となる</li>
</ul>
</li>
<li><code>noreferrer</code> はリファラを一切渡さないため、アクセス解析に支障をもたらす
<ul>
<li><a href="https://cinci.jp/blog/20240723-review-target-blank-noopener-noreferrer-practices">別タブへのリンク記述「target="_blank"とrel="noopener noreferrer"」の見直しを - 株式会社真摯</a></li>
</ul>
</li>
<li>Referer情報をどのくらい含めるかは <code>Referrer-Policy</code> で設定する
<ul>
<li>デフォは <code>strict-origin-when-cross-origin</code></li>
</ul>
</li>
</ul>
<h3 id="まとめ"><a href="https://about.tsono.org/articles/target-blank-not-working-with-disqus#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h3>
<ul>
<li>単なる技術ブログでは外部リンクに
<ul>
<li><code>noreferrer属性</code> は不要</li>
<li><code>noopener属性</code> も明示しなくていい</li>
</ul>
</li>
</ul><p><a href="https://about.tsono.org/articles/target-blank-not-working-with-disqus">元の記事を読む</a></p>]]></content:encoded></item><item><title>ラズパイで写真管理をして1年経った</title><link>https://about.tsono.org/articles/raspi-immich-home-photos</link><guid isPermaLink="true">https://about.tsono.org/articles/raspi-immich-home-photos</guid><pubDate>Wed, 20 Aug 2025 00:00:00 GMT</pubDate><description>Immich はいいぞ</description><content:encoded><![CDATA[<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/f6af953c061ee775/640.avif 640w, https://about.tsono.org/images/generated/f6af953c061ee775/960.avif 960w, https://about.tsono.org/images/generated/f6af953c061ee775/1280.avif 1280w, https://about.tsono.org/images/generated/f6af953c061ee775/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/f6af953c061ee775/640.webp 640w, https://about.tsono.org/images/generated/f6af953c061ee775/960.webp 960w, https://about.tsono.org/images/generated/f6af953c061ee775/1280.webp 1280w, https://about.tsono.org/images/generated/f6af953c061ee775/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/introduction/server.webp" alt="自宅サーバの様子（ラズパイ・HDD・ルータ）" width="1600" height="1200" loading="lazy" decoding="async"></picture>
<p>2024年6月から自宅サーバで「おうちGoogleフォト」を運用している。
スマホで撮影した写真・動画を事実上無制限に保存して快適に閲覧ができる。</p>
<p><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/introduction/immich_timeline.webp" alt="Immichタイムラインの様子" width="960" height="514" loading="lazy" decoding="async">
遠方の両親にはアルバムを共有。モバイルアプリがあるのでスマホから見てもらえる。</p>
<p>運用開始から約1年、安定稼働しているため、構築手順やハマりどころなどを振り返っておく。</p>
<h2 id="モチベ"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E3%83%A2%E3%83%81%E3%83%99">モチベ</a></h2>
<p>2024年に第一子が生まれ、写真・動画が一気に増えた。
それまで Google フォト のフリープランで運用していたが、無制限が終了したことで容量が 16GB ほどに制限されており、さすがに限界を迎えた。<br>
<a href="https://www.itmedia.co.jp/news/articles/2011/12/news057.html">Googleフォトの容量無制限無料バックアップ、2021年5月末で終了</a></p>
<p>容量を気にせずバンバン撮りたいので、👇の目標を立てた。</p>
<ol>
<li>事実上、無限に保存できること</li>
<li>スマホから保存・閲覧できること</li>
<li>サブスクしないこと</li>
<li>Google フォトからデータ移行できること</li>
<li>遠方の両親にもシェアできること</li>
</ol>
<p>現在（2025/08）のデータは合計265.6GBあるため、もしサブスクで運用すると...</p>
<ul>
<li><a href="https://www.apple.com/jp/icloud/">iCloud</a> 2TB ¥1,500/月</li>
<li><a href="https://one.google.com/about/plans?hl=ja&#x26;g1_landing_page=0">Google</a> 2TB ¥1,450/月</li>
<li><a href="https://www.amazon.co.jp/b?ie=UTF8&#x26;node=5262648051">Amazonフォト</a> は動画が5GBまでなので却下</li>
<li><a href="https://mitene.us/">みてね</a> は動画一本の長さが2分までに制限されるようなので却下</li>
</ul>
<p>Googleでも ¥17,400/年 かかる模様</p>
<p>この記事では、</p>
<ol>
<li>フォトストレージの構築（1.2.3.4.）</li>
<li>遠隔地の写真をシェアする(5.)</li>
</ol>
<p>という2つのゴールに分けて解説。</p>
<h2 id="完成図"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E5%AE%8C%E6%88%90%E5%9B%B3">完成図</a></h2>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/7d1f89869d7de408/640.avif 640w, https://about.tsono.org/images/generated/7d1f89869d7de408/960.avif 960w, https://about.tsono.org/images/generated/7d1f89869d7de408/1280.avif 1280w, https://about.tsono.org/images/generated/7d1f89869d7de408/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/7d1f89869d7de408/640.webp 640w, https://about.tsono.org/images/generated/7d1f89869d7de408/960.webp 960w, https://about.tsono.org/images/generated/7d1f89869d7de408/1280.webp 1280w, https://about.tsono.org/images/generated/7d1f89869d7de408/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/overview/server2.webp" alt="左から、ラズパイ・ルータ・HDD・ONU" width="1600" height="1200" loading="lazy" decoding="async"></picture>
<figure class="diagram" data-diagram="mermaid"><span class="diagram-light"><svg id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light" width="100%" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 1708.5px;" viewBox="-40.5 -58.1 1708.5 1250.1" role="graphics-document document" aria-roledescription="flowchart-v2"><style>#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .error-icon{fill:#552222;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .error-text{fill:#552222;stroke:#552222;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .edge-thickness-normal{stroke-width:1px;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .edge-thickness-thick{stroke-width:3.5px;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .edge-pattern-solid{stroke-dasharray:0;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .marker{fill:#333333;stroke:#333333;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .marker.cross{stroke:#333333;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light p{margin:0;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .cluster-label text{fill:#333;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .cluster-label span{color:#333;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .cluster-label span p{background-color:transparent;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .label text,#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light span{fill:#333;color:#333;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .node rect,#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .node circle,#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .node ellipse,#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .node polygon,#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .rough-node .label text,#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .node .label text,#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .image-shape .label,#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .icon-shape .label{text-anchor:middle;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .rough-node .label,#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .node .label,#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .image-shape .label,#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .icon-shape .label{text-align:center;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .node.clickable{cursor:pointer;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .arrowheadPath{fill:#333333;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .edgePath .path{stroke:#333333;stroke-width:1px;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .flowchart-link{stroke:#333333;fill:none;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .cluster text{fill:#333;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .cluster span{color:#333;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light rect.text{fill:none;stroke-width:0;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .icon-shape,#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .icon-shape p,#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .icon-shape .label rect,#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light .node .neo-node{stroke:#9370DB;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light [data-look="neo"].node rect,#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light [data-look="neo"].cluster rect,#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light [data-look="neo"].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light [data-look="neo"].swimlane.cluster rect{filter:none;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light [data-look="neo"].node path{stroke:#9370DB;stroke-width:1px;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light [data-look="neo"].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light [data-look="neo"].node .neo-line path{stroke:#9370DB;filter:none;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light [data-look="neo"].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light [data-look="neo"].node circle .state-start{fill:#000000;}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light [data-look="neo"].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light [data-look="neo"].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-pointEnd-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="11.5" refY="7" markerUnits="userSpaceOnUse" markerWidth="10.5" markerHeight="14" orient="auto"><path d="M 0 0 L 11.5 7 L 0 14 z" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-pointStart-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="1" refY="7" markerUnits="userSpaceOnUse" markerWidth="11.5" markerHeight="14" orient="auto"><polygon points="0,7 11.5,14 11.5,0" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></polygon></marker><marker id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-circleEnd-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refY="5" refX="12.25" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-circleStart-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-2" refY="5" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-crossEnd-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="17.7" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5;"></path></marker><marker id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-crossStart-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="-3.5" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5; stroke-dasharray: 1,0;"></path></marker><g class="root"><g class="clusters"><g class="cluster" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-lan" data-look="classic"><rect style="" x="8" y="8" width="1620" height="832"></rect><g class="cluster-label" transform="translate(774, 8)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">LAN</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-hdds" data-look="classic"><rect style="" x="1039" y="386" width="564" height="192"></rect><g class="cluster-label" transform="translate(1256, 386)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">HDDケース</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-rapy" data-look="classic"><rect style="" x="33" y="316" width="616" height="504"></rect><g class="cluster-label" transform="translate(253, 316)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Raspberry</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> Pi</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 4</tspan></tspan></text></g></g></g></g><g class="edgePaths"><path d="M624,482L628.167,482C632.333,482,640.667,482,677.333,482C714,482,779,482,844,482C909,482,974,482,1010,482C1046,482,1053,482,1056.5,482L1060,482" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-L_immich-server_hdd1_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-1eb5114d811dca82-light--L_immich-server_hdd1_0" data-points="W3sieCI6NjI0LCJ5Ijo0ODJ9LHsieCI6NjQ5LCJ5Ijo0ODJ9LHsieCI6ODQ0LCJ5Ijo0ODJ9LHsieCI6MTAzOSwieSI6NDgyfSx7IngiOjEwNjQsInkiOjQ4Mn1d" data-look="classic" marker-end="url(#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-pointEnd)"></path><path d="M1188,482L1210.167,482C1232.333,482,1276.667,482,1320.333,482C1364,482,1407,482,1428.5,482L1450,482" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-L_hdd1_hdd2_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-1eb5114d811dca82-light--L_hdd1_hdd2_0" data-points="W3sieCI6MTE4OCwieSI6NDgyfSx7IngiOjEzMjEsInkiOjQ4Mn0seyJ4IjoxNDU0LCJ5Ijo0ODJ9XQ==" data-look="classic" marker-end="url(#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-pointEnd)"></path><path d="M158.501,140.173L188.918,179.811C219.334,219.449,280.167,298.724,336.48,350.549C392.794,402.373,444.587,426.747,470.484,438.934L496.381,451.12" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-L_mobile_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-1eb5114d811dca82-light--L_mobile_in_lan_immich-server_0" data-points="W3sieCI6MTU2LjA2NTk3MjIyMjIyMjIzLCJ5IjoxMzd9LHsieCI6MzQxLCJ5IjozNzh9LHsieCI6NTAwLCJ5Ijo0NTIuODIzNTI5NDExNzY0N31d" data-look="classic" marker-start="url(#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-pointEnd)"></path><path d="M164.544,283.986L193.954,316.989C223.363,349.991,282.181,415.995,337.424,448.998C392.667,482,444.333,482,470.167,482L496,482" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-L_web_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-1eb5114d811dca82-light--L_web_in_lan_immich-server_0" data-points="W3sieCI6MTYxLjg4MzA2NDUxNjEyOTAyLCJ5IjoyODF9LHsieCI6MzQxLCJ5Ijo0ODJ9LHsieCI6NTAwLCJ5Ijo0ODJ9XQ==" data-look="classic" marker-start="url(#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-pointEnd)"></path><path d="M185.767,641.491L211.639,632.242C237.511,622.994,289.256,604.497,341.025,583.062C392.794,561.627,444.587,537.253,470.484,525.066L496.381,512.88" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-L_cloudflared_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-1eb5114d811dca82-light--L_cloudflared_immich-server_0" data-points="W3sieCI6MTgyLCJ5Ijo2NDIuODM3MTA0MDcyMzk4Mn0seyJ4IjozNDEsInkiOjU4Nn0seyJ4Ijo1MDAsInkiOjUxMS4xNzY0NzA1ODgyMzUzfV0=" data-look="classic" marker-start="url(#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-pointEnd)"></path><path d="M185.865,682.584L211.721,689.486C237.576,696.389,289.288,710.195,345.968,760.056C402.648,809.917,464.296,895.833,495.12,938.792L525.944,981.75" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-L_cloudflared_cloudflare_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-1eb5114d811dca82-light--L_cloudflared_cloudflare_0" data-points="W3sieCI6MTgyLCJ5Ijo2ODEuNTUyMDM2MTk5MDk1fSx7IngiOjM0MSwieSI6NzI0fSx7IngiOjUyOC4yNzU5NzQwMjU5NzQsInkiOjk4NX1d" data-look="classic" marker-start="url(#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-pointEnd)"></path><path d="M607.28,982.036L614.233,974.363C621.187,966.691,635.093,951.345,674.547,943.673C714,936,779,936,844,936C909,936,974,936,1010,936C1046,936,1053,936,1056.5,936L1060,936" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-L_cloudflare_mobile_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-1eb5114d811dca82-light--L_cloudflare_mobile_0" data-points="W3sieCI6NjA0LjU5Mzc1LCJ5Ijo5ODV9LHsieCI6NjQ5LCJ5Ijo5MzZ9LHsieCI6ODQ0LCJ5Ijo5MzZ9LHsieCI6MTAzOSwieSI6OTM2fSx7IngiOjEwNjQsInkiOjkzNn1d" data-look="classic" marker-start="url(#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-pointEnd)"></path><path d="M618.815,1081.632L623.846,1086.026C628.877,1090.421,638.938,1099.211,676.469,1103.605C714,1108,779,1108,844,1108C909,1108,974,1108,1010,1108C1046,1108,1053,1108,1056.5,1108L1060,1108" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-L_cloudflare_web_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-1eb5114d811dca82-light--L_cloudflare_web_0" data-points="W3sieCI6NjE1LjgwMjYzMTU3ODk0NzQsInkiOjEwNzl9LHsieCI6NjQ5LCJ5IjoxMTA4fSx7IngiOjg0NCwieSI6MTEwOH0seyJ4IjoxMDM5LCJ5IjoxMTA4fSx7IngiOjEwNjQsInkiOjExMDh9XQ==" data-look="classic" marker-start="url(#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light_flowchart-v2-pointEnd)"></path></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(844, 482)"><g class="label" data-id="mermaid-1eb5114d811dca82-light--L_immich-server_hdd1_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-68" y="-60.1" width="136" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">DB</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> /</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 写真</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(1321, 482)"><g class="label" data-id="mermaid-1eb5114d811dca82-light--L_hdd1_hdd2_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-76" y="-60.1" width="152" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">バックアップ</tspan></tspan></text></g></g></g><g class="edgeLabel"><g class="label" data-id="mermaid-1eb5114d811dca82-light--L_mobile_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g><g class="edgeLabel"><g class="label" data-id="mermaid-1eb5114d811dca82-light--L_web_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g><g class="edgeLabel"><g class="label" data-id="mermaid-1eb5114d811dca82-light--L_cloudflared_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g><g class="edgeLabel" transform="translate(386.66759, 787.64532)"><g class="label" data-id="mermaid-1eb5114d811dca82-light--L_cloudflared_cloudflare_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-102" y="-60.1" width="204" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Cloudflare</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> Tunnel</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(844, 936)"><g class="label" data-id="mermaid-1eb5114d811dca82-light--L_cloudflare_mobile_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-90" y="-60.1" width="180" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">サービストークン</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(844, 1108)"><g class="label" data-id="mermaid-1eb5114d811dca82-light--L_cloudflare_web_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-138" y="-60.1" width="276" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">ワンタイムパスワード</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> /</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">SSO認証</tspan></tspan></text></g></g></g></g><g class="nodes"><g class="node default" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-flowchart-immich-server-0" data-look="classic" transform="translate(562, 482)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>immich-server</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-flowchart-cloudflared-1" data-look="classic" transform="translate(120, 665)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>cloudflared</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-flowchart-hdd1-2" data-look="classic" transform="translate(1126, 482)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>HDD 1</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-flowchart-hdd2-3" data-look="classic" transform="translate(1516, 482)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>HDD 2</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-flowchart-web_in_lan-4" data-look="classic" transform="translate(120, 234)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Web App</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-flowchart-mobile_in_lan-5" data-look="classic" transform="translate(120, 90)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Mobile App</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-flowchart-cloudflare-17" data-look="classic" transform="translate(562, 1032)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Cloudflare</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-flowchart-mobile-19" data-look="classic" transform="translate(1126, 936)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Mobile App</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-flowchart-web-21" data-look="classic" transform="translate(1126, 1108)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Web App</p></span></div></foreignObject></g></g></g></g></g><defs><filter id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-drop-shadow" height="130%" width="130%"><fedropshadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs><defs><filter id="mermaid-1eb5114d811dca82-light--mermaid-1eb5114d811dca82-light-drop-shadow-small" height="150%" width="150%"><fedropshadow dx="2" dy="2" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs></svg></span></figure>
<p>LAN 内の Immich サーバが Cloudflare を通じて外部公開される様子。モバイルアプリからはトークン、WebアプリからはSSO認証を通じてアクセスする。</p>
<ul>
<li>登場人物
<ol>
<li>Immich: 写真・動画管理用のOSSアプリケーション</li>
<li>Raspberry Pi: Immichをホストするサーバ</li>
<li>HDD・ケース: DB,写真の保存領域</li>
<li>Cloudflare: LAN外との通信用のドメイン、トンネリング</li>
</ol>
</li>
</ul>
<h2 id="ゴール1-フォトストレージの構築"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E3%82%B4%E3%83%BC%E3%83%AB1-%E3%83%95%E3%82%A9%E3%83%88%E3%82%B9%E3%83%88%E3%83%AC%E3%83%BC%E3%82%B8%E3%81%AE%E6%A7%8B%E7%AF%89">ゴール1: フォトストレージの構築</a></h2>
<figure class="diagram" data-diagram="mermaid"><span class="diagram-light"><svg id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light" width="100%" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 1515.5px;" viewBox="-40.5 -58.1 1515.5 448.1" role="graphics-document document" aria-roledescription="flowchart-v2"><style>#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .error-icon{fill:#552222;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .error-text{fill:#552222;stroke:#552222;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .edge-thickness-normal{stroke-width:1px;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .edge-thickness-thick{stroke-width:3.5px;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .edge-pattern-solid{stroke-dasharray:0;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .marker{fill:#333333;stroke:#333333;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .marker.cross{stroke:#333333;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light p{margin:0;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .cluster-label text{fill:#333;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .cluster-label span{color:#333;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .cluster-label span p{background-color:transparent;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .label text,#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light span{fill:#333;color:#333;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .node rect,#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .node circle,#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .node ellipse,#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .node polygon,#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .rough-node .label text,#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .node .label text,#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .image-shape .label,#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .icon-shape .label{text-anchor:middle;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .rough-node .label,#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .node .label,#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .image-shape .label,#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .icon-shape .label{text-align:center;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .node.clickable{cursor:pointer;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .arrowheadPath{fill:#333333;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .edgePath .path{stroke:#333333;stroke-width:1px;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .flowchart-link{stroke:#333333;fill:none;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .cluster text{fill:#333;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .cluster span{color:#333;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light rect.text{fill:none;stroke-width:0;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .icon-shape,#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .icon-shape p,#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .icon-shape .label rect,#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light .node .neo-node{stroke:#9370DB;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light [data-look="neo"].node rect,#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light [data-look="neo"].cluster rect,#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light [data-look="neo"].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light [data-look="neo"].swimlane.cluster rect{filter:none;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light [data-look="neo"].node path{stroke:#9370DB;stroke-width:1px;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light [data-look="neo"].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light [data-look="neo"].node .neo-line path{stroke:#9370DB;filter:none;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light [data-look="neo"].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light [data-look="neo"].node circle .state-start{fill:#000000;}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light [data-look="neo"].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light [data-look="neo"].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light_flowchart-v2-pointEnd-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="11.5" refY="7" markerUnits="userSpaceOnUse" markerWidth="10.5" markerHeight="14" orient="auto"><path d="M 0 0 L 11.5 7 L 0 14 z" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light_flowchart-v2-pointStart-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="1" refY="7" markerUnits="userSpaceOnUse" markerWidth="11.5" markerHeight="14" orient="auto"><polygon points="0,7 11.5,14 11.5,0" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></polygon></marker><marker id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light_flowchart-v2-circleEnd-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refY="5" refX="12.25" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light_flowchart-v2-circleStart-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-2" refY="5" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light_flowchart-v2-crossEnd-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="17.7" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5;"></path></marker><marker id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light_flowchart-v2-crossStart-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="-3.5" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5; stroke-dasharray: 1,0;"></path></marker><g class="root"><g class="clusters"></g><g class="edgePaths"></g><g class="edgeLabels"></g><g class="nodes"><g class="root" transform="translate(0, 0)"><g class="clusters"><g class="cluster" id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light-lan" data-look="classic"><rect style="" x="8" y="8" width="1427" height="342"></rect><g class="cluster-label" transform="translate(677.5, 8)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">LAN</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light-hdds" data-look="classic"><rect style="" x="783.5" y="83" width="614" height="192"></rect><g class="cluster-label" transform="translate(1025.5, 83)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">HDDケース</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light-rapy" data-look="classic"><rect style="" x="309.5" y="46" width="199" height="256"></rect><g class="cluster-label" transform="translate(321, 46)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Raspberry</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> Pi</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 4</tspan></tspan></text></g></g></g></g><g class="edgePaths"><path d="M471,179L477.25,179C483.5,179,496,179,525.167,179C554.333,179,600.167,179,646,179C691.833,179,737.667,179,766.167,179C794.667,179,805.833,179,811.417,179L817,179" id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light-L_immich-server_hdd1_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-815c5ff7af26da90-light--L_immich-server_hdd1_0" data-points="W3sieCI6NDcxLCJ5IjoxNzl9LHsieCI6NTA4LjUsInkiOjE3OX0seyJ4Ijo2NDYsInkiOjE3OX0seyJ4Ijo3ODMuNSwieSI6MTc5fSx7IngiOjgyMSwieSI6MTc5fV0=" data-look="classic" marker-end="url(#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light_flowchart-v2-pointEnd)"></path><path d="M945,179L969.25,179C993.5,179,1042,179,1089.833,179C1137.667,179,1184.833,179,1208.417,179L1232,179" id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light-L_hdd1_hdd2_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-815c5ff7af26da90-light--L_hdd1_hdd2_0" data-points="W3sieCI6OTQ1LCJ5IjoxNzl9LHsieCI6MTA5MC41LCJ5IjoxNzl9LHsieCI6MTIzNiwieSI6MTc5fV0=" data-look="classic" marker-end="url(#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light_flowchart-v2-pointEnd)"></path><path d="M173.5,107L184.5,107C195.5,107,217.5,107,240.167,107C262.833,107,286.167,107,303.543,111.132C320.92,115.264,332.34,123.527,338.05,127.659L343.759,131.791" id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light-L_mobile_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-815c5ff7af26da90-light--L_mobile_in_lan_immich-server_0" data-points="W3sieCI6MTY5LjUsInkiOjEwN30seyJ4IjoyMzkuNSwieSI6MTA3fSx7IngiOjMwOS41LCJ5IjoxMDd9LHsieCI6MzQ3LCJ5IjoxMzQuMTM1Njc4MzkxOTU5OH1d" data-look="classic" marker-start="url(#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light_flowchart-v2-pointEnd)"></path><path d="M173.5,251L184.5,251C195.5,251,217.5,251,240.167,251C262.833,251,286.167,251,303.543,246.868C320.92,242.736,332.34,234.473,338.05,230.341L343.759,226.209" id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light-L_web_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-815c5ff7af26da90-light--L_web_in_lan_immich-server_0" data-points="W3sieCI6MTY5LjUsInkiOjI1MX0seyJ4IjoyMzkuNSwieSI6MjUxfSx7IngiOjMwOS41LCJ5IjoyNTF9LHsieCI6MzQ3LCJ5IjoyMjMuODY0MzIxNjA4MDQwMn1d" data-look="classic" marker-start="url(#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light_flowchart-v2-pointEnd)"></path></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(646, 179)"><g class="label" data-id="mermaid-815c5ff7af26da90-light--L_immich-server_hdd1_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-68" y="-60.1" width="136" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">DB</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> /</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 写真</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(1090.5, 179)"><g class="label" data-id="mermaid-815c5ff7af26da90-light--L_hdd1_hdd2_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-76" y="-60.1" width="152" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">バックアップ</tspan></tspan></text></g></g></g><g class="edgeLabel"><g class="label" data-id="mermaid-815c5ff7af26da90-light--L_mobile_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g><g class="edgeLabel"><g class="label" data-id="mermaid-815c5ff7af26da90-light--L_web_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g></g><g class="nodes"><g class="node default" id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light-flowchart-hdd1-1" data-look="classic" transform="translate(883, 179)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>HDD 1</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light-flowchart-immich-server-0" data-look="classic" transform="translate(409, 179)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>immich-server</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light-flowchart-hdd2-2" data-look="classic" transform="translate(1298, 179)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>HDD 2</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light-flowchart-mobile_in_lan-4" data-look="classic" transform="translate(107.5, 107)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Mobile App</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light-flowchart-web_in_lan-3" data-look="classic" transform="translate(107.5, 251)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Web App</p></span></div></foreignObject></g></g></g></g></g></g></g><defs><filter id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light-drop-shadow" height="130%" width="130%"><fedropshadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs><defs><filter id="mermaid-815c5ff7af26da90-light--mermaid-815c5ff7af26da90-light-drop-shadow-small" height="150%" width="150%"><fedropshadow dx="2" dy="2" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs></svg></span></figure>
<h3 id="必要なもの"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E5%BF%85%E8%A6%81%E3%81%AA%E3%82%82%E3%81%AE">必要なもの</a></h3>
<p>写真管理用のアプリケーションとそれをホストするサーバ、そして保存領域。</p>
<h4 id="アプリケーション"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3">アプリケーション</a></h4>
<p>OSSのフォトアプリケーションはたくさんある。我が家はスマホだけで写真を撮るのでモバイルアプリが必須。</p>
<p>👇️の比較表から見たときにモバイルアプリとアルバム機能がある <a href="https://immich.app/">Immich</a> を採用。Googleフォトライクなアプリで、別のツールを使用することでGoogle フォトからのデータ移行（後述）もサポートしている。</p>
<h4 id="サーバ"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E3%82%B5%E3%83%BC%E3%83%90">サーバ</a></h4>
<p>Raspberry Pi 4 にした。好みです。アクセサリとともに。</p>
<ul>
<li><a href="https://amzn.to/4fJMDiX">ラズベリーパイ 4 コンピューターモデルB 8GB</a></li>
<li><a href="https://amzn.to/4mJ9zBl">Miuzei 最新 Raspberry Pi 4 ケース</a></li>
<li><a href="https://amzn.to/46Zbo8y">KIOXIA(キオクシア) 旧東芝メモリ microSD 64GB</a><br>
SDはOSのインストール用に必要</li>
</ul>
<p>Immichの <a href="https://immich.app/docs/install/requirements/">必須要件</a> をクリアしている必要はあるので注意。</p>
<h4 id="保存領域"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E4%BF%9D%E5%AD%98%E9%A0%98%E5%9F%9F">保存領域</a></h4>
<p>容量については物理HDDを2つ（1つはバックアップ用）用意。</p>
<ul>
<li><a href="https://amzn.to/4fTmU7W">WESTERN DIGITAL 3.5インチ内蔵HDD</a></li>
<li><a href="https://amzn.to/4fFb29p">LHR-2BDPU3ES</a></li>
</ul>
<p>HDDを裸て使ってみたかった</p>
<p>さて、必要なものが揃ったら次にラズパイをセットアップします</p>
<h3 id="ラズパイとhddのセットアップ"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E3%83%A9%E3%82%BA%E3%83%91%E3%82%A4%E3%81%A8hdd%E3%81%AE%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97">ラズパイとHDDのセットアップ</a></h3>
<figure class="diagram" data-diagram="mermaid"><span class="diagram-light"><svg id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light" width="100%" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 1515.5px;" viewBox="-40.5 -58.1 1515.5 448.1" role="graphics-document document" aria-roledescription="flowchart-v2"><style>#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .error-icon{fill:#552222;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .error-text{fill:#552222;stroke:#552222;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .edge-thickness-normal{stroke-width:1px;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .edge-thickness-thick{stroke-width:3.5px;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .edge-pattern-solid{stroke-dasharray:0;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .marker{fill:#333333;stroke:#333333;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .marker.cross{stroke:#333333;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light p{margin:0;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .cluster-label text{fill:#333;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .cluster-label span{color:#333;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .cluster-label span p{background-color:transparent;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .label text,#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light span{fill:#333;color:#333;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .node rect,#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .node circle,#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .node ellipse,#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .node polygon,#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .rough-node .label text,#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .node .label text,#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .image-shape .label,#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .icon-shape .label{text-anchor:middle;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .rough-node .label,#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .node .label,#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .image-shape .label,#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .icon-shape .label{text-align:center;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .node.clickable{cursor:pointer;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .arrowheadPath{fill:#333333;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .edgePath .path{stroke:#333333;stroke-width:1px;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .flowchart-link{stroke:#333333;fill:none;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .cluster text{fill:#333;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .cluster span{color:#333;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light rect.text{fill:none;stroke-width:0;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .icon-shape,#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .icon-shape p,#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .icon-shape .label rect,#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light .node .neo-node{stroke:#9370DB;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light [data-look="neo"].node rect,#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light [data-look="neo"].cluster rect,#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light [data-look="neo"].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light [data-look="neo"].swimlane.cluster rect{filter:none;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light [data-look="neo"].node path{stroke:#9370DB;stroke-width:1px;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light [data-look="neo"].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light [data-look="neo"].node .neo-line path{stroke:#9370DB;filter:none;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light [data-look="neo"].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light [data-look="neo"].node circle .state-start{fill:#000000;}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light [data-look="neo"].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light [data-look="neo"].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light_flowchart-v2-pointEnd-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="11.5" refY="7" markerUnits="userSpaceOnUse" markerWidth="10.5" markerHeight="14" orient="auto"><path d="M 0 0 L 11.5 7 L 0 14 z" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light_flowchart-v2-pointStart-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="1" refY="7" markerUnits="userSpaceOnUse" markerWidth="11.5" markerHeight="14" orient="auto"><polygon points="0,7 11.5,14 11.5,0" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></polygon></marker><marker id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light_flowchart-v2-circleEnd-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refY="5" refX="12.25" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light_flowchart-v2-circleStart-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-2" refY="5" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light_flowchart-v2-crossEnd-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="17.7" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5;"></path></marker><marker id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light_flowchart-v2-crossStart-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="-3.5" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5; stroke-dasharray: 1,0;"></path></marker><g class="root"><g class="clusters"></g><g class="edgePaths"></g><g class="edgeLabels"></g><g class="nodes"><g class="root" transform="translate(0, 0)"><g class="clusters"><g class="cluster" id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light-lan" data-look="classic"><rect style="" x="8" y="8" width="1427" height="342"></rect><g class="cluster-label" transform="translate(677.5, 8)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">LAN</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light-hdds" data-look="classic"><rect style="fill:#E6FFFA !important;stroke:#008080 !important;stroke-width:3px !important" x="783.5" y="83" width="614" height="192"></rect><g class="cluster-label" transform="translate(1025.5, 83)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">HDDケース</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light-rapy" data-look="classic"><rect style="fill:#E6FFFA !important;stroke:#008080 !important;stroke-width:3px !important" x="309.5" y="46" width="199" height="256"></rect><g class="cluster-label" transform="translate(321, 46)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Raspberry</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> Pi</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 4</tspan></tspan></text></g></g></g></g><g class="edgePaths"><path d="M471,179L477.25,179C483.5,179,496,179,525.167,179C554.333,179,600.167,179,646,179C691.833,179,737.667,179,766.167,179C794.667,179,805.833,179,811.417,179L817,179" id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light-L_immich-server_hdd1_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-44845e52248d68aa-light--L_immich-server_hdd1_0" data-points="W3sieCI6NDcxLCJ5IjoxNzl9LHsieCI6NTA4LjUsInkiOjE3OX0seyJ4Ijo2NDYsInkiOjE3OX0seyJ4Ijo3ODMuNSwieSI6MTc5fSx7IngiOjgyMSwieSI6MTc5fV0=" data-look="classic" marker-end="url(#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light_flowchart-v2-pointEnd)"></path><path d="M945,179L969.25,179C993.5,179,1042,179,1089.833,179C1137.667,179,1184.833,179,1208.417,179L1232,179" id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light-L_hdd1_hdd2_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-44845e52248d68aa-light--L_hdd1_hdd2_0" data-points="W3sieCI6OTQ1LCJ5IjoxNzl9LHsieCI6MTA5MC41LCJ5IjoxNzl9LHsieCI6MTIzNiwieSI6MTc5fV0=" data-look="classic" marker-end="url(#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light_flowchart-v2-pointEnd)"></path><path d="M173.5,107L184.5,107C195.5,107,217.5,107,240.167,107C262.833,107,286.167,107,303.543,111.132C320.92,115.264,332.34,123.527,338.05,127.659L343.759,131.791" id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light-L_mobile_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-44845e52248d68aa-light--L_mobile_in_lan_immich-server_0" data-points="W3sieCI6MTY5LjUsInkiOjEwN30seyJ4IjoyMzkuNSwieSI6MTA3fSx7IngiOjMwOS41LCJ5IjoxMDd9LHsieCI6MzQ3LCJ5IjoxMzQuMTM1Njc4MzkxOTU5OH1d" data-look="classic" marker-start="url(#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light_flowchart-v2-pointEnd)"></path><path d="M173.5,251L184.5,251C195.5,251,217.5,251,240.167,251C262.833,251,286.167,251,303.543,246.868C320.92,242.736,332.34,234.473,338.05,230.341L343.759,226.209" id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light-L_web_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-44845e52248d68aa-light--L_web_in_lan_immich-server_0" data-points="W3sieCI6MTY5LjUsInkiOjI1MX0seyJ4IjoyMzkuNSwieSI6MjUxfSx7IngiOjMwOS41LCJ5IjoyNTF9LHsieCI6MzQ3LCJ5IjoyMjMuODY0MzIxNjA4MDQwMn1d" data-look="classic" marker-start="url(#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light_flowchart-v2-pointEnd)"></path></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(646, 179)"><g class="label" data-id="mermaid-44845e52248d68aa-light--L_immich-server_hdd1_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-68" y="-60.1" width="136" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">DB</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> /</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 写真</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(1090.5, 179)"><g class="label" data-id="mermaid-44845e52248d68aa-light--L_hdd1_hdd2_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-76" y="-60.1" width="152" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">バックアップ</tspan></tspan></text></g></g></g><g class="edgeLabel"><g class="label" data-id="mermaid-44845e52248d68aa-light--L_mobile_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g><g class="edgeLabel"><g class="label" data-id="mermaid-44845e52248d68aa-light--L_web_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g></g><g class="nodes"><g class="node default" id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light-flowchart-hdd1-1" data-look="classic" transform="translate(883, 179)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>HDD 1</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light-flowchart-immich-server-0" data-look="classic" transform="translate(409, 179)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>immich-server</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light-flowchart-hdd2-2" data-look="classic" transform="translate(1298, 179)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>HDD 2</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light-flowchart-mobile_in_lan-4" data-look="classic" transform="translate(107.5, 107)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Mobile App</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light-flowchart-web_in_lan-3" data-look="classic" transform="translate(107.5, 251)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Web App</p></span></div></foreignObject></g></g></g></g></g></g></g><defs><filter id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light-drop-shadow" height="130%" width="130%"><fedropshadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs><defs><filter id="mermaid-44845e52248d68aa-light--mermaid-44845e52248d68aa-light-drop-shadow-small" height="150%" width="150%"><fedropshadow dx="2" dy="2" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs></svg></span></figure>
<h4 id="osのインストール"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#os%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">OSのインストール</a></h4>
<p>公式に従います。OSを入れたSDカードをラズパイに指してbootする。<br>
<a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#sd-cards">Getting started - Raspberry Pi Documentation</a></p>
<h4 id="ローカルip固定化"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%ABip%E5%9B%BA%E5%AE%9A%E5%8C%96">ローカルIP固定化</a></h4>
<p>ラズパイが起動したらローカルIPを固定する。DHCPによる自動割り当てでIPが変わってしまうので、固定化しておくと楽。</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/fe827cfaba09a542/640.avif 640w, https://about.tsono.org/images/generated/fe827cfaba09a542/960.avif 960w, https://about.tsono.org/images/generated/fe827cfaba09a542/1280.avif 1280w, https://about.tsono.org/images/generated/fe827cfaba09a542/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/fe827cfaba09a542/640.webp 640w, https://about.tsono.org/images/generated/fe827cfaba09a542/960.webp 960w, https://about.tsono.org/images/generated/fe827cfaba09a542/1280.webp 1280w, https://about.tsono.org/images/generated/fe827cfaba09a542/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal1-unlimited-storage/DHCP_Settings.webp" alt="バッファローのルータ管理画面" width="1600" height="1295" loading="lazy" decoding="async"></picture>
<p>ルータのDHCP設定で、ラズパイの有線LANのMACアドレスに対して任意のIPアドレスを紐づけている（画像の一番下の行）。
MACアドレスは以下で調べる。</p>
<ol>
<li>ラズパイでをシェルを開く</li>
<li><code>ip a</code> を実行する</li>
<li><code>eth0:</code> の <code>link/ether</code> の後に書いてある</li>
</ol>
<p>wifiを使うなら <code>wlan0</code> を探すと良いが、速度を考えると有線がいいでしょう（今回は画像系なので特に）。</p>
<p>なお、使いたいIPアドレスが別の機器に設定されている場合、そのままでは手動割り当てができない。どうしても特定のIPアドレス（今回の例では 11.14）を使いたい場合は、以下の手順に従う。</p>
<ol>
<li>使いたいIPアドレスを使っている機器を、ネットワークから切断</li>
<li>ルータを再起動してIPアドレスの割り当てをリセット</li>
<li>手動設定</li>
</ol>
<p>一般的に利用可能な番号から順に割り当てることが多く、結果として若い番号から埋まっていく傾向がある模様（機種や設定で変わる）。</p>
<p>また、『ラズパイ ip 固定』で検索すると、 <code>/etc/dhcpcd.conf</code> を編集したり <code>NetworkManager</code> を設定するような記事がでてくるが、私の環境ではどれもうまくいかず...。ラズパイ公式も、ルーターでアドレス指定してねと言っている。<br>
<a href="https://www.raspberrypi.com/documentation/computers/configuration.html#assign-a-static-ip-address">Assign a static IP address</a></p>
<h4 id="vncやsshによる遠隔操作"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#vnc%E3%82%84ssh%E3%81%AB%E3%82%88%E3%82%8B%E9%81%A0%E9%9A%94%E6%93%8D%E4%BD%9C">VNCやSSHによる遠隔操作</a></h4>
<p>ラズパイのセットアップが終わったら、毎度モニタにつなぐのも面倒なので遠隔でリモートデスクトップできるようにする。<br>
<a href="https://www.indoorcorgielec.com/resources/raspberry-pi/raspberry-pi-vnc/">VNCでRaspberry Piにリモートデスクトップ接続</a></p>
<p>sshしたときにパスワードを打つのも面倒なので、公開鍵認証しておくと楽ちん<br>
<a href="https://raspi-school.com/ssh/">ラズベリーパイをリモート操作（SSHコマンド）</a></p>
<h4 id="ハードディスクのフォーマットとパーティション設定"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E3%83%8F%E3%83%BC%E3%83%89%E3%83%87%E3%82%A3%E3%82%B9%E3%82%AF%E3%81%AE%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%E3%81%A8%E3%83%91%E3%83%BC%E3%83%86%E3%82%A3%E3%82%B7%E3%83%A7%E3%83%B3%E8%A8%AD%E5%AE%9A">ハードディスクのフォーマットとパーティション設定</a></h4>
<p>次に、HDDケースにHDDを設置して、ラズパイとHDDケースをつなげる。</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/ad8d3d12541507c7/640.avif 640w, https://about.tsono.org/images/generated/ad8d3d12541507c7/960.avif 960w, https://about.tsono.org/images/generated/ad8d3d12541507c7/1280.avif 1280w, https://about.tsono.org/images/generated/ad8d3d12541507c7/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/ad8d3d12541507c7/640.webp 640w, https://about.tsono.org/images/generated/ad8d3d12541507c7/960.webp 960w, https://about.tsono.org/images/generated/ad8d3d12541507c7/1280.webp 1280w, https://about.tsono.org/images/generated/ad8d3d12541507c7/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal1-unlimited-storage/raspy.webp" alt="床で作業している様子" width="1600" height="1200" loading="lazy" decoding="async"></picture>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/ff37bc8d1659f6e5/640.avif 640w, https://about.tsono.org/images/generated/ff37bc8d1659f6e5/960.avif 960w, https://about.tsono.org/images/generated/ff37bc8d1659f6e5/1280.avif 1280w, https://about.tsono.org/images/generated/ff37bc8d1659f6e5/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/ff37bc8d1659f6e5/640.webp 640w, https://about.tsono.org/images/generated/ff37bc8d1659f6e5/960.webp 960w, https://about.tsono.org/images/generated/ff37bc8d1659f6e5/1280.webp 1280w, https://about.tsono.org/images/generated/ff37bc8d1659f6e5/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal1-unlimited-storage/hdd2.webp" alt="2台目を接続" width="1600" height="1200" loading="lazy" decoding="async"></picture>
<p>その後、以下を参考に2つのHDDをマウント。<br>
<a href="https://qiita.com/shimanuki-yu/items/cddf7e1d490ad66743f3">Raspberry PiでHDDをマウントする</a></p>
<p>_私の場合、メインは <code>/mnt/hdd1</code> 、バックアップ用は <code>/mnt/hdd2</code> にマウントした。</p>
<p>これで、ラズパイにOSを入れ、ローカルIPを固定し、HDDをマウントできた。次はImmichの導入。</p>
<h3 id="immichのセットアップ"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#immich%E3%81%AE%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97">Immichのセットアップ</a></h3>
<figure class="diagram" data-diagram="mermaid"><span class="diagram-light"><svg id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light" width="100%" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 1515.5px;" viewBox="-40.5 -58.1 1515.5 448.1" role="graphics-document document" aria-roledescription="flowchart-v2"><style>#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .error-icon{fill:#552222;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .error-text{fill:#552222;stroke:#552222;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .edge-thickness-normal{stroke-width:1px;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .edge-thickness-thick{stroke-width:3.5px;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .edge-pattern-solid{stroke-dasharray:0;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .marker{fill:#333333;stroke:#333333;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .marker.cross{stroke:#333333;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light p{margin:0;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .cluster-label text{fill:#333;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .cluster-label span{color:#333;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .cluster-label span p{background-color:transparent;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .label text,#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light span{fill:#333;color:#333;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .node rect,#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .node circle,#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .node ellipse,#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .node polygon,#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .rough-node .label text,#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .node .label text,#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .image-shape .label,#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .icon-shape .label{text-anchor:middle;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .rough-node .label,#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .node .label,#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .image-shape .label,#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .icon-shape .label{text-align:center;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .node.clickable{cursor:pointer;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .arrowheadPath{fill:#333333;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .edgePath .path{stroke:#333333;stroke-width:1px;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .flowchart-link{stroke:#333333;fill:none;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .cluster text{fill:#333;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .cluster span{color:#333;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light rect.text{fill:none;stroke-width:0;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .icon-shape,#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .icon-shape p,#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .icon-shape .label rect,#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light .node .neo-node{stroke:#9370DB;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light [data-look="neo"].node rect,#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light [data-look="neo"].cluster rect,#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light [data-look="neo"].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light [data-look="neo"].swimlane.cluster rect{filter:none;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light [data-look="neo"].node path{stroke:#9370DB;stroke-width:1px;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light [data-look="neo"].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light [data-look="neo"].node .neo-line path{stroke:#9370DB;filter:none;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light [data-look="neo"].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light [data-look="neo"].node circle .state-start{fill:#000000;}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light [data-look="neo"].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light [data-look="neo"].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light_flowchart-v2-pointEnd-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="11.5" refY="7" markerUnits="userSpaceOnUse" markerWidth="10.5" markerHeight="14" orient="auto"><path d="M 0 0 L 11.5 7 L 0 14 z" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light_flowchart-v2-pointStart-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="1" refY="7" markerUnits="userSpaceOnUse" markerWidth="11.5" markerHeight="14" orient="auto"><polygon points="0,7 11.5,14 11.5,0" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></polygon></marker><marker id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light_flowchart-v2-circleEnd-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refY="5" refX="12.25" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light_flowchart-v2-circleStart-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-2" refY="5" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light_flowchart-v2-crossEnd-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="17.7" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5;"></path></marker><marker id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light_flowchart-v2-crossStart-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="-3.5" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5; stroke-dasharray: 1,0;"></path></marker><g class="root"><g class="clusters"></g><g class="edgePaths"></g><g class="edgeLabels"></g><g class="nodes"><g class="root" transform="translate(0, 0)"><g class="clusters"><g class="cluster" id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light-lan" data-look="classic"><rect style="" x="8" y="8" width="1427" height="342"></rect><g class="cluster-label" transform="translate(677.5, 8)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">LAN</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light-hdds" data-look="classic"><rect style="" x="783.5" y="83" width="614" height="192"></rect><g class="cluster-label" transform="translate(1025.5, 83)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">HDDケース</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light-rapy" data-look="classic"><rect style="" x="309.5" y="46" width="199" height="256"></rect><g class="cluster-label" transform="translate(321, 46)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Raspberry</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> Pi</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 4</tspan></tspan></text></g></g></g></g><g class="edgePaths"><path d="M471,179L477.25,179C483.5,179,496,179,525.167,179C554.333,179,600.167,179,646,179C691.833,179,737.667,179,766.167,179C794.667,179,805.833,179,811.417,179L817,179" id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light-L_immich-server_hdd1_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-67b08bc21c8ad836-light--L_immich-server_hdd1_0" data-points="W3sieCI6NDcxLCJ5IjoxNzl9LHsieCI6NTA4LjUsInkiOjE3OX0seyJ4Ijo2NDYsInkiOjE3OX0seyJ4Ijo3ODMuNSwieSI6MTc5fSx7IngiOjgyMSwieSI6MTc5fV0=" data-look="classic" marker-end="url(#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light_flowchart-v2-pointEnd)"></path><path d="M945,179L969.25,179C993.5,179,1042,179,1089.833,179C1137.667,179,1184.833,179,1208.417,179L1232,179" id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light-L_hdd1_hdd2_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-67b08bc21c8ad836-light--L_hdd1_hdd2_0" data-points="W3sieCI6OTQ1LCJ5IjoxNzl9LHsieCI6MTA5MC41LCJ5IjoxNzl9LHsieCI6MTIzNiwieSI6MTc5fV0=" data-look="classic" marker-end="url(#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light_flowchart-v2-pointEnd)"></path><path d="M173.5,107L184.5,107C195.5,107,217.5,107,240.167,107C262.833,107,286.167,107,303.543,111.132C320.92,115.264,332.34,123.527,338.05,127.659L343.759,131.791" id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light-L_mobile_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-67b08bc21c8ad836-light--L_mobile_in_lan_immich-server_0" data-points="W3sieCI6MTY5LjUsInkiOjEwN30seyJ4IjoyMzkuNSwieSI6MTA3fSx7IngiOjMwOS41LCJ5IjoxMDd9LHsieCI6MzQ3LCJ5IjoxMzQuMTM1Njc4MzkxOTU5OH1d" data-look="classic" marker-start="url(#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light_flowchart-v2-pointEnd)"></path><path d="M173.5,251L184.5,251C195.5,251,217.5,251,240.167,251C262.833,251,286.167,251,303.543,246.868C320.92,242.736,332.34,234.473,338.05,230.341L343.759,226.209" id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light-L_web_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-67b08bc21c8ad836-light--L_web_in_lan_immich-server_0" data-points="W3sieCI6MTY5LjUsInkiOjI1MX0seyJ4IjoyMzkuNSwieSI6MjUxfSx7IngiOjMwOS41LCJ5IjoyNTF9LHsieCI6MzQ3LCJ5IjoyMjMuODY0MzIxNjA4MDQwMn1d" data-look="classic" marker-start="url(#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light_flowchart-v2-pointEnd)"></path></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(646, 179)"><g class="label" data-id="mermaid-67b08bc21c8ad836-light--L_immich-server_hdd1_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-68" y="-60.1" width="136" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">DB</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> /</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 写真</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(1090.5, 179)"><g class="label" data-id="mermaid-67b08bc21c8ad836-light--L_hdd1_hdd2_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-76" y="-60.1" width="152" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">バックアップ</tspan></tspan></text></g></g></g><g class="edgeLabel"><g class="label" data-id="mermaid-67b08bc21c8ad836-light--L_mobile_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g><g class="edgeLabel"><g class="label" data-id="mermaid-67b08bc21c8ad836-light--L_web_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g></g><g class="nodes"><g class="node default" id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light-flowchart-hdd1-1" data-look="classic" transform="translate(883, 179)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>HDD 1</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light-flowchart-immich-server-0" data-look="classic" transform="translate(409, 179)"><rect class="basic label-container" style="fill:#E6FFFA !important;stroke:#008080 !important;stroke-width:3px !important" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="color:black !important" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="color: black !important; display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span style="color:black !important" class="nodeLabel"><p>immich-server</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light-flowchart-hdd2-2" data-look="classic" transform="translate(1298, 179)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>HDD 2</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light-flowchart-mobile_in_lan-4" data-look="classic" transform="translate(107.5, 107)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Mobile App</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light-flowchart-web_in_lan-3" data-look="classic" transform="translate(107.5, 251)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Web App</p></span></div></foreignObject></g></g></g></g></g></g></g><defs><filter id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light-drop-shadow" height="130%" width="130%"><fedropshadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs><defs><filter id="mermaid-67b08bc21c8ad836-light--mermaid-67b08bc21c8ad836-light-drop-shadow-small" height="150%" width="150%"><fedropshadow dx="2" dy="2" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs></svg></span></figure>
<h4 id="dockerでのセットアップと設定ファイルの用意"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#docker%E3%81%A7%E3%81%AE%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97%E3%81%A8%E8%A8%AD%E5%AE%9A%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E7%94%A8%E6%84%8F">Dockerでのセットアップと設定ファイルの用意</a></h4>
<p><a href="https://immich.app/docs/overview/quick-start">公式のクイックスタート</a>と同じくDockerで立ち上げるのが楽。</p>
<p>なお <code>.env</code> ファイルのうち写真アップロード先とDB保存先は、先程マウントした <code>hdd1</code> にしておく。</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">UPLOAD_LOCATION</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">=</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">/mnt/hdd1/immich/images</span></span>
<span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">DB_DATA_LOCATION</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">=</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">/mnt/hdd1/immich/postgres</span></span></code></pre>
<h4 id="immich管理アカウント作成"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#immich%E7%AE%A1%E7%90%86%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E4%BD%9C%E6%88%90">Immich管理アカウント作成</a></h4>
<p>コンテナ立ち上げが成功すると、 <code>http://&#x3C;machine-ip-address>:2283</code> でImmichにアクセスできる。アクセス後は<a href="https://immich.app/docs/administration/user-management#register-the-admin-user">adminユーザの作成</a>をする</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/465baf33e32a5b81/640.avif 640w, https://about.tsono.org/images/generated/465baf33e32a5b81/718.avif 718w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/465baf33e32a5b81/640.webp 640w, https://about.tsono.org/images/generated/465baf33e32a5b81/718.webp 718w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal1-unlimited-storage/create_admin.webp" alt="アクセス後の画面" width="718" height="1272" loading="lazy" decoding="async"></picture>
<p>一般ユーザアカウントも作成できるので、そのまま私・妻用のアカウントを作った。</p>
<p>また、ここでStorageTemplateの設定を確認しておくといい👇️</p>
<h4 id="storagetemplate"><a href="https://immich.app/docs/administration/storage-template/">StorageTemplate</a></h4>
<p>写真や動画の保存先・フォルダ構造やファイル名の付け方の設定のこと。私は <code>UPLOAD_LOCATION/library/ユーザ名/2022/2022-02-03/IMAGE_56437.jpg</code> のような形式で保存されるようにしている。</p>
<p>設定変更以降に追加した写真から反映され、変更前に追加済であったものは、 <code>ジョブ → ストレージテンプレートの移行</code> ボタンを押すことで反映可能。</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/a82833ed15bb8d66/640.avif 640w, https://about.tsono.org/images/generated/a82833ed15bb8d66/960.avif 960w, https://about.tsono.org/images/generated/a82833ed15bb8d66/1280.avif 1280w, https://about.tsono.org/images/generated/a82833ed15bb8d66/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/a82833ed15bb8d66/640.webp 640w, https://about.tsono.org/images/generated/a82833ed15bb8d66/960.webp 960w, https://about.tsono.org/images/generated/a82833ed15bb8d66/1280.webp 1280w, https://about.tsono.org/images/generated/a82833ed15bb8d66/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal1-unlimited-storage/storage_template.png" alt="Immich ストレージテンプレートの移行" width="1600" height="540" loading="lazy" decoding="async"></picture>
<p>私の場合、Google フォト から大量の写真を移動してきたあとに設定をしたため、反映にかなりの時間がかかった。好みがあれば予め設定しておけると嬉しい。</p>
<p>ここまでで、ラズパイ・HDD・Immich のセットアップが完了。次は Googleフォト にある写真・動画を Immich に移行する。</p>
<h3 id="googleフォトからの移行"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#google%E3%83%95%E3%82%A9%E3%83%88%E3%81%8B%E3%82%89%E3%81%AE%E7%A7%BB%E8%A1%8C">Googleフォトからの移行</a></h3>
<figure class="diagram" data-diagram="mermaid"><span class="diagram-light"><svg id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light" width="100%" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 1654.5px;" viewBox="-40.5 -58.1 1654.5 572.1" role="graphics-document document" aria-roledescription="flowchart-v2"><style>#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .error-icon{fill:#552222;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .error-text{fill:#552222;stroke:#552222;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .edge-thickness-normal{stroke-width:1px;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .edge-thickness-thick{stroke-width:3.5px;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .edge-pattern-solid{stroke-dasharray:0;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .marker{fill:#333333;stroke:#333333;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .marker.cross{stroke:#333333;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light p{margin:0;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .cluster-label text{fill:#333;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .cluster-label span{color:#333;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .cluster-label span p{background-color:transparent;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .label text,#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light span{fill:#333;color:#333;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .node rect,#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .node circle,#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .node ellipse,#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .node polygon,#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .rough-node .label text,#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .node .label text,#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .image-shape .label,#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .icon-shape .label{text-anchor:middle;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .rough-node .label,#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .node .label,#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .image-shape .label,#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .icon-shape .label{text-align:center;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .node.clickable{cursor:pointer;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .arrowheadPath{fill:#333333;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .edgePath .path{stroke:#333333;stroke-width:1px;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .flowchart-link{stroke:#333333;fill:none;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .cluster text{fill:#333;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .cluster span{color:#333;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light rect.text{fill:none;stroke-width:0;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .icon-shape,#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .icon-shape p,#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .icon-shape .label rect,#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light .node .neo-node{stroke:#9370DB;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light [data-look="neo"].node rect,#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light [data-look="neo"].cluster rect,#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light [data-look="neo"].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light [data-look="neo"].swimlane.cluster rect{filter:none;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light [data-look="neo"].node path{stroke:#9370DB;stroke-width:1px;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light [data-look="neo"].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light [data-look="neo"].node .neo-line path{stroke:#9370DB;filter:none;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light [data-look="neo"].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light [data-look="neo"].node circle .state-start{fill:#000000;}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light [data-look="neo"].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light [data-look="neo"].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-pointEnd-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="11.5" refY="7" markerUnits="userSpaceOnUse" markerWidth="10.5" markerHeight="14" orient="auto"><path d="M 0 0 L 11.5 7 L 0 14 z" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-pointStart-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="1" refY="7" markerUnits="userSpaceOnUse" markerWidth="11.5" markerHeight="14" orient="auto"><polygon points="0,7 11.5,14 11.5,0" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></polygon></marker><marker id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-circleEnd-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refY="5" refX="12.25" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-circleStart-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-2" refY="5" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-crossEnd-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="17.7" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5;"></path></marker><marker id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-crossStart-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="-3.5" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5; stroke-dasharray: 1,0;"></path></marker><g class="root"><g class="clusters"></g><g class="edgePaths"></g><g class="edgeLabels"></g><g class="nodes"><g class="root" transform="translate(0, 0)"><g class="clusters"><g class="cluster" id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light-lan" data-look="classic"><rect style="" x="8" y="8" width="1566" height="466"></rect><g class="cluster-label" transform="translate(747, 8)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">LAN</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light-hdds" data-look="classic"><rect style="" x="922.5" y="152" width="614" height="192"></rect><g class="cluster-label" transform="translate(1164.5, 152)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">HDDケース</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light-rapy" data-look="classic"><rect style="" x="448.5" y="53" width="199" height="369"></rect><g class="cluster-label" transform="translate(460, 53)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Raspberry</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> Pi</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 4</tspan></tspan></text></g></g></g></g><g class="edgePaths"><path d="M169.5,104L192.75,104C216,104,262.5,104,309,104C355.5,104,402,104,436.042,119.618C470.083,135.236,491.667,166.473,502.459,182.091L513.25,197.709" id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light-L_GoogleTakeout_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style="stroke:#008080;stroke-width:4px;color:008080;fill:none;;;stroke:#008080;stroke-width:4px;color:008080;fill:none" data-edge="true" data-et="edge" data-id="mermaid-b31c7e60d540c229-light--L_GoogleTakeout_immich-server_0" data-points="W3sieCI6MTY5LjUsInkiOjEwNH0seyJ4IjozMDksInkiOjEwNH0seyJ4Ijo0NDguNSwieSI6MTA0fSx7IngiOjUxNS41MjQzMDU1NTU1NTU1LCJ5IjoyMDF9XQ==" data-look="classic" marker-end="url(#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-pointEnd__008080)"></path><path d="M610,248L616.25,248C622.5,248,635,248,664.167,248C693.333,248,739.167,248,785,248C830.833,248,876.667,248,905.167,248C933.667,248,944.833,248,950.417,248L956,248" id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light-L_immich-server_hdd1_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style="stroke:#008080;stroke-width:4px;color:008080;fill:none;;;stroke:#008080;stroke-width:4px;color:008080;fill:none" data-edge="true" data-et="edge" data-id="mermaid-b31c7e60d540c229-light--L_immich-server_hdd1_0" data-points="W3sieCI6NjEwLCJ5IjoyNDh9LHsieCI6NjQ3LjUsInkiOjI0OH0seyJ4Ijo3ODUsInkiOjI0OH0seyJ4Ijo5MjIuNSwieSI6MjQ4fSx7IngiOjk2MCwieSI6MjQ4fV0=" data-look="classic" marker-end="url(#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-pointEnd__008080)"></path><path d="M1084,248L1108.25,248C1132.5,248,1181,248,1228.833,248C1276.667,248,1323.833,248,1347.417,248L1371,248" id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light-L_hdd1_hdd2_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-b31c7e60d540c229-light--L_hdd1_hdd2_0" data-points="W3sieCI6MTA4NCwieSI6MjQ4fSx7IngiOjEyMjkuNSwieSI6MjQ4fSx7IngiOjEzNzUsInkiOjI0OH1d" data-look="classic" marker-end="url(#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-pointEnd)"></path><path d="M173.5,248L196.083,248C218.667,248,263.833,248,309.667,248C355.5,248,402,248,430.833,248C459.667,248,470.833,248,476.417,248L482,248" id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light-L_mobile_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-b31c7e60d540c229-light--L_mobile_in_lan_immich-server_0" data-points="W3sieCI6MTY5LjUsInkiOjI0OH0seyJ4IjozMDksInkiOjI0OH0seyJ4Ijo0NDguNSwieSI6MjQ4fSx7IngiOjQ4NiwieSI6MjQ4fV0=" data-look="classic" marker-start="url(#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-pointEnd)"></path><path d="M173.5,392L196.083,392C218.667,392,263.833,392,309.667,392C355.5,392,402,392,436.042,376.382C470.083,360.764,491.667,329.527,502.459,313.909L513.25,298.291" id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light-L_web_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-b31c7e60d540c229-light--L_web_in_lan_immich-server_0" data-points="W3sieCI6MTY5LjUsInkiOjM5Mn0seyJ4IjozMDksInkiOjM5Mn0seyJ4Ijo0NDguNSwieSI6MzkyfSx7IngiOjUxNS41MjQzMDU1NTU1NTU1LCJ5IjoyOTV9XQ==" data-look="classic" marker-start="url(#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-pointEnd)"></path></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(309, 104)"><g class="label" data-id="mermaid-b31c7e60d540c229-light--L_GoogleTakeout_immich-server_0" transform="translate(0, 16.1)"><g><rect class="background" style="color:008080 !important" x="-70" y="-60.1" width="140" height="88"></rect><text y="-10.1" text-anchor="middle" style="fill:008080 !important"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">immich-go</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(785, 248)"><g class="label" data-id="mermaid-b31c7e60d540c229-light--L_immich-server_hdd1_0" transform="translate(0, 16.1)"><g><rect class="background" style="color:008080 !important" x="-68" y="-60.1" width="136" height="88"></rect><text y="-10.1" text-anchor="middle" style="fill:008080 !important"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">DB</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> /</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 写真</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(1229.5, 248)"><g class="label" data-id="mermaid-b31c7e60d540c229-light--L_hdd1_hdd2_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-76" y="-60.1" width="152" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">バックアップ</tspan></tspan></text></g></g></g><g class="edgeLabel"><g class="label" data-id="mermaid-b31c7e60d540c229-light--L_mobile_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g><g class="edgeLabel"><g class="label" data-id="mermaid-b31c7e60d540c229-light--L_web_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g></g><g class="nodes"><g class="node default" id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light-flowchart-hdd1-3" data-look="classic" transform="translate(1022, 248)"><rect class="basic label-container" style="fill:#E6FFFA !important;stroke:#008080 !important;stroke-width:3px !important" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="color:black !important" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="color: black !important; display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span style="color:black !important" class="nodeLabel"><p>HDD 1</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light-flowchart-GoogleTakeout-1" data-look="classic" transform="translate(107.5, 104)"><rect class="basic label-container" style="fill:#E6FFFA !important;stroke:#008080 !important;stroke-width:3px !important" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="color:black !important" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="color: black !important; display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span style="color:black !important" class="nodeLabel"><p>GoogleTakeout</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light-flowchart-immich-server-0" data-look="classic" transform="translate(548, 248)"><rect class="basic label-container" style="fill:#E6FFFA !important;stroke:#008080 !important;stroke-width:3px !important" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="color:black !important" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="color: black !important; display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span style="color:black !important" class="nodeLabel"><p>immich-server</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light-flowchart-hdd2-4" data-look="classic" transform="translate(1437, 248)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>HDD 2</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light-flowchart-mobile_in_lan-6" data-look="classic" transform="translate(107.5, 248)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Mobile App</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light-flowchart-web_in_lan-5" data-look="classic" transform="translate(107.5, 392)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Web App</p></span></div></foreignObject></g></g></g></g></g></g><marker id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light_flowchart-v2-pointEnd__008080" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;" stroke="#008080" fill="#008080"></path></marker></g><defs><filter id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light-drop-shadow" height="130%" width="130%"><fedropshadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs><defs><filter id="mermaid-b31c7e60d540c229-light--mermaid-b31c7e60d540c229-light-drop-shadow-small" height="150%" width="150%"><fedropshadow dx="2" dy="2" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs></svg></span></figure>
<p><code>immich-go</code> を使う。Google フォトの 写真をImmichで管理する保存領域に移行できるコマンドラインツールです。</p>
<p>必要な材料👇️</p>
<ol>
<li>immich-go</li>
<li>Google Takeout
<ul>
<li>Google アカウントに保存されているデータをエクスポートしたもの</li>
</ul>
</li>
<li>ユーザアカウントごとのImmich API キー
<ul>
<li>Immichに対してアプリケーション外から操作をする際に必要な鍵</li>
</ul>
</li>
</ol>
<p>具体的には、</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">./immich-go</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> -server=http://</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">&#x3C;</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">machine-ip-address</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">></span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">:2283</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> -key=</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">&#x3C;</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">Immichで作成したAPI</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> キ</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">ー</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">></span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> upload</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> -create-albums</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> -google-photos</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> &#x3C;</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">ダウンロードしたGoogle</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> Photo</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> Takeout</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> のパ</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">ス</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">></span></span></code></pre>
<p>とすることで、Googleから落としてきたコンテンツをImmichの任意ユーザのコンテンツとして取り込むことができる。</p>
<h4 id="写真の重複"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E5%86%99%E7%9C%9F%E3%81%AE%E9%87%8D%E8%A4%87">写真の重複</a></h4>
<p>バックアップ前に“写真がどこにあるか”を整理しておく必要がある。過去のすべての写真がスマホに入っていれば Immich のモバイルアプリを起動して、スマホからバックアップするだけでOK。</p>
<p>しかし実際には「Googleフォトだけにある写真」「スマホだけにある写真」「両方にある写真」が混在している。</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>// Google フォトに保存された写真と、スマホに保存された写真が一部重なってるイメージ</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>時系列:      2008 ------2017-------2023----------> 新しい</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>Googleフォト: [===========++++++++++]</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>スマホ       :           [++++++++++==========]</span></span></code></pre>
<p>同じ写真がバックアップされてしまうと、容量がもったいない。</p>
<p>今回は、2008〜2023年は Google フォトから移行し、それ以降はスマホから直接バックアップすることにした。</p>
<p>厳密に分けることは難しく2024年前後に重複が発生するが、Immich には重複検出・削除機能があるため、多少は許容範囲。</p>
<img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal1-unlimited-storage/duplicate_delete.gif" alt="Immichの重複検出・削除機能" width="540" height="290" loading="lazy" decoding="async">
<h4 id="immich-go"><a href="https://github.com/simulot/immich-go">immich-go</a></h4>
<p>immich-go をダウンロードする。 <code>&#x3C;> Code</code> 押下 > <code>Download ZIP</code> でOK。</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/95d73752d1aa8a78/640.avif 640w, https://about.tsono.org/images/generated/95d73752d1aa8a78/960.avif 960w, https://about.tsono.org/images/generated/95d73752d1aa8a78/1280.avif 1280w, https://about.tsono.org/images/generated/95d73752d1aa8a78/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/95d73752d1aa8a78/640.webp 640w, https://about.tsono.org/images/generated/95d73752d1aa8a78/960.webp 960w, https://about.tsono.org/images/generated/95d73752d1aa8a78/1280.webp 1280w, https://about.tsono.org/images/generated/95d73752d1aa8a78/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal1-unlimited-storage/immich-go.webp" alt="immich-goのリポジトリ" width="1600" height="855" loading="lazy" decoding="async"></picture>
<p>PC内の好きな場所においておく。</p>
<h4 id="google-takeout"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#google-takeout">Google Takeout</a></h4>
<p>以下のリンクから Google Takeout にアクセスして、エクスポートする。
<a href="https://takeout.google.com/">https://takeout.google.com/</a></p>
<p>Google フォトのみチェックボックスをONにして <code>次のステップ</code> を押下</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/8b0b535ec2940367/640.avif 640w, https://about.tsono.org/images/generated/8b0b535ec2940367/960.avif 960w, https://about.tsono.org/images/generated/8b0b535ec2940367/1280.avif 1280w, https://about.tsono.org/images/generated/8b0b535ec2940367/1350.avif 1350w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/8b0b535ec2940367/640.webp 640w, https://about.tsono.org/images/generated/8b0b535ec2940367/960.webp 960w, https://about.tsono.org/images/generated/8b0b535ec2940367/1280.webp 1280w, https://about.tsono.org/images/generated/8b0b535ec2940367/1350.webp 1350w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal1-unlimited-storage/takeout_export.webp" alt="Google データ エクスポート" width="1350" height="1148" loading="lazy" decoding="async"></picture>
<p><code>エクスポートを作成</code> を押下</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/4eab619f0287ce4e/640.avif 640w, https://about.tsono.org/images/generated/4eab619f0287ce4e/960.avif 960w, https://about.tsono.org/images/generated/4eab619f0287ce4e/1054.avif 1054w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/4eab619f0287ce4e/640.webp 640w, https://about.tsono.org/images/generated/4eab619f0287ce4e/960.webp 960w, https://about.tsono.org/images/generated/4eab619f0287ce4e/1054.webp 1054w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal1-unlimited-storage/export.webp" alt="export.png" width="1054" height="1456" loading="lazy" decoding="async"></picture>
<p>しばらく待つとGoogleからメールが届く</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/cd3c7d0c13174780/640.avif 640w, https://about.tsono.org/images/generated/cd3c7d0c13174780/960.avif 960w, https://about.tsono.org/images/generated/cd3c7d0c13174780/1280.avif 1280w, https://about.tsono.org/images/generated/cd3c7d0c13174780/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/cd3c7d0c13174780/640.webp 640w, https://about.tsono.org/images/generated/cd3c7d0c13174780/960.webp 960w, https://about.tsono.org/images/generated/cd3c7d0c13174780/1280.webp 1280w, https://about.tsono.org/images/generated/cd3c7d0c13174780/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal1-unlimited-storage/mail.webp" alt="Googleから届くメール" width="1600" height="994" loading="lazy" decoding="async"></picture>
<p>メール内リンクに飛ぶと、件数ごとにダウンロードボタンが設置されている。順次押下してダウンロードしていけばOK。zipファイルがダウンロードされるはず。</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/3e105c8bfd714be2/640.avif 640w, https://about.tsono.org/images/generated/3e105c8bfd714be2/960.avif 960w, https://about.tsono.org/images/generated/3e105c8bfd714be2/1280.avif 1280w, https://about.tsono.org/images/generated/3e105c8bfd714be2/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/3e105c8bfd714be2/640.webp 640w, https://about.tsono.org/images/generated/3e105c8bfd714be2/960.webp 960w, https://about.tsono.org/images/generated/3e105c8bfd714be2/1280.webp 1280w, https://about.tsono.org/images/generated/3e105c8bfd714be2/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal1-unlimited-storage/download.webp" alt="download.png" width="1600" height="1243" loading="lazy" decoding="async"></picture>
<p>件数が多すぎて面倒であれば、エクスポート前にファイルサイズを大きめに設定しておくといい。</p>
<h4 id="immich-api-キー"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#immich-api-%E3%82%AD%E3%83%BC">Immich API キー</a></h4>
<p>お次に <code>API キー</code> を発行する。<code>immich-go</code> から Immich のユーザアカウントに対して操作する際に必要な鍵。ユーザアカウント事に発行する。</p>
<p>手順</p>
<ol>
<li>Immichにログイン</li>
<li>アカウント設定</li>
<li>APIキー</li>
<li>新しいAPIキー</li>
<li>任意の名前をつけて作成押下</li>
<li>新しいキーが発行されるのでコピーしておく</li>
</ol>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/32ee0057e2ce6faf/640.avif 640w, https://about.tsono.org/images/generated/32ee0057e2ce6faf/960.avif 960w, https://about.tsono.org/images/generated/32ee0057e2ce6faf/1280.avif 1280w, https://about.tsono.org/images/generated/32ee0057e2ce6faf/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/32ee0057e2ce6faf/640.webp 640w, https://about.tsono.org/images/generated/32ee0057e2ce6faf/960.webp 960w, https://about.tsono.org/images/generated/32ee0057e2ce6faf/1280.webp 1280w, https://about.tsono.org/images/generated/32ee0057e2ce6faf/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal1-unlimited-storage/api-key.webp" alt="apiキーの作成" width="1600" height="1068" loading="lazy" decoding="async"></picture>
<h4 id="immich-goで移行"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#immich-go%E3%81%A7%E7%A7%BB%E8%A1%8C">immich-goで移行</a></h4>
<p>コマンドを実行する前に、<code>Google Takeout</code> の zip を解凍して中身を確認する。今回は 2024年以降の写真はスマホからバックアップする方針のため、その期間を含む zip は不要。使用しないファイルはどこかに移動しておく</p>
<p>必要な zip ファイルを準備ができたら、 <code>immich-go</code> をダウンロードしたディレクトリへ移動して、次のコマンドを実行。</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line"><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">./immich-go</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> -server=http://</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">&#x3C;</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">machine-ip-address</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">></span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">:2283</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> -key=</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">&#x3C;</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">Immichで作成したAPI</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> キ</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">ー</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">></span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> upload</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> -create-albums</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> -google-photos</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF"> /takeoutがあるディレクトリ名/takeout-</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">*</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">.zip</span></span></code></pre>
<p>なお <code>--dry-run</code> オプションをつけることで、実行される処理を事前に確認できる。</p>
<p>コマンド実行後、しばらく待てば Immich に画像や動画が取り込まれている。私のアカウントは写真が多かったためコマンドを実行して寝た🛌。翌朝には終わっていた。</p>
<h3 id="モバイルアプリの設定"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E3%83%A2%E3%83%90%E3%82%A4%E3%83%AB%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE%E8%A8%AD%E5%AE%9A">モバイルアプリの設定</a></h3>
<p>次に Immich モバイルアプリをダウンロードしてセッティング。</p>
<figure class="diagram" data-diagram="mermaid"><span class="diagram-light"><svg id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light" width="100%" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 1515.5px;" viewBox="-40.5 -58.1 1515.5 448.1" role="graphics-document document" aria-roledescription="flowchart-v2"><style>#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .error-icon{fill:#552222;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .error-text{fill:#552222;stroke:#552222;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .edge-thickness-normal{stroke-width:1px;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .edge-thickness-thick{stroke-width:3.5px;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .edge-pattern-solid{stroke-dasharray:0;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .marker{fill:#333333;stroke:#333333;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .marker.cross{stroke:#333333;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light p{margin:0;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .cluster-label text{fill:#333;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .cluster-label span{color:#333;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .cluster-label span p{background-color:transparent;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .label text,#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light span{fill:#333;color:#333;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .node rect,#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .node circle,#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .node ellipse,#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .node polygon,#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .rough-node .label text,#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .node .label text,#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .image-shape .label,#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .icon-shape .label{text-anchor:middle;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .rough-node .label,#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .node .label,#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .image-shape .label,#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .icon-shape .label{text-align:center;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .node.clickable{cursor:pointer;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .arrowheadPath{fill:#333333;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .edgePath .path{stroke:#333333;stroke-width:1px;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .flowchart-link{stroke:#333333;fill:none;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .cluster text{fill:#333;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .cluster span{color:#333;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light rect.text{fill:none;stroke-width:0;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .icon-shape,#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .icon-shape p,#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .icon-shape .label rect,#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light .node .neo-node{stroke:#9370DB;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light [data-look="neo"].node rect,#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light [data-look="neo"].cluster rect,#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light [data-look="neo"].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light [data-look="neo"].swimlane.cluster rect{filter:none;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light [data-look="neo"].node path{stroke:#9370DB;stroke-width:1px;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light [data-look="neo"].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light [data-look="neo"].node .neo-line path{stroke:#9370DB;filter:none;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light [data-look="neo"].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light [data-look="neo"].node circle .state-start{fill:#000000;}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light [data-look="neo"].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light [data-look="neo"].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light_flowchart-v2-pointEnd-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="11.5" refY="7" markerUnits="userSpaceOnUse" markerWidth="10.5" markerHeight="14" orient="auto"><path d="M 0 0 L 11.5 7 L 0 14 z" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light_flowchart-v2-pointStart-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="1" refY="7" markerUnits="userSpaceOnUse" markerWidth="11.5" markerHeight="14" orient="auto"><polygon points="0,7 11.5,14 11.5,0" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></polygon></marker><marker id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light_flowchart-v2-circleEnd-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refY="5" refX="12.25" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light_flowchart-v2-circleStart-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-2" refY="5" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light_flowchart-v2-crossEnd-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="17.7" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5;"></path></marker><marker id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light_flowchart-v2-crossStart-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="-3.5" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5; stroke-dasharray: 1,0;"></path></marker><g class="root"><g class="clusters"></g><g class="edgePaths"></g><g class="edgeLabels"></g><g class="nodes"><g class="root" transform="translate(0, 0)"><g class="clusters"><g class="cluster" id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light-lan" data-look="classic"><rect style="" x="8" y="8" width="1427" height="342"></rect><g class="cluster-label" transform="translate(677.5, 8)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">LAN</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light-hdds" data-look="classic"><rect style="" x="783.5" y="83" width="614" height="192"></rect><g class="cluster-label" transform="translate(1025.5, 83)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">HDDケース</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light-rapy" data-look="classic"><rect style="" x="309.5" y="46" width="199" height="256"></rect><g class="cluster-label" transform="translate(321, 46)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Raspberry</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> Pi</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 4</tspan></tspan></text></g></g></g></g><g class="edgePaths"><path d="M471,179L477.25,179C483.5,179,496,179,525.167,179C554.333,179,600.167,179,646,179C691.833,179,737.667,179,766.167,179C794.667,179,805.833,179,811.417,179L817,179" id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light-L_immich-server_hdd1_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-d4ad5ec67b32aba0-light--L_immich-server_hdd1_0" data-points="W3sieCI6NDcxLCJ5IjoxNzl9LHsieCI6NTA4LjUsInkiOjE3OX0seyJ4Ijo2NDYsInkiOjE3OX0seyJ4Ijo3ODMuNSwieSI6MTc5fSx7IngiOjgyMSwieSI6MTc5fV0=" data-look="classic" marker-end="url(#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light_flowchart-v2-pointEnd)"></path><path d="M945,179L969.25,179C993.5,179,1042,179,1089.833,179C1137.667,179,1184.833,179,1208.417,179L1232,179" id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light-L_hdd1_hdd2_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-d4ad5ec67b32aba0-light--L_hdd1_hdd2_0" data-points="W3sieCI6OTQ1LCJ5IjoxNzl9LHsieCI6MTA5MC41LCJ5IjoxNzl9LHsieCI6MTIzNiwieSI6MTc5fV0=" data-look="classic" marker-end="url(#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light_flowchart-v2-pointEnd)"></path><path d="M173.5,107L184.5,107C195.5,107,217.5,107,240.167,107C262.833,107,286.167,107,303.543,111.132C320.92,115.264,332.34,123.527,338.05,127.659L343.759,131.791" id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light-L_mobile_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-d4ad5ec67b32aba0-light--L_mobile_in_lan_immich-server_0" data-points="W3sieCI6MTY5LjUsInkiOjEwN30seyJ4IjoyMzkuNSwieSI6MTA3fSx7IngiOjMwOS41LCJ5IjoxMDd9LHsieCI6MzQ3LCJ5IjoxMzQuMTM1Njc4MzkxOTU5OH1d" data-look="classic" marker-start="url(#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light_flowchart-v2-pointEnd)"></path><path d="M173.5,251L184.5,251C195.5,251,217.5,251,240.167,251C262.833,251,286.167,251,303.543,246.868C320.92,242.736,332.34,234.473,338.05,230.341L343.759,226.209" id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light-L_web_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-d4ad5ec67b32aba0-light--L_web_in_lan_immich-server_0" data-points="W3sieCI6MTY5LjUsInkiOjI1MX0seyJ4IjoyMzkuNSwieSI6MjUxfSx7IngiOjMwOS41LCJ5IjoyNTF9LHsieCI6MzQ3LCJ5IjoyMjMuODY0MzIxNjA4MDQwMn1d" data-look="classic" marker-start="url(#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light_flowchart-v2-pointEnd)"></path></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(646, 179)"><g class="label" data-id="mermaid-d4ad5ec67b32aba0-light--L_immich-server_hdd1_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-68" y="-60.1" width="136" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">DB</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> /</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 写真</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(1090.5, 179)"><g class="label" data-id="mermaid-d4ad5ec67b32aba0-light--L_hdd1_hdd2_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-76" y="-60.1" width="152" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">バックアップ</tspan></tspan></text></g></g></g><g class="edgeLabel"><g class="label" data-id="mermaid-d4ad5ec67b32aba0-light--L_mobile_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g><g class="edgeLabel"><g class="label" data-id="mermaid-d4ad5ec67b32aba0-light--L_web_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g></g><g class="nodes"><g class="node default" id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light-flowchart-hdd1-1" data-look="classic" transform="translate(883, 179)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>HDD 1</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light-flowchart-immich-server-0" data-look="classic" transform="translate(409, 179)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>immich-server</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light-flowchart-hdd2-2" data-look="classic" transform="translate(1298, 179)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>HDD 2</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light-flowchart-mobile_in_lan-4" data-look="classic" transform="translate(107.5, 107)"><rect class="basic label-container" style="fill:#E6FFFA !important;stroke:#008080 !important;stroke-width:3px !important" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="color:black !important" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="color: black !important; display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span style="color:black !important" class="nodeLabel"><p>Mobile App</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light-flowchart-web_in_lan-3" data-look="classic" transform="translate(107.5, 251)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Web App</p></span></div></foreignObject></g></g></g></g></g></g></g><defs><filter id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light-drop-shadow" height="130%" width="130%"><fedropshadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs><defs><filter id="mermaid-d4ad5ec67b32aba0-light--mermaid-d4ad5ec67b32aba0-light-drop-shadow-small" height="150%" width="150%"><fedropshadow dx="2" dy="2" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs></svg></span></figure>
<p>ダウンロード・ログイン・バックアップ、すべて以下のドキュメントに従えば無問題️<br>
<a href="https://immich.app/docs/features/mobile-app/">https://immich.app/docs/features/mobile-app/</a></p>
<p>アプリ起動直後は、 <code>http://&#x3C;machine-ip-address>:2283</code> でアクセス</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/fc7c00c30a190d6b/640.avif 640w, https://about.tsono.org/images/generated/fc7c00c30a190d6b/960.avif 960w, https://about.tsono.org/images/generated/fc7c00c30a190d6b/1125.avif 1125w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/fc7c00c30a190d6b/640.webp 640w, https://about.tsono.org/images/generated/fc7c00c30a190d6b/960.webp 960w, https://about.tsono.org/images/generated/fc7c00c30a190d6b/1125.webp 1125w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal1-unlimited-storage/mobile_app_boot.webp" alt="Immichモバイルアプリ起動直後" width="1125" height="2436" loading="lazy" decoding="async"></picture>
<p>作成したユーザのメールアドレスとパスワードを打ち込めばログイン可能</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/a8a4a2a735f3caea/333.avif 333w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/a8a4a2a735f3caea/333.webp 333w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal1-unlimited-storage/mobile_app_login.png" alt="ログイン画面" width="333" height="720" loading="lazy" decoding="async"></picture>
<p>次にスマホのローカルに入っている写真・動画のバックアップ設定を行う<br>
<a href="https://immich.app/docs/features/mobile-app/#backup">https://immich.app/docs/features/mobile-app/#backup</a></p>
<p>自動バックアップ設定もしておくと良い<br>
<a href="https://immich.app/docs/features/automatic-backup">https://immich.app/docs/features/automatic-backup</a></p>
<p>これで、スマホで取った写真をImmich経由でHDDに保存し、そのまま閲覧できるようになる。</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/ebfc4e0c51a51693/333.avif 333w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/ebfc4e0c51a51693/333.webp 333w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal1-unlimited-storage/mobile_app_timeline.png" alt="Immichモバイルアプリ タイムラインの様子" width="333" height="720" loading="lazy" decoding="async"></picture>
<h3 id="hdd1をバックアップする"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#hdd1%E3%82%92%E3%83%90%E3%83%83%E3%82%AF%E3%82%A2%E3%83%83%E3%83%97%E3%81%99%E3%82%8B">HDD1をバックアップする</a></h3>
<p>最後にHDD1のデータをHDD2にバックアップするよう設定したい。HDD1がだめになったらすべての資産が消えてしまうので</p>
<figure class="diagram" data-diagram="mermaid"><span class="diagram-light"><svg id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light" width="100%" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 1515.5px;" viewBox="-40.5 -58.1 1515.5 448.1" role="graphics-document document" aria-roledescription="flowchart-v2"><style>#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .error-icon{fill:#552222;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .error-text{fill:#552222;stroke:#552222;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .edge-thickness-normal{stroke-width:1px;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .edge-thickness-thick{stroke-width:3.5px;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .edge-pattern-solid{stroke-dasharray:0;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .marker{fill:#333333;stroke:#333333;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .marker.cross{stroke:#333333;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light p{margin:0;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .cluster-label text{fill:#333;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .cluster-label span{color:#333;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .cluster-label span p{background-color:transparent;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .label text,#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light span{fill:#333;color:#333;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .node rect,#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .node circle,#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .node ellipse,#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .node polygon,#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .rough-node .label text,#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .node .label text,#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .image-shape .label,#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .icon-shape .label{text-anchor:middle;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .rough-node .label,#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .node .label,#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .image-shape .label,#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .icon-shape .label{text-align:center;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .node.clickable{cursor:pointer;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .arrowheadPath{fill:#333333;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .edgePath .path{stroke:#333333;stroke-width:1px;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .flowchart-link{stroke:#333333;fill:none;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .cluster text{fill:#333;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .cluster span{color:#333;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light rect.text{fill:none;stroke-width:0;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .icon-shape,#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .icon-shape p,#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .icon-shape .label rect,#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light .node .neo-node{stroke:#9370DB;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light [data-look="neo"].node rect,#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light [data-look="neo"].cluster rect,#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light [data-look="neo"].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light [data-look="neo"].swimlane.cluster rect{filter:none;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light [data-look="neo"].node path{stroke:#9370DB;stroke-width:1px;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light [data-look="neo"].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light [data-look="neo"].node .neo-line path{stroke:#9370DB;filter:none;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light [data-look="neo"].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light [data-look="neo"].node circle .state-start{fill:#000000;}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light [data-look="neo"].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light [data-look="neo"].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light_flowchart-v2-pointEnd-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="11.5" refY="7" markerUnits="userSpaceOnUse" markerWidth="10.5" markerHeight="14" orient="auto"><path d="M 0 0 L 11.5 7 L 0 14 z" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light_flowchart-v2-pointStart-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="1" refY="7" markerUnits="userSpaceOnUse" markerWidth="11.5" markerHeight="14" orient="auto"><polygon points="0,7 11.5,14 11.5,0" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></polygon></marker><marker id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light_flowchart-v2-circleEnd-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refY="5" refX="12.25" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light_flowchart-v2-circleStart-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-2" refY="5" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light_flowchart-v2-crossEnd-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="17.7" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5;"></path></marker><marker id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light_flowchart-v2-crossStart-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="-3.5" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5; stroke-dasharray: 1,0;"></path></marker><g class="root"><g class="clusters"></g><g class="edgePaths"></g><g class="edgeLabels"></g><g class="nodes"><g class="root" transform="translate(0, 0)"><g class="clusters"><g class="cluster" id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light-lan" data-look="classic"><rect style="" x="8" y="8" width="1427" height="342"></rect><g class="cluster-label" transform="translate(677.5, 8)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">LAN</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light-hdds" data-look="classic"><rect style="" x="783.5" y="83" width="614" height="192"></rect><g class="cluster-label" transform="translate(1025.5, 83)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">HDDケース</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light-rapy" data-look="classic"><rect style="" x="309.5" y="46" width="199" height="256"></rect><g class="cluster-label" transform="translate(321, 46)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Raspberry</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> Pi</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 4</tspan></tspan></text></g></g></g></g><g class="edgePaths"><path d="M471,179L477.25,179C483.5,179,496,179,525.167,179C554.333,179,600.167,179,646,179C691.833,179,737.667,179,766.167,179C794.667,179,805.833,179,811.417,179L817,179" id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light-L_immich-server_hdd1_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-f47ca181e054781f-light--L_immich-server_hdd1_0" data-points="W3sieCI6NDcxLCJ5IjoxNzl9LHsieCI6NTA4LjUsInkiOjE3OX0seyJ4Ijo2NDYsInkiOjE3OX0seyJ4Ijo3ODMuNSwieSI6MTc5fSx7IngiOjgyMSwieSI6MTc5fV0=" data-look="classic" marker-end="url(#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light_flowchart-v2-pointEnd)"></path><path d="M945,179L969.25,179C993.5,179,1042,179,1089.833,179C1137.667,179,1184.833,179,1208.417,179L1232,179" id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light-L_hdd1_hdd2_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-f47ca181e054781f-light--L_hdd1_hdd2_0" data-points="W3sieCI6OTQ1LCJ5IjoxNzl9LHsieCI6MTA5MC41LCJ5IjoxNzl9LHsieCI6MTIzNiwieSI6MTc5fV0=" data-look="classic" marker-end="url(#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light_flowchart-v2-pointEnd)"></path><path d="M173.5,107L184.5,107C195.5,107,217.5,107,240.167,107C262.833,107,286.167,107,303.543,111.132C320.92,115.264,332.34,123.527,338.05,127.659L343.759,131.791" id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light-L_mobile_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-f47ca181e054781f-light--L_mobile_in_lan_immich-server_0" data-points="W3sieCI6MTY5LjUsInkiOjEwN30seyJ4IjoyMzkuNSwieSI6MTA3fSx7IngiOjMwOS41LCJ5IjoxMDd9LHsieCI6MzQ3LCJ5IjoxMzQuMTM1Njc4MzkxOTU5OH1d" data-look="classic" marker-start="url(#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light_flowchart-v2-pointEnd)"></path><path d="M173.5,251L184.5,251C195.5,251,217.5,251,240.167,251C262.833,251,286.167,251,303.543,246.868C320.92,242.736,332.34,234.473,338.05,230.341L343.759,226.209" id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light-L_web_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-f47ca181e054781f-light--L_web_in_lan_immich-server_0" data-points="W3sieCI6MTY5LjUsInkiOjI1MX0seyJ4IjoyMzkuNSwieSI6MjUxfSx7IngiOjMwOS41LCJ5IjoyNTF9LHsieCI6MzQ3LCJ5IjoyMjMuODY0MzIxNjA4MDQwMn1d" data-look="classic" marker-start="url(#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light_flowchart-v2-pointEnd)"></path></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(646, 179)"><g class="label" data-id="mermaid-f47ca181e054781f-light--L_immich-server_hdd1_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-68" y="-60.1" width="136" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">DB</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> /</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 写真</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(1090.5, 179)"><g class="label" data-id="mermaid-f47ca181e054781f-light--L_hdd1_hdd2_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-76" y="-60.1" width="152" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">バックアップ</tspan></tspan></text></g></g></g><g class="edgeLabel"><g class="label" data-id="mermaid-f47ca181e054781f-light--L_mobile_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g><g class="edgeLabel"><g class="label" data-id="mermaid-f47ca181e054781f-light--L_web_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g></g><g class="nodes"><g class="node default" id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light-flowchart-hdd1-1" data-look="classic" transform="translate(883, 179)"><rect class="basic label-container" style="fill:#E6FFFA !important;stroke:#008080 !important;stroke-width:3px !important" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="color:black !important" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="color: black !important; display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span style="color:black !important" class="nodeLabel"><p>HDD 1</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light-flowchart-immich-server-0" data-look="classic" transform="translate(409, 179)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>immich-server</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light-flowchart-hdd2-2" data-look="classic" transform="translate(1298, 179)"><rect class="basic label-container" style="fill:#E6FFFA !important;stroke:#008080 !important;stroke-width:3px !important" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="color:black !important" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="color: black !important; display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span style="color:black !important" class="nodeLabel"><p>HDD 2</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light-flowchart-mobile_in_lan-4" data-look="classic" transform="translate(107.5, 107)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Mobile App</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light-flowchart-web_in_lan-3" data-look="classic" transform="translate(107.5, 251)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Web App</p></span></div></foreignObject></g></g></g></g></g></g></g><defs><filter id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light-drop-shadow" height="130%" width="130%"><fedropshadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs><defs><filter id="mermaid-f47ca181e054781f-light--mermaid-f47ca181e054781f-light-drop-shadow-small" height="150%" width="150%"><fedropshadow dx="2" dy="2" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs></svg></span></figure>
<p><a href="https://www.borgbackup.org">Borg</a> を使う。差分バックアップツール。
Immich公式でも <code>borg</code> による<a href="https://immich.app/docs/guides/template-backup-script/">バックアップ方法</a>が紹介されているため採用。</p>
<p>手順は公式ドキュメントに従う。ドキュメント中の “Borg backup template” をベースにしたスクリプトを<code>immich-borg.sh</code>として保存し、毎週土曜の午前1:00に実行されるよう<code>crontab</code>を設定。</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>0 1 * * 6 /immich-borg.sh</span></span></code></pre>
<h3 id="done"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#done">Done</a></h3>
<p>これで、スマホから Immich にログインして、撮影した写真や動画をそのまま HDD にバックアップできる環境が整った。
当初の条件もクリア</p>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" checked disabled> 1. 事実上、無限に写真と動画が保存できること</li>
<li class="task-list-item"><input type="checkbox" checked disabled> 2. スマホから保存・閲覧できること</li>
<li class="task-list-item"><input type="checkbox" checked disabled> 3. サブスクはしないこと</li>
<li class="task-list-item"><input type="checkbox" checked disabled> 4. Google フォトに保存した大量のコンテンツを引き継げること</li>
</ul>
<p>週に一度は別のHDDにもバックアップを行う<sup><a href="https://about.tsono.org/articles/raspi-immich-home-photos#user-content-fn-fn:1" id="user-content-fnref-fn:1" data-footnote-ref="" aria-describedby="footnote-label">1</a></sup>。</p>
<p>加えて Immich のアルバム機能を使えば、「息子用アルバム」や「旅行用アルバム」を作成し、私と妻がそれぞれ写真を追加できる。これまで Google フォトや LINE で行っていたスタイルも実現できる。</p>
<p>これにて、フォトストレージの構築はクリア。家庭内の写真管理は解決した。</p>
<h2 id="ゴール2-遠隔地の家族に安全に写真をシェアする"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E3%82%B4%E3%83%BC%E3%83%AB2-%E9%81%A0%E9%9A%94%E5%9C%B0%E3%81%AE%E5%AE%B6%E6%97%8F%E3%81%AB%E5%AE%89%E5%85%A8%E3%81%AB%E5%86%99%E7%9C%9F%E3%82%92%E3%82%B7%E3%82%A7%E3%82%A2%E3%81%99%E3%82%8B">ゴール2: 遠隔地の家族に安全に写真をシェアする</a></h2>
<p>次の課題は両親への共有。<br>
いままで私は LINE で親に写真を送っていた。が、結構面倒...😇
『一箇所にまとめておけば、好きなときに見てもらえる仕組み』がほしい。</p>
<p>幸いImmichであれば複数アカウントが作成できる。アルバム機能もあり、アルバム事に権限管理も可。
親用のアカウントを作り、両親はアプリを開いてアルバムをタップすれば、愛孫のかわいい〜👶写真を眺めることができるのでは🤔</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/0b744df49c19a697/640.avif 640w, https://about.tsono.org/images/generated/0b744df49c19a697/960.avif 960w, https://about.tsono.org/images/generated/0b744df49c19a697/1125.avif 1125w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/0b744df49c19a697/640.webp 640w, https://about.tsono.org/images/generated/0b744df49c19a697/960.webp 960w, https://about.tsono.org/images/generated/0b744df49c19a697/1125.webp 1125w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/album.webp" alt="アルバム機能" width="1125" height="2436" loading="lazy" decoding="async"></picture>
<p>しかし、自宅ホストのサーバである以上、外部からの安全なアクセス手段が必要。</p>
<p>この課題を解決するために、 <code>Cloudflare Tunnel</code> を使う。</p>
<h3 id="cloudflare-tunnel--cloudflare-access"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#cloudflare-tunnel--cloudflare-access">Cloudflare Tunnel × Cloudflare Access</a></h3>
<p><a href="https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/">Cloudflare Tunnel</a>は、軽量ツール（<code>cloudflared</code>）をサーバに入れることで公開IPやポート開放なしに外部公開できるもの。通信はCloudflareを経由する。</p>
<p>2023年6月ごろに <a href="https://discord.com/channels/979116623879368755/1122615710846308484">Immich公式Discord</a> に「どうやってインターネットに公開するのがよいか？」という議論があり、一定数のユーザーが Cloudflare Tunnel を採用していると述べている。</p>
<p>更に、<code>Cloudflare Access</code> による認証を組み合わせれば限定公開も容易。</p>
<p>なお、100MB以上のファイルをアップロードする際には制限があるので注意が必要（今回は読み込みオンリーなので問題はなし）</p>
<h3 id="完成図cloudflare"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E5%AE%8C%E6%88%90%E5%9B%B3cloudflare">完成図（Cloudflare）</a></h3>
<figure class="diagram" data-diagram="mermaid"><span class="diagram-light"><svg id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light" width="100%" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 1708.5px;" viewBox="-40.5 -58.1 1708.5 1250.1" role="graphics-document document" aria-roledescription="flowchart-v2"><style>#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .error-icon{fill:#552222;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .error-text{fill:#552222;stroke:#552222;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .edge-thickness-normal{stroke-width:1px;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .edge-thickness-thick{stroke-width:3.5px;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .edge-pattern-solid{stroke-dasharray:0;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .marker{fill:#333333;stroke:#333333;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .marker.cross{stroke:#333333;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light p{margin:0;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .cluster-label text{fill:#333;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .cluster-label span{color:#333;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .cluster-label span p{background-color:transparent;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .label text,#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light span{fill:#333;color:#333;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .node rect,#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .node circle,#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .node ellipse,#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .node polygon,#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .rough-node .label text,#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .node .label text,#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .image-shape .label,#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .icon-shape .label{text-anchor:middle;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .rough-node .label,#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .node .label,#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .image-shape .label,#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .icon-shape .label{text-align:center;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .node.clickable{cursor:pointer;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .arrowheadPath{fill:#333333;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .edgePath .path{stroke:#333333;stroke-width:1px;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .flowchart-link{stroke:#333333;fill:none;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .cluster text{fill:#333;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .cluster span{color:#333;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light rect.text{fill:none;stroke-width:0;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .icon-shape,#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .icon-shape p,#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .icon-shape .label rect,#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light .node .neo-node{stroke:#9370DB;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light [data-look="neo"].node rect,#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light [data-look="neo"].cluster rect,#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light [data-look="neo"].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light [data-look="neo"].swimlane.cluster rect{filter:none;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light [data-look="neo"].node path{stroke:#9370DB;stroke-width:1px;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light [data-look="neo"].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light [data-look="neo"].node .neo-line path{stroke:#9370DB;filter:none;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light [data-look="neo"].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light [data-look="neo"].node circle .state-start{fill:#000000;}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light [data-look="neo"].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light [data-look="neo"].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointEnd-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="11.5" refY="7" markerUnits="userSpaceOnUse" markerWidth="10.5" markerHeight="14" orient="auto"><path d="M 0 0 L 11.5 7 L 0 14 z" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointStart-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="1" refY="7" markerUnits="userSpaceOnUse" markerWidth="11.5" markerHeight="14" orient="auto"><polygon points="0,7 11.5,14 11.5,0" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></polygon></marker><marker id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-circleEnd-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refY="5" refX="12.25" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-circleStart-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-2" refY="5" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-crossEnd-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="17.7" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5;"></path></marker><marker id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-crossStart-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="-3.5" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5; stroke-dasharray: 1,0;"></path></marker><g class="root"><g class="clusters"><g class="cluster" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-lan" data-look="classic"><rect style="" x="8" y="8" width="1620" height="832"></rect><g class="cluster-label" transform="translate(774, 8)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">LAN</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-hdds" data-look="classic"><rect style="" x="1039" y="386" width="564" height="192"></rect><g class="cluster-label" transform="translate(1256, 386)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">HDDケース</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-rapy" data-look="classic"><rect style="" x="33" y="316" width="616" height="504"></rect><g class="cluster-label" transform="translate(253, 316)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Raspberry</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> Pi</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 4</tspan></tspan></text></g></g></g></g><g class="edgePaths"><path d="M624,482L628.167,482C632.333,482,640.667,482,677.333,482C714,482,779,482,844,482C909,482,974,482,1010,482C1046,482,1053,482,1056.5,482L1060,482" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-L_immich-server_hdd1_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-61a54a4c8bf42787-light--L_immich-server_hdd1_0" data-points="W3sieCI6NjI0LCJ5Ijo0ODJ9LHsieCI6NjQ5LCJ5Ijo0ODJ9LHsieCI6ODQ0LCJ5Ijo0ODJ9LHsieCI6MTAzOSwieSI6NDgyfSx7IngiOjEwNjQsInkiOjQ4Mn1d" data-look="classic" marker-end="url(#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointEnd)"></path><path d="M1188,482L1210.167,482C1232.333,482,1276.667,482,1320.333,482C1364,482,1407,482,1428.5,482L1450,482" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-L_hdd1_hdd2_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-61a54a4c8bf42787-light--L_hdd1_hdd2_0" data-points="W3sieCI6MTE4OCwieSI6NDgyfSx7IngiOjEzMjEsInkiOjQ4Mn0seyJ4IjoxNDU0LCJ5Ijo0ODJ9XQ==" data-look="classic" marker-end="url(#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointEnd)"></path><path d="M158.501,140.173L188.918,179.811C219.334,219.449,280.167,298.724,336.48,350.549C392.794,402.373,444.587,426.747,470.484,438.934L496.381,451.12" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-L_mobile_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-61a54a4c8bf42787-light--L_mobile_in_lan_immich-server_0" data-points="W3sieCI6MTU2LjA2NTk3MjIyMjIyMjIzLCJ5IjoxMzd9LHsieCI6MzQxLCJ5IjozNzh9LHsieCI6NTAwLCJ5Ijo0NTIuODIzNTI5NDExNzY0N31d" data-look="classic" marker-start="url(#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointEnd)"></path><path d="M164.544,283.986L193.954,316.989C223.363,349.991,282.181,415.995,337.424,448.998C392.667,482,444.333,482,470.167,482L496,482" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-L_web_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-61a54a4c8bf42787-light--L_web_in_lan_immich-server_0" data-points="W3sieCI6MTYxLjg4MzA2NDUxNjEyOTAyLCJ5IjoyODF9LHsieCI6MzQxLCJ5Ijo0ODJ9LHsieCI6NTAwLCJ5Ijo0ODJ9XQ==" data-look="classic" marker-start="url(#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointEnd)"></path><path d="M185.767,641.491L211.639,632.242C237.511,622.994,289.256,604.497,341.025,583.062C392.794,561.627,444.587,537.253,470.484,525.066L496.381,512.88" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-L_cloudflared_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-61a54a4c8bf42787-light--L_cloudflared_immich-server_0" data-points="W3sieCI6MTgyLCJ5Ijo2NDIuODM3MTA0MDcyMzk4Mn0seyJ4IjozNDEsInkiOjU4Nn0seyJ4Ijo1MDAsInkiOjUxMS4xNzY0NzA1ODgyMzUzfV0=" data-look="classic" marker-start="url(#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointEnd)"></path><path d="M185.865,682.584L211.721,689.486C237.576,696.389,289.288,710.195,345.968,760.056C402.648,809.917,464.296,895.833,495.12,938.792L525.944,981.75" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-L_cloudflared_cloudflare_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style="stroke:#008080;stroke-width:3px;fill:none;;;stroke:#008080;stroke-width:3px;fill:none" data-edge="true" data-et="edge" data-id="mermaid-61a54a4c8bf42787-light--L_cloudflared_cloudflare_0" data-points="W3sieCI6MTgyLCJ5Ijo2ODEuNTUyMDM2MTk5MDk1fSx7IngiOjM0MSwieSI6NzI0fSx7IngiOjUyOC4yNzU5NzQwMjU5NzQsInkiOjk4NX1d" data-look="classic" marker-start="url(#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointStart__008080)" marker-end="url(#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointEnd__008080)"></path><path d="M607.28,982.036L614.233,974.363C621.187,966.691,635.093,951.345,674.547,943.673C714,936,779,936,844,936C909,936,974,936,1010,936C1046,936,1053,936,1056.5,936L1060,936" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-L_cloudflare_mobile_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style="stroke:#008080;stroke-width:3px;fill:none;;;stroke:#008080;stroke-width:3px;fill:none" data-edge="true" data-et="edge" data-id="mermaid-61a54a4c8bf42787-light--L_cloudflare_mobile_0" data-points="W3sieCI6NjA0LjU5Mzc1LCJ5Ijo5ODV9LHsieCI6NjQ5LCJ5Ijo5MzZ9LHsieCI6ODQ0LCJ5Ijo5MzZ9LHsieCI6MTAzOSwieSI6OTM2fSx7IngiOjEwNjQsInkiOjkzNn1d" data-look="classic" marker-start="url(#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointStart__008080)" marker-end="url(#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointEnd__008080)"></path><path d="M618.815,1081.632L623.846,1086.026C628.877,1090.421,638.938,1099.211,676.469,1103.605C714,1108,779,1108,844,1108C909,1108,974,1108,1010,1108C1046,1108,1053,1108,1056.5,1108L1060,1108" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-L_cloudflare_web_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style="stroke:#008080;stroke-width:3px;fill:none;;;stroke:#008080;stroke-width:3px;fill:none" data-edge="true" data-et="edge" data-id="mermaid-61a54a4c8bf42787-light--L_cloudflare_web_0" data-points="W3sieCI6NjE1LjgwMjYzMTU3ODk0NzQsInkiOjEwNzl9LHsieCI6NjQ5LCJ5IjoxMTA4fSx7IngiOjg0NCwieSI6MTEwOH0seyJ4IjoxMDM5LCJ5IjoxMTA4fSx7IngiOjEwNjQsInkiOjExMDh9XQ==" data-look="classic" marker-start="url(#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointStart__008080)" marker-end="url(#mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointEnd__008080)"></path></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(844, 482)"><g class="label" data-id="mermaid-61a54a4c8bf42787-light--L_immich-server_hdd1_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-68" y="-60.1" width="136" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">DB</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> /</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 写真</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(1321, 482)"><g class="label" data-id="mermaid-61a54a4c8bf42787-light--L_hdd1_hdd2_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-76" y="-60.1" width="152" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">バックアップ</tspan></tspan></text></g></g></g><g class="edgeLabel"><g class="label" data-id="mermaid-61a54a4c8bf42787-light--L_mobile_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g><g class="edgeLabel"><g class="label" data-id="mermaid-61a54a4c8bf42787-light--L_web_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g><g class="edgeLabel"><g class="label" data-id="mermaid-61a54a4c8bf42787-light--L_cloudflared_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g><g class="edgeLabel" transform="translate(386.66759, 787.64532)"><g class="label" data-id="mermaid-61a54a4c8bf42787-light--L_cloudflared_cloudflare_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-102" y="-60.1" width="204" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Cloudflare</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> Tunnel</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(844, 936)"><g class="label" data-id="mermaid-61a54a4c8bf42787-light--L_cloudflare_mobile_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-90" y="-60.1" width="180" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">サービストークン</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(844, 1108)"><g class="label" data-id="mermaid-61a54a4c8bf42787-light--L_cloudflare_web_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-138" y="-60.1" width="276" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">ワンタイムパスワード</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> /</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">SSO認証</tspan></tspan></text></g></g></g></g><g class="nodes"><g class="node default" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-flowchart-immich-server-0" data-look="classic" transform="translate(562, 482)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>immich-server</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-flowchart-cloudflared-1" data-look="classic" transform="translate(120, 665)"><rect class="basic label-container" style="stroke:#008080 !important;stroke-width:3px !important" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>cloudflared</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-flowchart-hdd1-2" data-look="classic" transform="translate(1126, 482)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>HDD 1</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-flowchart-hdd2-3" data-look="classic" transform="translate(1516, 482)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>HDD 2</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-flowchart-web_in_lan-4" data-look="classic" transform="translate(120, 234)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Web App</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-flowchart-mobile_in_lan-5" data-look="classic" transform="translate(120, 90)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Mobile App</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-flowchart-cloudflare-17" data-look="classic" transform="translate(562, 1032)"><rect class="basic label-container" style="stroke:#008080 !important;stroke-width:3px !important" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Cloudflare</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-flowchart-mobile-19" data-look="classic" transform="translate(1126, 936)"><rect class="basic label-container" style="stroke:#008080 !important;stroke-width:3px !important" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Mobile App</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-flowchart-web-21" data-look="classic" transform="translate(1126, 1108)"><rect class="basic label-container" style="stroke:#008080 !important;stroke-width:3px !important" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Web App</p></span></div></foreignObject></g></g></g></g><marker id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointStart__008080" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;" stroke="#008080" fill="#008080"></path></marker><marker id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light_flowchart-v2-pointEnd__008080" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;" stroke="#008080" fill="#008080"></path></marker></g><defs><filter id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-drop-shadow" height="130%" width="130%"><fedropshadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs><defs><filter id="mermaid-61a54a4c8bf42787-light--mermaid-61a54a4c8bf42787-light-drop-shadow-small" height="150%" width="150%"><fedropshadow dx="2" dy="2" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs></svg></span></figure>
<h3 id="cloudflare-registry-でドメインを取得する"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#cloudflare-registry-%E3%81%A7%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B">Cloudflare Registry でドメインを取得する</a></h3>
<p>Cloudflareにサインアップし、<a href="https://dash.cloudflare.com/login">ダッシュボード</a>から <code>ドメインの登録 > ドメイン登録</code> に遷移して任意のドメインを取得。
（取得しなくてもいい）</p>
<h3 id="tunnelの作成"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#tunnel%E3%81%AE%E4%BD%9C%E6%88%90">tunnelの作成</a></h3>
<p>ドメインの購入が完了したらトンネルを作成。</p>
<h4 id="手順"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E6%89%8B%E9%A0%86">手順</a></h4>
<ol>
<li><code>ダッシュボード</code></li>
<li><code>サイドメニュー</code></li>
<li><code>Zero Trust</code></li>
<li><code>ネットワーク</code></li>
<li><code>Tunnels</code></li>
<li><code>トンネルを作成する</code></li>
</ol>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/bb422e88d5ffb1b4/640.avif 640w, https://about.tsono.org/images/generated/bb422e88d5ffb1b4/960.avif 960w, https://about.tsono.org/images/generated/bb422e88d5ffb1b4/1280.avif 1280w, https://about.tsono.org/images/generated/bb422e88d5ffb1b4/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/bb422e88d5ffb1b4/640.webp 640w, https://about.tsono.org/images/generated/bb422e88d5ffb1b4/960.webp 960w, https://about.tsono.org/images/generated/bb422e88d5ffb1b4/1280.webp 1280w, https://about.tsono.org/images/generated/bb422e88d5ffb1b4/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/cloudflare_zero.webp" alt="Cloudflare Zero Trustの管理画面" width="1600" height="871" loading="lazy" decoding="async"></picture>
<ol>
<li><code>Cloudflaredを選択する</code></li>
<li><code>任意の名前をつけて保存</code></li>
<li><code>次へ</code></li>
</ol>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/f389aa2bb662c7e1/640.avif 640w, https://about.tsono.org/images/generated/f389aa2bb662c7e1/960.avif 960w, https://about.tsono.org/images/generated/f389aa2bb662c7e1/1280.avif 1280w, https://about.tsono.org/images/generated/f389aa2bb662c7e1/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/f389aa2bb662c7e1/640.webp 640w, https://about.tsono.org/images/generated/f389aa2bb662c7e1/960.webp 960w, https://about.tsono.org/images/generated/f389aa2bb662c7e1/1280.webp 1280w, https://about.tsono.org/images/generated/f389aa2bb662c7e1/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/create_tunnel.webp" alt="トンネルの作成" width="1600" height="984" loading="lazy" decoding="async"></picture>
<p><code>Debian</code> を選択して、表示されるコマンドをサーバで実行。</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/f2ec3a7b7d8eca5a/640.avif 640w, https://about.tsono.org/images/generated/f2ec3a7b7d8eca5a/960.avif 960w, https://about.tsono.org/images/generated/f2ec3a7b7d8eca5a/1280.avif 1280w, https://about.tsono.org/images/generated/f2ec3a7b7d8eca5a/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/f2ec3a7b7d8eca5a/640.webp 640w, https://about.tsono.org/images/generated/f2ec3a7b7d8eca5a/960.webp 960w, https://about.tsono.org/images/generated/f2ec3a7b7d8eca5a/1280.webp 1280w, https://about.tsono.org/images/generated/f2ec3a7b7d8eca5a/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/connector.webp" alt="Cloudflare Tunnel コネクタのインストール・実行" width="1600" height="1026" loading="lazy" decoding="async"></picture>
<p>サーバ側でのコマンドが成功すると、このようにコネクタIDと接続済みステータスが表示されるので次へ押下</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/5bffdde228dd1947/640.avif 640w, https://about.tsono.org/images/generated/5bffdde228dd1947/960.avif 960w, https://about.tsono.org/images/generated/5bffdde228dd1947/1280.avif 1280w, https://about.tsono.org/images/generated/5bffdde228dd1947/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/5bffdde228dd1947/640.webp 640w, https://about.tsono.org/images/generated/5bffdde228dd1947/960.webp 960w, https://about.tsono.org/images/generated/5bffdde228dd1947/1280.webp 1280w, https://about.tsono.org/images/generated/5bffdde228dd1947/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/connector_created.png" alt="コネクタ接続完了" width="1600" height="348" loading="lazy" decoding="async"></picture>
<p>以下を入力して保存を押下</p>
<ul>
<li>サブドメイン: 任意の名前</li>
<li>ドメイン: Cloudflareで購入したドメインがプルダウンで表示されるため選択</li>
<li>サービス: HTTP</li>
<li>URL: localhost:2283</li>
</ul>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/25a31949f7ba0ef4/640.avif 640w, https://about.tsono.org/images/generated/25a31949f7ba0ef4/960.avif 960w, https://about.tsono.org/images/generated/25a31949f7ba0ef4/1280.avif 1280w, https://about.tsono.org/images/generated/25a31949f7ba0ef4/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/25a31949f7ba0ef4/640.webp 640w, https://about.tsono.org/images/generated/25a31949f7ba0ef4/960.webp 960w, https://about.tsono.org/images/generated/25a31949f7ba0ef4/1280.webp 1280w, https://about.tsono.org/images/generated/25a31949f7ba0ef4/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/public_host.png" alt="トンネルのパブリックホスト名を入力" width="1600" height="651" loading="lazy" decoding="async"></picture>
<p>これで、Cloudflare経由で外部公開できた。設定したURLを打ち込むことで、アクセス可能となっているはず。</p>
<h3 id="cloudflare-accessで認証機能を追加する"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#cloudflare-access%E3%81%A7%E8%AA%8D%E8%A8%BC%E6%A9%9F%E8%83%BD%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B">Cloudflare Accessで認証機能を追加する</a></h3>
<p>しかし、アクセス制限がついてなくて危険なので設定していく。</p>
<h4 id="webブラウザからの認証"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#web%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%8B%E3%82%89%E3%81%AE%E8%AA%8D%E8%A8%BC">Webブラウザからの認証</a></h4>
<figure class="diagram" data-diagram="mermaid"><span class="diagram-light"><svg id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light" width="100%" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 1708.5px;" viewBox="-40.5 -58.1 1708.5 1250.1" role="graphics-document document" aria-roledescription="flowchart-v2"><style>#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .error-icon{fill:#552222;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .error-text{fill:#552222;stroke:#552222;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .edge-thickness-normal{stroke-width:1px;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .edge-thickness-thick{stroke-width:3.5px;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .edge-pattern-solid{stroke-dasharray:0;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .marker{fill:#333333;stroke:#333333;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .marker.cross{stroke:#333333;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light p{margin:0;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .cluster-label text{fill:#333;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .cluster-label span{color:#333;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .cluster-label span p{background-color:transparent;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .label text,#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light span{fill:#333;color:#333;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .node rect,#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .node circle,#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .node ellipse,#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .node polygon,#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .rough-node .label text,#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .node .label text,#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .image-shape .label,#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .icon-shape .label{text-anchor:middle;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .rough-node .label,#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .node .label,#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .image-shape .label,#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .icon-shape .label{text-align:center;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .node.clickable{cursor:pointer;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .arrowheadPath{fill:#333333;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .edgePath .path{stroke:#333333;stroke-width:1px;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .flowchart-link{stroke:#333333;fill:none;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .cluster text{fill:#333;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .cluster span{color:#333;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light rect.text{fill:none;stroke-width:0;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .icon-shape,#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .icon-shape p,#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .icon-shape .label rect,#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light .node .neo-node{stroke:#9370DB;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light [data-look="neo"].node rect,#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light [data-look="neo"].cluster rect,#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light [data-look="neo"].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light [data-look="neo"].swimlane.cluster rect{filter:none;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light [data-look="neo"].node path{stroke:#9370DB;stroke-width:1px;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light [data-look="neo"].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light [data-look="neo"].node .neo-line path{stroke:#9370DB;filter:none;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light [data-look="neo"].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light [data-look="neo"].node circle .state-start{fill:#000000;}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light [data-look="neo"].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light [data-look="neo"].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointEnd-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="11.5" refY="7" markerUnits="userSpaceOnUse" markerWidth="10.5" markerHeight="14" orient="auto"><path d="M 0 0 L 11.5 7 L 0 14 z" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointStart-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="1" refY="7" markerUnits="userSpaceOnUse" markerWidth="11.5" markerHeight="14" orient="auto"><polygon points="0,7 11.5,14 11.5,0" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></polygon></marker><marker id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-circleEnd-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refY="5" refX="12.25" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-circleStart-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-2" refY="5" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-crossEnd-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="17.7" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5;"></path></marker><marker id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-crossStart-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="-3.5" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5; stroke-dasharray: 1,0;"></path></marker><g class="root"><g class="clusters"><g class="cluster" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-lan" data-look="classic"><rect style="" x="8" y="8" width="1620" height="832"></rect><g class="cluster-label" transform="translate(774, 8)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">LAN</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-hdds" data-look="classic"><rect style="" x="1039" y="386" width="564" height="192"></rect><g class="cluster-label" transform="translate(1256, 386)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">HDDケース</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-rapy" data-look="classic"><rect style="" x="33" y="316" width="616" height="504"></rect><g class="cluster-label" transform="translate(253, 316)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Raspberry</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> Pi</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 4</tspan></tspan></text></g></g></g></g><g class="edgePaths"><path d="M624,482L628.167,482C632.333,482,640.667,482,677.333,482C714,482,779,482,844,482C909,482,974,482,1010,482C1046,482,1053,482,1056.5,482L1060,482" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-L_immich-server_hdd1_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-8dd73a371df38e0b-light--L_immich-server_hdd1_0" data-points="W3sieCI6NjI0LCJ5Ijo0ODJ9LHsieCI6NjQ5LCJ5Ijo0ODJ9LHsieCI6ODQ0LCJ5Ijo0ODJ9LHsieCI6MTAzOSwieSI6NDgyfSx7IngiOjEwNjQsInkiOjQ4Mn1d" data-look="classic" marker-end="url(#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointEnd)"></path><path d="M1188,482L1210.167,482C1232.333,482,1276.667,482,1320.333,482C1364,482,1407,482,1428.5,482L1450,482" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-L_hdd1_hdd2_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-8dd73a371df38e0b-light--L_hdd1_hdd2_0" data-points="W3sieCI6MTE4OCwieSI6NDgyfSx7IngiOjEzMjEsInkiOjQ4Mn0seyJ4IjoxNDU0LCJ5Ijo0ODJ9XQ==" data-look="classic" marker-end="url(#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointEnd)"></path><path d="M158.501,140.173L188.918,179.811C219.334,219.449,280.167,298.724,336.48,350.549C392.794,402.373,444.587,426.747,470.484,438.934L496.381,451.12" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-L_mobile_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-8dd73a371df38e0b-light--L_mobile_in_lan_immich-server_0" data-points="W3sieCI6MTU2LjA2NTk3MjIyMjIyMjIzLCJ5IjoxMzd9LHsieCI6MzQxLCJ5IjozNzh9LHsieCI6NTAwLCJ5Ijo0NTIuODIzNTI5NDExNzY0N31d" data-look="classic" marker-start="url(#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointEnd)"></path><path d="M164.544,283.986L193.954,316.989C223.363,349.991,282.181,415.995,337.424,448.998C392.667,482,444.333,482,470.167,482L496,482" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-L_web_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-8dd73a371df38e0b-light--L_web_in_lan_immich-server_0" data-points="W3sieCI6MTYxLjg4MzA2NDUxNjEyOTAyLCJ5IjoyODF9LHsieCI6MzQxLCJ5Ijo0ODJ9LHsieCI6NTAwLCJ5Ijo0ODJ9XQ==" data-look="classic" marker-start="url(#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointEnd)"></path><path d="M185.767,641.491L211.639,632.242C237.511,622.994,289.256,604.497,341.025,583.062C392.794,561.627,444.587,537.253,470.484,525.066L496.381,512.88" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-L_cloudflared_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-8dd73a371df38e0b-light--L_cloudflared_immich-server_0" data-points="W3sieCI6MTgyLCJ5Ijo2NDIuODM3MTA0MDcyMzk4Mn0seyJ4IjozNDEsInkiOjU4Nn0seyJ4Ijo1MDAsInkiOjUxMS4xNzY0NzA1ODgyMzUzfV0=" data-look="classic" marker-start="url(#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointEnd)"></path><path d="M185.865,682.584L211.721,689.486C237.576,696.389,289.288,710.195,345.968,760.056C402.648,809.917,464.296,895.833,495.12,938.792L525.944,981.75" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-L_cloudflared_cloudflare_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style="stroke:#008080;stroke-width:3px;fill:none;;;stroke:#008080;stroke-width:3px;fill:none" data-edge="true" data-et="edge" data-id="mermaid-8dd73a371df38e0b-light--L_cloudflared_cloudflare_0" data-points="W3sieCI6MTgyLCJ5Ijo2ODEuNTUyMDM2MTk5MDk1fSx7IngiOjM0MSwieSI6NzI0fSx7IngiOjUyOC4yNzU5NzQwMjU5NzQsInkiOjk4NX1d" data-look="classic" marker-start="url(#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointStart__008080)" marker-end="url(#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointEnd__008080)"></path><path d="M607.28,982.036L614.233,974.363C621.187,966.691,635.093,951.345,674.547,943.673C714,936,779,936,844,936C909,936,974,936,1010,936C1046,936,1053,936,1056.5,936L1060,936" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-L_cloudflare_mobile_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-8dd73a371df38e0b-light--L_cloudflare_mobile_0" data-points="W3sieCI6NjA0LjU5Mzc1LCJ5Ijo5ODV9LHsieCI6NjQ5LCJ5Ijo5MzZ9LHsieCI6ODQ0LCJ5Ijo5MzZ9LHsieCI6MTAzOSwieSI6OTM2fSx7IngiOjEwNjQsInkiOjkzNn1d" data-look="classic" marker-start="url(#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointEnd)"></path><path d="M618.815,1081.632L623.846,1086.026C628.877,1090.421,638.938,1099.211,676.469,1103.605C714,1108,779,1108,844,1108C909,1108,974,1108,1010,1108C1046,1108,1053,1108,1056.5,1108L1060,1108" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-L_cloudflare_web_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style="stroke:#008080;stroke-width:3px;fill:none;;;stroke:#008080;stroke-width:3px;fill:none" data-edge="true" data-et="edge" data-id="mermaid-8dd73a371df38e0b-light--L_cloudflare_web_0" data-points="W3sieCI6NjE1LjgwMjYzMTU3ODk0NzQsInkiOjEwNzl9LHsieCI6NjQ5LCJ5IjoxMTA4fSx7IngiOjg0NCwieSI6MTEwOH0seyJ4IjoxMDM5LCJ5IjoxMTA4fSx7IngiOjEwNjQsInkiOjExMDh9XQ==" data-look="classic" marker-start="url(#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointStart__008080)" marker-end="url(#mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointEnd__008080)"></path></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(844, 482)"><g class="label" data-id="mermaid-8dd73a371df38e0b-light--L_immich-server_hdd1_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-68" y="-60.1" width="136" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">DB</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> /</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 写真</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(1321, 482)"><g class="label" data-id="mermaid-8dd73a371df38e0b-light--L_hdd1_hdd2_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-76" y="-60.1" width="152" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">バックアップ</tspan></tspan></text></g></g></g><g class="edgeLabel"><g class="label" data-id="mermaid-8dd73a371df38e0b-light--L_mobile_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g><g class="edgeLabel"><g class="label" data-id="mermaid-8dd73a371df38e0b-light--L_web_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g><g class="edgeLabel"><g class="label" data-id="mermaid-8dd73a371df38e0b-light--L_cloudflared_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g><g class="edgeLabel" transform="translate(386.66759, 787.64532)"><g class="label" data-id="mermaid-8dd73a371df38e0b-light--L_cloudflared_cloudflare_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-102" y="-60.1" width="204" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Cloudflare</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> Tunnel</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(844, 936)"><g class="label" data-id="mermaid-8dd73a371df38e0b-light--L_cloudflare_mobile_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-90" y="-60.1" width="180" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">サービストークン</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(844, 1108)"><g class="label" data-id="mermaid-8dd73a371df38e0b-light--L_cloudflare_web_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-138" y="-60.1" width="276" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">ワンタイムパスワード</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> /</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">SSO認証</tspan></tspan></text></g></g></g></g><g class="nodes"><g class="node default" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-flowchart-immich-server-0" data-look="classic" transform="translate(562, 482)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>immich-server</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-flowchart-cloudflared-1" data-look="classic" transform="translate(120, 665)"><rect class="basic label-container" style="fill:#008080 !important;stroke:#008080 !important;stroke-width:3px !important" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="color:white !important" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="color: white !important; display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span style="color:white !important" class="nodeLabel"><p>cloudflared</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-flowchart-hdd1-2" data-look="classic" transform="translate(1126, 482)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>HDD 1</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-flowchart-hdd2-3" data-look="classic" transform="translate(1516, 482)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>HDD 2</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-flowchart-web_in_lan-4" data-look="classic" transform="translate(120, 234)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Web App</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-flowchart-mobile_in_lan-5" data-look="classic" transform="translate(120, 90)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Mobile App</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-flowchart-cloudflare-17" data-look="classic" transform="translate(562, 1032)"><rect class="basic label-container" style="fill:#008080 !important;stroke:#008080 !important;stroke-width:3px !important" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="color:white !important" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="color: white !important; display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span style="color:white !important" class="nodeLabel"><p>Cloudflare</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-flowchart-mobile-19" data-look="classic" transform="translate(1126, 936)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Mobile App</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-flowchart-web-21" data-look="classic" transform="translate(1126, 1108)"><rect class="basic label-container" style="fill:#008080 !important;stroke:#008080 !important;stroke-width:3px !important" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="color:white !important" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="color: white !important; display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span style="color:white !important" class="nodeLabel"><p>Web App</p></span></div></foreignObject></g></g></g></g><marker id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointStart__008080" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;" stroke="#008080" fill="#008080"></path></marker><marker id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light_flowchart-v2-pointEnd__008080" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;" stroke="#008080" fill="#008080"></path></marker></g><defs><filter id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-drop-shadow" height="130%" width="130%"><fedropshadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs><defs><filter id="mermaid-8dd73a371df38e0b-light--mermaid-8dd73a371df38e0b-light-drop-shadow-small" height="150%" width="150%"><fedropshadow dx="2" dy="2" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs></svg></span></figure>
<p>まずはLAN外からブラウザで Immich へアクセスしたときに、Email認証ができるようにを設定。</p>
<p>ポリシーの追加画面に移動</p>
<ol>
<li><code>Access</code></li>
<li><code>ポリシー</code></li>
<li><code>ポリシーを追加する</code></li>
</ol>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/2c4b0f7ee84e4dea/640.avif 640w, https://about.tsono.org/images/generated/2c4b0f7ee84e4dea/960.avif 960w, https://about.tsono.org/images/generated/2c4b0f7ee84e4dea/1280.avif 1280w, https://about.tsono.org/images/generated/2c4b0f7ee84e4dea/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/2c4b0f7ee84e4dea/640.webp 640w, https://about.tsono.org/images/generated/2c4b0f7ee84e4dea/960.webp 960w, https://about.tsono.org/images/generated/2c4b0f7ee84e4dea/1280.webp 1280w, https://about.tsono.org/images/generated/2c4b0f7ee84e4dea/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/policy.webp" alt="ポリシーの追加" width="1600" height="664" loading="lazy" decoding="async"></picture>
<p>お次にポリシーを設定</p>
<ol>
<li>ポリシー名に任意の名前を設定</li>
<li>セレクターで Emails を選択</li>
<li>認証時にSSO対象となるメールアドレスを追加する</li>
<li>保存</li>
</ol>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/95d29e5de7811980/640.avif 640w, https://about.tsono.org/images/generated/95d29e5de7811980/960.avif 960w, https://about.tsono.org/images/generated/95d29e5de7811980/1280.avif 1280w, https://about.tsono.org/images/generated/95d29e5de7811980/1593.avif 1593w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/95d29e5de7811980/640.webp 640w, https://about.tsono.org/images/generated/95d29e5de7811980/960.webp 960w, https://about.tsono.org/images/generated/95d29e5de7811980/1280.webp 1280w, https://about.tsono.org/images/generated/95d29e5de7811980/1593.webp 1593w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/add_policy.png" alt="ポリシーを追加" width="1593" height="704" loading="lazy" decoding="async"></picture>
<p>以下のように追加される</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/bdbbdbd92b38c293/640.avif 640w, https://about.tsono.org/images/generated/bdbbdbd92b38c293/960.avif 960w, https://about.tsono.org/images/generated/bdbbdbd92b38c293/979.avif 979w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/bdbbdbd92b38c293/640.webp 640w, https://about.tsono.org/images/generated/bdbbdbd92b38c293/960.webp 960w, https://about.tsono.org/images/generated/bdbbdbd92b38c293/979.webp 979w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/created_policy.png" alt="作成されたポリシー" width="979" height="484" loading="lazy" decoding="async"></picture>
<p>続いて、作成したポリシーをアプリケーションに設定する。</p>
<ol>
<li><code>Access</code></li>
<li><code>アプリケーション</code></li>
<li><code>アプリケーションを追加する</code></li>
</ol>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/0005cfeffbe2b12d/640.avif 640w, https://about.tsono.org/images/generated/0005cfeffbe2b12d/960.avif 960w, https://about.tsono.org/images/generated/0005cfeffbe2b12d/1261.avif 1261w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/0005cfeffbe2b12d/640.webp 640w, https://about.tsono.org/images/generated/0005cfeffbe2b12d/960.webp 960w, https://about.tsono.org/images/generated/0005cfeffbe2b12d/1261.webp 1261w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/add_app.png" alt="アプリケーションの追加" width="1261" height="409" loading="lazy" decoding="async"></picture>
<p>次にアプリケーションの種類を選ぶ</p>
<ol>
<li><code>セルフホスト</code></li>
<li><code>選択する</code></li>
</ol>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/7a21ad6243f4e07f/640.avif 640w, https://about.tsono.org/images/generated/7a21ad6243f4e07f/810.avif 810w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/7a21ad6243f4e07f/640.webp 640w, https://about.tsono.org/images/generated/7a21ad6243f4e07f/810.webp 810w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/app_self_host.png" alt="アプリケーションの種類を選択" width="810" height="758" loading="lazy" decoding="async"></picture>
<p>アプリケーションの情報を入力</p>
<ol>
<li>任意のアプリケーション名を追加</li>
<li>パブリックホスト名を追加をクリック > パブリックホストの入力欄が出てくる</li>
<li>サブドメイン・ドメインは先程のTunnelと同様のものを入力</li>
<li>Access ポリシー欄で、 <code>既存のポリシーを選択</code> を押下</li>
</ol>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/a9cb80ea89d0a867/640.avif 640w, https://about.tsono.org/images/generated/a9cb80ea89d0a867/960.avif 960w, https://about.tsono.org/images/generated/a9cb80ea89d0a867/1280.avif 1280w, https://about.tsono.org/images/generated/a9cb80ea89d0a867/1582.avif 1582w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/a9cb80ea89d0a867/640.webp 640w, https://about.tsono.org/images/generated/a9cb80ea89d0a867/960.webp 960w, https://about.tsono.org/images/generated/a9cb80ea89d0a867/1280.webp 1280w, https://about.tsono.org/images/generated/a9cb80ea89d0a867/1582.webp 1582w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/add_app_info.webp" alt="アプリケーション情報の入力画面" width="1582" height="832" loading="lazy" decoding="async"></picture>
<ol>
<li>先ほど作成したポリシーがでてくるのでチェックして確認</li>
<li>次へ で進んでいくと、保存ボタンが出てくるので保存</li>
</ol>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/46fcc15ecf6278e5/640.avif 640w, https://about.tsono.org/images/generated/46fcc15ecf6278e5/869.avif 869w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/46fcc15ecf6278e5/640.webp 640w, https://about.tsono.org/images/generated/46fcc15ecf6278e5/869.webp 869w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/add_app_policy.png" alt="作済みのポリシーが表示される" width="869" height="307" loading="lazy" decoding="async"></picture>
<p>以上。再び、設定したURLにブラウザでアクセスしてみると、SSO認証画面が表示されるはず</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/8d1f33b1ec49026a/640.avif 640w, https://about.tsono.org/images/generated/8d1f33b1ec49026a/674.avif 674w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/8d1f33b1ec49026a/640.webp 640w, https://about.tsono.org/images/generated/8d1f33b1ec49026a/674.webp 674w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/web_auth.png" alt="Cloudflareの認証画面" width="674" height="916" loading="lazy" decoding="async"></picture>
<p>ポリシーに追加した Email を入力すればメールが届き、メールに書いてあるパスコードを入力することで認証を突破できる。突破後はImmichのログイン画面に遷移する。（画像ではGoogle のOAuthでも認証できるようにしている）</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/89cbac69a95c03bf/640.avif 640w, https://about.tsono.org/images/generated/89cbac69a95c03bf/653.avif 653w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/89cbac69a95c03bf/640.webp 640w, https://about.tsono.org/images/generated/89cbac69a95c03bf/653.webp 653w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/web_one_time_code.png" alt="パスコード入力画面" width="653" height="486" loading="lazy" decoding="async"></picture>
<h4 id="モバイルアプリからの認証"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E3%83%A2%E3%83%90%E3%82%A4%E3%83%AB%E3%82%A2%E3%83%97%E3%83%AA%E3%81%8B%E3%82%89%E3%81%AE%E8%AA%8D%E8%A8%BC">モバイルアプリからの認証</a></h4>
<figure class="diagram" data-diagram="mermaid"><span class="diagram-light"><svg id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light" width="100%" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 1708.5px;" viewBox="-40.5 -58.1 1708.5 1250.1" role="graphics-document document" aria-roledescription="flowchart-v2"><style>#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .error-icon{fill:#552222;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .error-text{fill:#552222;stroke:#552222;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .edge-thickness-normal{stroke-width:1px;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .edge-thickness-thick{stroke-width:3.5px;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .edge-pattern-solid{stroke-dasharray:0;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .marker{fill:#333333;stroke:#333333;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .marker.cross{stroke:#333333;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light p{margin:0;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .cluster-label text{fill:#333;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .cluster-label span{color:#333;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .cluster-label span p{background-color:transparent;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .label text,#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light span{fill:#333;color:#333;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .node rect,#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .node circle,#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .node ellipse,#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .node polygon,#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .rough-node .label text,#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .node .label text,#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .image-shape .label,#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .icon-shape .label{text-anchor:middle;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .rough-node .label,#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .node .label,#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .image-shape .label,#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .icon-shape .label{text-align:center;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .node.clickable{cursor:pointer;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .arrowheadPath{fill:#333333;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .edgePath .path{stroke:#333333;stroke-width:1px;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .flowchart-link{stroke:#333333;fill:none;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .cluster text{fill:#333;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .cluster span{color:#333;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light rect.text{fill:none;stroke-width:0;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .icon-shape,#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .icon-shape p,#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .icon-shape .label rect,#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light .node .neo-node{stroke:#9370DB;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light [data-look="neo"].node rect,#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light [data-look="neo"].cluster rect,#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light [data-look="neo"].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light [data-look="neo"].swimlane.cluster rect{filter:none;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light [data-look="neo"].node path{stroke:#9370DB;stroke-width:1px;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light [data-look="neo"].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light [data-look="neo"].node .neo-line path{stroke:#9370DB;filter:none;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light [data-look="neo"].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light [data-look="neo"].node circle .state-start{fill:#000000;}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light [data-look="neo"].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light [data-look="neo"].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointEnd-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="11.5" refY="7" markerUnits="userSpaceOnUse" markerWidth="10.5" markerHeight="14" orient="auto"><path d="M 0 0 L 11.5 7 L 0 14 z" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointStart-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="1" refY="7" markerUnits="userSpaceOnUse" markerWidth="11.5" markerHeight="14" orient="auto"><polygon points="0,7 11.5,14 11.5,0" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></polygon></marker><marker id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-circleEnd-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refY="5" refX="12.25" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-circleStart-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-2" refY="5" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1,0;"></circle></marker><marker id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1,0;"></path></marker><marker id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-crossEnd-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="17.7" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5;"></path></marker><marker id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-crossStart-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="-3.5" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5; stroke-dasharray: 1,0;"></path></marker><g class="root"><g class="clusters"><g class="cluster" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-lan" data-look="classic"><rect style="" x="8" y="8" width="1620" height="832"></rect><g class="cluster-label" transform="translate(774, 8)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">LAN</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-hdds" data-look="classic"><rect style="" x="1039" y="386" width="564" height="192"></rect><g class="cluster-label" transform="translate(1256, 386)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">HDDケース</tspan></tspan></text></g></g></g><g class="cluster" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-rapy" data-look="classic"><rect style="" x="33" y="316" width="616" height="504"></rect><g class="cluster-label" transform="translate(253, 316)"><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Raspberry</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> Pi</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 4</tspan></tspan></text></g></g></g></g><g class="edgePaths"><path d="M624,482L628.167,482C632.333,482,640.667,482,677.333,482C714,482,779,482,844,482C909,482,974,482,1010,482C1046,482,1053,482,1056.5,482L1060,482" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-L_immich-server_hdd1_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-8789b2939ac6e257-light--L_immich-server_hdd1_0" data-points="W3sieCI6NjI0LCJ5Ijo0ODJ9LHsieCI6NjQ5LCJ5Ijo0ODJ9LHsieCI6ODQ0LCJ5Ijo0ODJ9LHsieCI6MTAzOSwieSI6NDgyfSx7IngiOjEwNjQsInkiOjQ4Mn1d" data-look="classic" marker-end="url(#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointEnd)"></path><path d="M1188,482L1210.167,482C1232.333,482,1276.667,482,1320.333,482C1364,482,1407,482,1428.5,482L1450,482" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-L_hdd1_hdd2_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-8789b2939ac6e257-light--L_hdd1_hdd2_0" data-points="W3sieCI6MTE4OCwieSI6NDgyfSx7IngiOjEzMjEsInkiOjQ4Mn0seyJ4IjoxNDU0LCJ5Ijo0ODJ9XQ==" data-look="classic" marker-end="url(#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointEnd)"></path><path d="M158.501,140.173L188.918,179.811C219.334,219.449,280.167,298.724,336.48,350.549C392.794,402.373,444.587,426.747,470.484,438.934L496.381,451.12" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-L_mobile_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-8789b2939ac6e257-light--L_mobile_in_lan_immich-server_0" data-points="W3sieCI6MTU2LjA2NTk3MjIyMjIyMjIzLCJ5IjoxMzd9LHsieCI6MzQxLCJ5IjozNzh9LHsieCI6NTAwLCJ5Ijo0NTIuODIzNTI5NDExNzY0N31d" data-look="classic" marker-start="url(#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointEnd)"></path><path d="M164.544,283.986L193.954,316.989C223.363,349.991,282.181,415.995,337.424,448.998C392.667,482,444.333,482,470.167,482L496,482" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-L_web_in_lan_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-8789b2939ac6e257-light--L_web_in_lan_immich-server_0" data-points="W3sieCI6MTYxLjg4MzA2NDUxNjEyOTAyLCJ5IjoyODF9LHsieCI6MzQxLCJ5Ijo0ODJ9LHsieCI6NTAwLCJ5Ijo0ODJ9XQ==" data-look="classic" marker-start="url(#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointEnd)"></path><path d="M185.767,641.491L211.639,632.242C237.511,622.994,289.256,604.497,341.025,583.062C392.794,561.627,444.587,537.253,470.484,525.066L496.381,512.88" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-L_cloudflared_immich-server_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-8789b2939ac6e257-light--L_cloudflared_immich-server_0" data-points="W3sieCI6MTgyLCJ5Ijo2NDIuODM3MTA0MDcyMzk4Mn0seyJ4IjozNDEsInkiOjU4Nn0seyJ4Ijo1MDAsInkiOjUxMS4xNzY0NzA1ODgyMzUzfV0=" data-look="classic" marker-start="url(#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointEnd)"></path><path d="M185.865,682.584L211.721,689.486C237.576,696.389,289.288,710.195,345.968,760.056C402.648,809.917,464.296,895.833,495.12,938.792L525.944,981.75" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-L_cloudflared_cloudflare_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style="stroke:#008080;stroke-width:3px;fill:none;;;stroke:#008080;stroke-width:3px;fill:none" data-edge="true" data-et="edge" data-id="mermaid-8789b2939ac6e257-light--L_cloudflared_cloudflare_0" data-points="W3sieCI6MTgyLCJ5Ijo2ODEuNTUyMDM2MTk5MDk1fSx7IngiOjM0MSwieSI6NzI0fSx7IngiOjUyOC4yNzU5NzQwMjU5NzQsInkiOjk4NX1d" data-look="classic" marker-start="url(#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointStart__008080)" marker-end="url(#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointEnd__008080)"></path><path d="M607.28,982.036L614.233,974.363C621.187,966.691,635.093,951.345,674.547,943.673C714,936,779,936,844,936C909,936,974,936,1010,936C1046,936,1053,936,1056.5,936L1060,936" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-L_cloudflare_mobile_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style="stroke:#008080;stroke-width:3px;fill:none;;;stroke:#008080;stroke-width:3px;fill:none" data-edge="true" data-et="edge" data-id="mermaid-8789b2939ac6e257-light--L_cloudflare_mobile_0" data-points="W3sieCI6NjA0LjU5Mzc1LCJ5Ijo5ODV9LHsieCI6NjQ5LCJ5Ijo5MzZ9LHsieCI6ODQ0LCJ5Ijo5MzZ9LHsieCI6MTAzOSwieSI6OTM2fSx7IngiOjEwNjQsInkiOjkzNn1d" data-look="classic" marker-start="url(#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointStart__008080)" marker-end="url(#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointEnd__008080)"></path><path d="M618.815,1081.632L623.846,1086.026C628.877,1090.421,638.938,1099.211,676.469,1103.605C714,1108,779,1108,844,1108C909,1108,974,1108,1010,1108C1046,1108,1053,1108,1056.5,1108L1060,1108" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-L_cloudflare_web_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="mermaid-8789b2939ac6e257-light--L_cloudflare_web_0" data-points="W3sieCI6NjE1LjgwMjYzMTU3ODk0NzQsInkiOjEwNzl9LHsieCI6NjQ5LCJ5IjoxMTA4fSx7IngiOjg0NCwieSI6MTEwOH0seyJ4IjoxMDM5LCJ5IjoxMTA4fSx7IngiOjEwNjQsInkiOjExMDh9XQ==" data-look="classic" marker-start="url(#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointStart)" marker-end="url(#mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointEnd)"></path></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(844, 482)"><g class="label" data-id="mermaid-8789b2939ac6e257-light--L_immich-server_hdd1_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-68" y="-60.1" width="136" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">DB</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> /</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> 写真</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(1321, 482)"><g class="label" data-id="mermaid-8789b2939ac6e257-light--L_hdd1_hdd2_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-76" y="-60.1" width="152" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">バックアップ</tspan></tspan></text></g></g></g><g class="edgeLabel"><g class="label" data-id="mermaid-8789b2939ac6e257-light--L_mobile_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g><g class="edgeLabel"><g class="label" data-id="mermaid-8789b2939ac6e257-light--L_web_in_lan_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g><g class="edgeLabel"><g class="label" data-id="mermaid-8789b2939ac6e257-light--L_cloudflared_immich-server_0" transform="translate(0, 16.1)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g><g class="edgeLabel" transform="translate(386.66759, 787.64532)"><g class="label" data-id="mermaid-8789b2939ac6e257-light--L_cloudflared_cloudflare_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-102" y="-60.1" width="204" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Cloudflare</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> Tunnel</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(844, 936)"><g class="label" data-id="mermaid-8789b2939ac6e257-light--L_cloudflare_mobile_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-90" y="-60.1" width="180" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">サービストークン</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(844, 1108)"><g class="label" data-id="mermaid-8789b2939ac6e257-light--L_cloudflare_web_0" transform="translate(0, 16.1)"><g><rect class="background" style="" x="-138" y="-60.1" width="276" height="88"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">ワンタイムパスワード</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> /</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">SSO認証</tspan></tspan></text></g></g></g></g><g class="nodes"><g class="node default" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-flowchart-immich-server-0" data-look="classic" transform="translate(562, 482)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>immich-server</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-flowchart-cloudflared-1" data-look="classic" transform="translate(120, 665)"><rect class="basic label-container" style="fill:#008080 !important;stroke:#008080 !important;stroke-width:3px !important" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="color:white !important" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="color: white !important; display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span style="color:white !important" class="nodeLabel"><p>cloudflared</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-flowchart-hdd1-2" data-look="classic" transform="translate(1126, 482)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>HDD 1</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-flowchart-hdd2-3" data-look="classic" transform="translate(1516, 482)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>HDD 2</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-flowchart-web_in_lan-4" data-look="classic" transform="translate(120, 234)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Web App</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-flowchart-mobile_in_lan-5" data-look="classic" transform="translate(120, 90)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Mobile App</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-flowchart-cloudflare-17" data-look="classic" transform="translate(562, 1032)"><rect class="basic label-container" style="fill:#008080 !important;stroke:#008080 !important;stroke-width:3px !important" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="color:white !important" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="color: white !important; display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span style="color:white !important" class="nodeLabel"><p>Cloudflare</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-flowchart-mobile-19" data-look="classic" transform="translate(1126, 936)"><rect class="basic label-container" style="fill:#008080 !important;stroke:#008080 !important;stroke-width:3px !important" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="color:white !important" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="color: white !important; display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span style="color:white !important" class="nodeLabel"><p>Mobile App</p></span></div></foreignObject></g></g><g class="node default" id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-flowchart-web-21" data-look="classic" transform="translate(1126, 1108)"><rect class="basic label-container" style="" x="-30" y="-15" width="60" height="30"></rect><g class="label" style="" transform="translate(0, 0)"><rect></rect><foreignObject width="0" height="0"><div style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"><p>Web App</p></span></div></foreignObject></g></g></g></g><marker id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointStart__008080" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;" stroke="#008080" fill="#008080"></path></marker><marker id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light_flowchart-v2-pointEnd__008080" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1,0;" stroke="#008080" fill="#008080"></path></marker></g><defs><filter id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-drop-shadow" height="130%" width="130%"><fedropshadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs><defs><filter id="mermaid-8789b2939ac6e257-light--mermaid-8789b2939ac6e257-light-drop-shadow-small" height="150%" width="150%"><fedropshadow dx="2" dy="2" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"></fedropshadow></filter></defs></svg></span></figure>
<p>次に、Immichモバイルアプリからアクセスする方法。モバイルアプリではブラウザのように認証画面に遷移できないため、そのままではログインできない。</p>
<p>そこで Cloudflareの <code>Service Token</code> と、Immichモバイルアプリの設定 <code>カスタムプロキシヘッダ設定</code> を活用する。</p>
<p><code>Service Token</code> は、アプリやプログラムから Cloudflare の制限されたリソースへとアクセスするための鍵。</p>
<p>Immich モバイルアプリには、サーバへアクセスする際のリクエストに任意の値を含めることができる <code>カスタムプロキシヘッダ</code> 設定があるため、こちらにトークンを設定することで認証を突破できる。</p>
<h4 id="cloudflare上の設定"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#cloudflare%E4%B8%8A%E3%81%AE%E8%A8%AD%E5%AE%9A">Cloudflare上の設定</a></h4>
<p>Service Token を作成する</p>
<ol>
<li><code>Cloudflare Zero Trustホーム</code></li>
<li><code>Access</code></li>
<li><code>サービス認証</code></li>
<li><code>サービストークンを作成する</code></li>
</ol>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/39623caa19ddf06d/640.avif 640w, https://about.tsono.org/images/generated/39623caa19ddf06d/960.avif 960w, https://about.tsono.org/images/generated/39623caa19ddf06d/1280.avif 1280w, https://about.tsono.org/images/generated/39623caa19ddf06d/1432.avif 1432w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/39623caa19ddf06d/640.webp 640w, https://about.tsono.org/images/generated/39623caa19ddf06d/960.webp 960w, https://about.tsono.org/images/generated/39623caa19ddf06d/1280.webp 1280w, https://about.tsono.org/images/generated/39623caa19ddf06d/1432.webp 1432w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/service_auth.png" alt="Service認証画面" width="1432" height="616" loading="lazy" decoding="async"></picture>
<ol>
<li>任意のトークン名を入力</li>
<li>任意の期限を入力</li>
<li>トークンを生成する</li>
</ol>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/5e3766b64282e010/640.avif 640w, https://about.tsono.org/images/generated/5e3766b64282e010/960.avif 960w, https://about.tsono.org/images/generated/5e3766b64282e010/1280.avif 1280w, https://about.tsono.org/images/generated/5e3766b64282e010/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/5e3766b64282e010/640.webp 640w, https://about.tsono.org/images/generated/5e3766b64282e010/960.webp 960w, https://about.tsono.org/images/generated/5e3766b64282e010/1280.webp 1280w, https://about.tsono.org/images/generated/5e3766b64282e010/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/add_service_token.png" alt="サービストークン作成画面" width="1600" height="442" loading="lazy" decoding="async"></picture>
<p><code>クライアントID</code> と <code>クライアントシークレット</code> が表示されるのでコピーしておく。</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/2c06e4396ef369b2/640.avif 640w, https://about.tsono.org/images/generated/2c06e4396ef369b2/960.avif 960w, https://about.tsono.org/images/generated/2c06e4396ef369b2/1280.avif 1280w, https://about.tsono.org/images/generated/2c06e4396ef369b2/1548.avif 1548w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/2c06e4396ef369b2/640.webp 640w, https://about.tsono.org/images/generated/2c06e4396ef369b2/960.webp 960w, https://about.tsono.org/images/generated/2c06e4396ef369b2/1280.webp 1280w, https://about.tsono.org/images/generated/2c06e4396ef369b2/1548.webp 1548w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/created_service_token.png" alt="生成されたトークン" width="1548" height="890" loading="lazy" decoding="async"></picture>
<p>次に、再びポリシーを作成。セレクターから Service Token を選び、先ほど作成したトークンをプルダウンから選択。</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/9f57d3136c8149ba/640.avif 640w, https://about.tsono.org/images/generated/9f57d3136c8149ba/960.avif 960w, https://about.tsono.org/images/generated/9f57d3136c8149ba/1280.avif 1280w, https://about.tsono.org/images/generated/9f57d3136c8149ba/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/9f57d3136c8149ba/640.webp 640w, https://about.tsono.org/images/generated/9f57d3136c8149ba/960.webp 960w, https://about.tsono.org/images/generated/9f57d3136c8149ba/1280.webp 1280w, https://about.tsono.org/images/generated/9f57d3136c8149ba/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/add_service_policy.webp" alt="セレクターでService Tokenを選択肢、値のフォームをクリックするとプルダウンで作成済みのサービス認証が表示される" width="1600" height="714" loading="lazy" decoding="async"></picture>
<p>ポリシーを保存し、先ほど作成したアプリケーションにこのポリシーを設定。</p>
<ol>
<li><code>Access</code></li>
<li><code>アプリケーション</code></li>
<li>作成したアプリケーション名の三点ドット</li>
<li><code>編集</code></li>
</ol>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/340a6b583a5d1483/640.avif 640w, https://about.tsono.org/images/generated/340a6b583a5d1483/960.avif 960w, https://about.tsono.org/images/generated/340a6b583a5d1483/1280.avif 1280w, https://about.tsono.org/images/generated/340a6b583a5d1483/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/340a6b583a5d1483/640.webp 640w, https://about.tsono.org/images/generated/340a6b583a5d1483/960.webp 960w, https://about.tsono.org/images/generated/340a6b583a5d1483/1280.webp 1280w, https://about.tsono.org/images/generated/340a6b583a5d1483/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/add_app_policy_service.webp" alt="add_app_policy_service.png" width="1600" height="668" loading="lazy" decoding="async"></picture>
<p>アプリケーションにポリシーを追加</p>
<ol>
<li><code>タグ: ポリシー</code></li>
<li><code>既存のポリシーを選択</code></li>
<li>作成した Service Tokenのポリシーを選択</li>
<li><code>確認</code></li>
<li><code>アプリケーションを保存</code></li>
</ol>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/334ff9e22caf4d42/640.avif 640w, https://about.tsono.org/images/generated/334ff9e22caf4d42/960.avif 960w, https://about.tsono.org/images/generated/334ff9e22caf4d42/1280.avif 1280w, https://about.tsono.org/images/generated/334ff9e22caf4d42/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/334ff9e22caf4d42/640.webp 640w, https://about.tsono.org/images/generated/334ff9e22caf4d42/960.webp 960w, https://about.tsono.org/images/generated/334ff9e22caf4d42/1280.webp 1280w, https://about.tsono.org/images/generated/334ff9e22caf4d42/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/select_policy.webp" alt="作成したポリシーが選択できる" width="1600" height="929" loading="lazy" decoding="async"></picture>
<p>これでCloudflare側の設定は完了。</p>
<h4 id="immich-モバイルアプリ上の設定"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#immich-%E3%83%A2%E3%83%90%E3%82%A4%E3%83%AB%E3%82%A2%E3%83%97%E3%83%AA%E4%B8%8A%E3%81%AE%E8%A8%AD%E5%AE%9A">Immich モバイルアプリ上の設定</a></h4>
<p>お次はImmichのモバイルアプリで、アクセス時にトークンを含めるように設定する。</p>
<ol>
<li>Immichモバイルアプリのログイン画面を開く</li>
<li>歯車マークをタップ</li>
<li>カスタムプロキシヘッダをタップ</li>
<li>プロキシヘッダに以下を入力します
<ol>
<li>生成したクライアントIDのヘッダーと値</li>
<li>クライアントシークレットのヘッダーと値</li>
</ol>
</li>
</ol>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/686ffa369919970c/640.avif 640w, https://about.tsono.org/images/generated/686ffa369919970c/960.avif 960w, https://about.tsono.org/images/generated/686ffa369919970c/1280.avif 1280w, https://about.tsono.org/images/generated/686ffa369919970c/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/686ffa369919970c/640.webp 640w, https://about.tsono.org/images/generated/686ffa369919970c/960.webp 960w, https://about.tsono.org/images/generated/686ffa369919970c/1280.webp 1280w, https://about.tsono.org/images/generated/686ffa369919970c/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/add_custom_proxy.webp" alt="カスタムプロキシヘッダの設定" width="1600" height="921" loading="lazy" decoding="async"></picture>
<p>以上。これで、Immichモバイルアプリから外部向けURLにアクセスしても認証を通過でき、作成済みアカウントでログインすれば写真を閲覧できる。</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/fc601026b1a0466c/640.avif 640w, https://about.tsono.org/images/generated/fc601026b1a0466c/960.avif 960w, https://about.tsono.org/images/generated/fc601026b1a0466c/1006.avif 1006w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/fc601026b1a0466c/640.webp 640w, https://about.tsono.org/images/generated/fc601026b1a0466c/960.webp 960w, https://about.tsono.org/images/generated/fc601026b1a0466c/1006.webp 1006w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/raspi-immich-home-photos/goal2-secure-sharing/login_immich_mobile.webp" alt="ドメインを打ち込めば、ログイン画面に遷移できる" width="1006" height="894" loading="lazy" decoding="async"></picture>
<p>つまり、以下の手順を4人分実施すれば、両親も自分のスマホから孫の写真を見られるようになる。</p>
<ol>
<li>Immichで両親のアカウントを作成する</li>
<li>両親のアカウントに、息子のアルバムへの閲覧権限を付与する</li>
<li>両親のスマホにモバイルアプリをダウンロードする</li>
<li>モバイルアプリでカスタムプロキシヘッダを設定</li>
<li>各自のアカウントでログイン</li>
</ol>
<h3 id="done️"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#done%EF%B8%8F">Done👍️</a></h3>
<p>これにて、</p>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" checked disabled> 遠隔地の家族に安全に写真をシェアする</li>
</ul>
<p>クリア。</p>
<h4 id="費用"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E8%B2%BB%E7%94%A8">費用</a></h4>









































<table><thead><tr><th>項目</th><th>単価</th><th>数量</th><th>小計</th></tr></thead><tbody><tr><td>Raspberry Pi 4 (8GB)</td><td>¥12,000</td><td>1</td><td>¥12,000</td></tr><tr><td>HDD 1TB</td><td>¥7,000</td><td>2</td><td>¥14,000</td></tr><tr><td>HDDケース（スタンド）</td><td>¥4,000</td><td>1</td><td>¥4,000</td></tr><tr><td>雑費（SD・ケーブル）</td><td>¥600</td><td>1</td><td>¥600</td></tr><tr><td>合計</td><td></td><td></td><td>¥30,600</td></tr></tbody></table>























<table><thead><tr><th>項目</th><th>単価</th><th>数量</th><th>小計</th></tr></thead><tbody><tr><td>ドメイン代</td><td>¥1,000</td><td>1</td><td>¥1,000</td></tr><tr><td>年額合計</td><td></td><td></td><td>¥1,000</td></tr></tbody></table>
<p>Google One (2TB) は ¥17,400/年。
初期費用はかかるものの、2年弱運用できればおとく...?</p>
<h4 id="メリット"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E3%83%A1%E3%83%AA%E3%83%83%E3%83%88">メリット</a></h4>
<ul>
<li>サブスク費用が不要（</li>
<li>HDD増設すれば容量は実質無限</li>
<li>おもしろい</li>
</ul>
<h4 id="デメリット"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E3%83%87%E3%83%A1%E3%83%AA%E3%83%83%E3%83%88">デメリット</a></h4>
<ul>
<li>初期構築の手間</li>
<li>HDDが壊れたときのリスクが大きい。クラウドと比べてリスク分散も難しい</li>
<li>Immich のアップデートが頻繁にある、破壊的な変更がたまにあるため、しっかり調べて対応しないといけない</li>
</ul>
<h4 id="今後の課題"><a href="https://about.tsono.org/articles/raspi-immich-home-photos#%E4%BB%8A%E5%BE%8C%E3%81%AE%E8%AA%B2%E9%A1%8C">今後の課題</a></h4>
<ul>
<li>もう一箇所バックアップを用意したい</li>
<li>週1のバックアップ用にもかかわらず、HDD2が常時接続＆回転しっぱなし。</li>
</ul>
<section data-footnotes="" class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes</h2>
<ol>
<li id="user-content-fn-fn:1">
<p><a href="https://www.backblaze.com/blog/the-3-2-1-backup-strategy/">3-2-1 backup strategy</a> に従うと、別の場所にもう1つバックアップを用意すべきでしょうね。 <a href="https://about.tsono.org/articles/raspi-immich-home-photos#user-content-fnref-fn:1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section><p><a href="https://about.tsono.org/articles/raspi-immich-home-photos">元の記事を読む</a></p>]]></content:encoded></item><item><title>Chromeでリロードをしてもコンソール・ネットワークログを保持する方法</title><link>https://about.tsono.org/articles/chrome-log-setting</link><guid isPermaLink="true">https://about.tsono.org/articles/chrome-log-setting</guid><pubDate>Thu, 07 Aug 2025 00:00:00 GMT</pubDate><description>Chromeの開発者ツールでコンソール・ネットワークを見てデバッグをする場合、ページのリロードによって履歴が消えてしまう。その対処法。</description><content:encoded><![CDATA[<p>Chromeの開発者ツールでコンソール・ネットワークを見てデバッグをする場合、ページのリロードによって履歴が消えてしまう。その対処法。</p>
<h2 id="コンソール"><a href="https://about.tsono.org/articles/chrome-log-setting#%E3%82%B3%E3%83%B3%E3%82%BD%E3%83%BC%E3%83%AB">コンソール</a></h2>
<ol>
<li>開発者ツール</li>
<li>歯車マーク(⚙️)</li>
<li>コンソール > 移動時にログを保持にチェック</li>
</ol>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/54f07ce0dc74dfc1/640.avif 640w, https://about.tsono.org/images/generated/54f07ce0dc74dfc1/960.avif 960w, https://about.tsono.org/images/generated/54f07ce0dc74dfc1/1280.avif 1280w, https://about.tsono.org/images/generated/54f07ce0dc74dfc1/1840.avif 1840w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/54f07ce0dc74dfc1/640.webp 640w, https://about.tsono.org/images/generated/54f07ce0dc74dfc1/960.webp 960w, https://about.tsono.org/images/generated/54f07ce0dc74dfc1/1280.webp 1280w, https://about.tsono.org/images/generated/54f07ce0dc74dfc1/1840.webp 1840w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/chrome-log-setting/console-preserve-log.png" alt="Chrome DevToolsの「移動時にログを保持」設定" width="1840" height="1400" loading="lazy" decoding="async"></picture>
<h2 id="ネットワーク"><a href="https://about.tsono.org/articles/chrome-log-setting#%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF">ネットワーク</a></h2>
<ol>
<li>開発者ツール</li>
<li>歯車マーク(⚙️)</li>
<li>ネットワーク > ログを保持にチェック</li>
</ol>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/0080c04865c702ab/640.avif 640w, https://about.tsono.org/images/generated/0080c04865c702ab/960.avif 960w, https://about.tsono.org/images/generated/0080c04865c702ab/1280.avif 1280w, https://about.tsono.org/images/generated/0080c04865c702ab/1842.avif 1842w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/0080c04865c702ab/640.webp 640w, https://about.tsono.org/images/generated/0080c04865c702ab/960.webp 960w, https://about.tsono.org/images/generated/0080c04865c702ab/1280.webp 1280w, https://about.tsono.org/images/generated/0080c04865c702ab/1842.webp 1842w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/chrome-log-setting/network-preserve-log.png" alt="Chrome DevToolsの「ログを保持」設定" width="1842" height="1116" loading="lazy" decoding="async"></picture><p><a href="https://about.tsono.org/articles/chrome-log-setting">元の記事を読む</a></p>]]></content:encoded></item><item><title>Bootstrap5で入れ子モーダルを実現する</title><link>https://about.tsono.org/articles/bootstrap5-nested-model</link><guid isPermaLink="true">https://about.tsono.org/articles/bootstrap5-nested-model</guid><pubDate>Sat, 19 Jul 2025 00:00:00 GMT</pubDate><description>Bootstrap5では公式にサポートされていない入れ子モーダルを作る</description><content:encoded><![CDATA[<p>ウェブアプリにおいて、ユーザーからの操作や情報入力を段階的に進めるために、複数のモーダルを重ねて表示したいケースがしばしば存在する。
しかし <code>Bootstrap5</code> では標準のモーダル機能として入れ子モーダルをサポートしていない。</p>
<p>公式でもUXの関係でサポートしていないと明示されており、モーダルから別のモーダルを呼び出すことは可能だが、元のモーダルは消えてしまう。</p>
<p><a href="https://getbootstrap.jp/docs/5.3/components/modal/#toggle-between-modals">Toggle between modals</a></p>
<h2 id="なぜ消えるか"><a href="https://about.tsono.org/articles/bootstrap5-nested-model#%E3%81%AA%E3%81%9C%E6%B6%88%E3%81%88%E3%82%8B%E3%81%8B">なぜ消えるか</a></h2>
<p>通常、Bootstrap5のモーダルはdata属性を用いて展開する。</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">&#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"btn btn-primary"</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> data-bs-target</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"#modalA"</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> data-bs-toggle</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">  Open second modal</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span></code></pre>
<p>このとき、<code>bootstrap.js</code> で呼ばれる処理の中に、すでに開いているモーダルがある場合は閉じる処理が入っているため、展開中のものは閉じられてしまう。</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">// avoid conflict when clicking modal toggler while another one is open</span></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">const</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> alreadyOpen</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> =</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> SelectorEngine.</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">findOne</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">OPEN_SELECTOR</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">)</span></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">if</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> (alreadyOpen) {</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">  Modal.</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">getInstance</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(alreadyOpen).</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">hide</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">()</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">}</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">const</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> data</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> =</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> Modal.</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">getOrCreateInstance</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(target)</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">data.</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">toggle</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">this</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">)</span></span></code></pre>
<p><a href="https://github.com/twbs/bootstrap/blob/86ffedb026636b803c7dd21cc0b804f37e7201cb/js/src/modal.js#L359">js/src/modal.js</a></p>
<p>そのため、data属性を用いたモーダル展開を使うことはできない。</p>
<h2 id="解決策"><a href="https://about.tsono.org/articles/bootstrap5-nested-model#%E8%A7%A3%E6%B1%BA%E7%AD%96">解決策</a></h2>
<p>代わりにモーダルインスタンスの <code>show()</code> メソッドを使う。</p>
<p><a href="https://github.com/twbs/bootstrap/blob/86ffedb026636b803c7dd21cc0b804f37e7201cb/js/src/modal.js#L98">js/src/modal.js</a></p>
<p><code>show()</code> には上述の処理は含まれてないため複数のモーダルを同時に表示できる。
あとはモーダルと背景となる <code>backdrop</code> の <code>z-index</code> を調整してうまく層を作ればいい。</p>
<h2 id="サンプル"><a href="https://about.tsono.org/articles/bootstrap5-nested-model#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB">サンプル</a></h2>
<p>以下は <code>jQuery</code> でモーダルの表示トリガーを監視し、モーダルの <code>z-index</code> と <code>backdrop</code> を管理することで入れ子モーダルを実装している。</p>
<h4 id="js"><a href="https://about.tsono.org/articles/bootstrap5-nested-model#js">js</a></h4>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line"><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">$</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">function</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> () {</span></span>
<span class="line"><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">  $</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(document).</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">on</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'click'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">, </span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'.show-modal'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">, </span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">function</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> () {</span></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">    const</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> nextId</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> =</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF"> $</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">this</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">).</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">data</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'show-modal'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">)</span></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">    if</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> (nextId) </span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">showModal</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(nextId)</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">  })</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">  function</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF"> showModal</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">modalId</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">) {</span></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">    const</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> newModal</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> =</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF"> $</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'#'</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> +</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> modalId)</span></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">    const</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> modalInstance</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> =</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> new</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> bootstrap.</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">Modal</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(newModal[</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">0</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">])</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">    modalInstance.</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">show</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">()</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">    _setupModalZIndex</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(newModal)</span></span>
<span class="line"><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">    _setupBackdrop</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(modalId)</span></span>
<span class="line"><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">    _cleanupModal</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(newModal, modalId)</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">  }</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">  /**</span></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">   * モーダルのz-indexを設定する</span></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">   * z-index = 1040 + 10 * 表示中のモーダル数（Bootstrap標準の重なり順に準拠）</span></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">   * ex: 1段目: 1040, 2段目: 1050, 3段目: 1060, ...</span></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">   */</span></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">  function</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF"> _setupModalZIndex</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">modal</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">) {</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">    modal.</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">one</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'shown.bs.modal'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">, </span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">function</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> () {</span></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">      const</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> modalCount</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> =</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF"> $</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'.modal.show'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">).</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">length</span></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">      const</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> zIndex</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> =</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> 1040</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> +</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> 10</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> *</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> modalCount</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      modal.</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">css</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'z-index'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">, zIndex)</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      modal.</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">data</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'zIndex'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">, zIndex) </span><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">// backdropで使うために保存しておく</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">    })</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">  }</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">  /**</span></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">   * モーダルbackdropのz-indexを調整する</span></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">   * ex: 1段目: 1039, 2段目: 1049, 3段目: 1059, ...</span></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">   */</span></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">  function</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF"> _setupBackdrop</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">modalId</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">) {</span></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">    // z-index の設定は shown.bs.modal の後でないと正しい数にならない</span></span>
<span class="line"><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">    $</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'#'</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> +</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> modalId).</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">one</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'shown.bs.modal'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">, </span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">function</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> () {</span></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">      const</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> modal</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> =</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF"> $</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">this</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">)</span></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">      const</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> zIndex</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> =</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> modal.</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">data</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'zIndex'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">)</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">      const</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> backdrop</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> =</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF"> $</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'.modal-backdrop'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">).</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">not</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'.modal-stack'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">).</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">last</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">()</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      backdrop</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        .</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">css</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'z-index'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">, zIndex </span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">-</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> 1</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">) </span><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">// モーダルより1つ下に配置</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        .</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">addClass</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'modal-stack'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">)</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        .</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">attr</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'data-backdrop-for'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">, modalId) </span><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">// 削除処理のためにモーダルIDで関連付け</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">    })</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">  }</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">  /**</span></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">   * モーダルが閉じられたとき（hidden.bs.modal）に、対応するbackdropを削除し、</span></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">   * フォーカスを親モーダルかbodyへ逃がす</span></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">   */</span></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">  function</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF"> _cleanupModal</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">modal</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">, </span><span style="--shiki-light:#702C00;--shiki-dark:#FFB757">modalId</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">) {</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">    modal.</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">one</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'hidden.bs.modal'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">, () </span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">=></span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> {</span></span>
<span class="line"><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">      $</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">`.modal-backdrop[data-backdrop-for="${</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">modalId</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">}"]`</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">).</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">remove</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">()</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">      const</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> openModals</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> =</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF"> $</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'.modal.show'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">)</span></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">      if</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> (openModals.</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">length</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> ></span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> 0</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">) {</span></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">        // 親モーダルにフォーカスを当てる</span></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">        const</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> lastModal</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> =</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> openModals.</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">last</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">()</span></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">        const</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> focusTarget</span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492"> =</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> lastModal</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">          .</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">find</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'[autofocus], .btn-close, .btn, input, select'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">)</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">          .</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">first</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">()</span></span>
<span class="line"><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">        if</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> (focusTarget.</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">length</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">) focusTarget.</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">trigger</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'focus'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">)</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      } </span><span style="--shiki-light:#A0111F;--shiki-dark:#FF9492">else</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6"> {</span></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">        // 最後のモーダルを閉じた場合、bodyにフォーカスを逃がす（アクセシビリティ対策）</span></span>
<span class="line"><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">        $</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(document.activeElement).</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">trigger</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'blur'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">)</span></span>
<span class="line"><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">        $</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'body'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">).</span><span style="--shiki-light:#622CBC;--shiki-dark:#DBB7FF">trigger</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">(</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">'focus'</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">)</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      }</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">    })</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">  }</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">})</span></span></code></pre>
<h4 id="html"><a href="https://about.tsono.org/articles/bootstrap5-nested-model#html">html</a></h4>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">&#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">link</span></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">  href</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"</span></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">  rel</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"stylesheet"</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">/></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">&#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">script</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> src</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"https://code.jquery.com/jquery-3.7.1.min.js"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">>&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">script</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">&#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">script</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> src</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">>&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">script</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">&#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"btn btn-primary show-modal"</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> data-show-modal</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal1"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">  Open Modal 1</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">&#x3C;!-- モーダル1 --></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">&#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal"</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> id</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal1"</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> tabindex</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"-1"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">  &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-dialog"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">    &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-content"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-header"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">h5</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-title"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">>Modal 1&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">h5</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">          type</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"button"</span></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">          class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"btn-close"</span></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">          data-bs-dismiss</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal"</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        >&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-body"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"btn btn-secondary show-modal"</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> data-show-modal</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal2"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">          Open Modal 2</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">    &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">  &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">&#x3C;!-- モーダル2 --></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">&#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal"</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> id</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal2"</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> tabindex</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"-1"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">  &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-dialog"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">    &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-content"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-header"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">h5</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-title"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">>Modal 2&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">h5</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">          type</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"button"</span></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">          class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"btn-close"</span></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">          data-bs-dismiss</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal"</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        >&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-body"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"btn btn-secondary show-modal"</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> data-show-modal</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal3"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">          Open Modal 3</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">    &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">  &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">&#x3C;!-- モーダル3 --></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">&#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal"</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> id</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal3"</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> tabindex</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"-1"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">  &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-dialog"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">    &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-content"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-header"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">h5</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-title"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">>Modal 3&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">h5</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">          type</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"button"</span></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">          class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"btn-close"</span></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">          data-bs-dismiss</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal"</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        >&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-body"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"btn btn-secondary show-modal"</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> data-show-modal</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal4"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">          Open Modal 4</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">    &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">  &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">&#x3C;!-- モーダル4 --></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">&#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal"</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> id</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal4"</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> tabindex</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"-1"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">  &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-dialog"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">    &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-content"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-header"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">h5</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-title"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">>Modal 4&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">h5</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">          type</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"button"</span></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">          class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"btn-close"</span></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">          data-bs-dismiss</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal"</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        >&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-body"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"btn btn-secondary show-modal"</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> data-show-modal</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal5"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">          Open Modal 5</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">    &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">  &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"></span>
<span class="line"><span style="--shiki-light:#66707B;--shiki-dark:#BDC4CC">&#x3C;!-- モーダル5 --></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">&#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal"</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> id</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal5"</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> tabindex</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"-1"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">  &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-dialog"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">    &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-content"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-header"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">h5</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-title"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">>Modal 5&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">h5</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">          type</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"button"</span></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">          class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"btn-close"</span></span>
<span class="line"><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF">          data-bs-dismiss</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal"</span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        >&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal-body"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">        &#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">p</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">>Last modal (5)&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">p</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">      &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">    &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">  &#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span>
<span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">div</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span></code></pre>
<p>モーダルからモーダルを開くたび、モーダルと <code>backdrop</code> の <code>z-index</code> を調整することで層を形成している。</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>      _______________</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>     /               /   Modal 4</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>    / z-index:1070  /</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>   /_______________/</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>------ -index:1069 ----- Backdrop 4</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>      _______________</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>     /               /   Modal 3</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>    / z-index:1060  /</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>   /_______________/</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>----- z-index:1059 ----- Backdrop 3</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>      _______________</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>     /               /    Modal 2</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>    / z-index:1050  /</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>   /_______________/</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>------ z-index:1049 ----- Backdrop 2</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span></span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>      _______________</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>     /               /    Modal 1</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>    / z-index:1040  /</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>   /_______________/</span></span>
<span class="line" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6"><span>------ z-index:1039 ----- Backdrop 1</span></span></code></pre>
<p>モーダルを呼び出すボタンには</p>
<ul>
<li><code>show-modal</code> クラス</li>
<li><code>data-show-modal="モーダルのID"</code></li>
</ul>
<p>をつける。 モーダル自体は通常の定義と変わらないため、使い心地にも違和感はない。</p>
<pre class="shiki shiki-themes github-light-high-contrast github-dark-high-contrast" style="--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10" tabindex="0"><code><span class="line"><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">&#x3C;</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> class</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"btn show-modal"</span><span style="--shiki-light:#023B95;--shiki-dark:#91CBFF"> data-show-modal</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">=</span><span style="--shiki-light:#032563;--shiki-dark:#ADDCFF">"modal1"</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">>Open Modal 1&#x3C;/</span><span style="--shiki-light:#024C1A;--shiki-dark:#72F088">button</span><span style="--shiki-light:#0E1116;--shiki-dark:#F0F3F6">></span></span></code></pre>
<h3 id="デモ"><a href="https://about.tsono.org/articles/bootstrap5-nested-model#%E3%83%87%E3%83%A2">デモ</a></h3>
<p><img src="https://about.tsono.org/images/articles/bootstrap5-nested-modal/modal.gif" alt="Bootstrap5の入れ子モーダルの動作デモ" width="1276" height="620" loading="lazy"></p><p><a href="https://about.tsono.org/articles/bootstrap5-nested-model">元の記事を読む</a></p>]]></content:encoded></item><item><title>レビューは試験ではないことがわかってきた</title><link>https://about.tsono.org/articles/review-is-not-exam</link><guid isPermaLink="true">https://about.tsono.org/articles/review-is-not-exam</guid><pubDate>Mon, 14 Jul 2025 00:00:00 GMT</pubDate><description>レビューを受ける側からする側へ回って感じた意識の変化の話。</description><content:encoded><![CDATA[<p>昨年の4月にエンジニアに転職してリモートで保守・開発をしてきた。入社してから社内のテックリードが割り振ったタスクをもとに実装をし、PRを出してレビューをしてもらう流れが10ヶ月ほど続いていた。</p>
<p>実装や技術的な問題解決に取り組むことは楽しい一方、レビューを受ける際に「レビュワーの正解を探し当てる必要がある」と考えていた。</p>
<p>背景には、私が「中途未経験で業界に入った自分には圧倒的に知識と経験が足りない」という劣等感を抱いていたことと、前職の文脈が影響していたからだと思う。</p>
<h2 id="自分がレビューをするようになって"><a href="https://about.tsono.org/articles/review-is-not-exam#%E8%87%AA%E5%88%86%E3%81%8C%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC%E3%82%92%E3%81%99%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%A6">自分がレビューをするようになって</a></h2>
<p>自分自身がレビューをする立場になったことで、認識が大きく変わった。レビューは「試験」ではなく「お互い知見・判断を持ち寄り、より良いものを作るための対話の場」であることを実感した。
レビューをしているとき、自分が過去に経験した課題や良さそな解法を提案としてコメントするが、それが唯一の正解だとは思わない。あくまでも提案であり、より適した解法があればそちらを採用したいという思いでレビューしている。</p>
<p>自身のPRについたコメントは批判ではなく嬉しい意見として捉えられるようになり、レビューに対する過度な緊張がなくなった。</p>
<h2 id="無謬性は存在しない"><a href="https://about.tsono.org/articles/review-is-not-exam#%E7%84%A1%E8%AC%AC%E6%80%A7%E3%81%AF%E5%AD%98%E5%9C%A8%E3%81%97%E3%81%AA%E3%81%84">無謬性は存在しない</a></h2>
<p>レビューを経てマージされたコードにも後から修正が入ったり、仕様変更でやり直しが発生することも少なくない。最善な選択は後でひっくり返ることを実感した。</p>
<p>逆に言えば、自分の提案や設計次第でプロダクト全体の質が変わることを強く意識するようにもなった。
ただ言われたとおりに作るのではなく、自らの判断や提案がプロダクトに影響を与えるというコントロール感を強く持てるようになった。より主体的に開発に関われるようになったかな。</p>
<h2 id="なぜ今まで実感できていなかったのか"><a href="https://about.tsono.org/articles/review-is-not-exam#%E3%81%AA%E3%81%9C%E4%BB%8A%E3%81%BE%E3%81%A7%E5%AE%9F%E6%84%9F%E3%81%A7%E3%81%8D%E3%81%A6%E3%81%84%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%8B">なぜ今まで実感できていなかったのか</a></h2>
<p>書いてみると当たり前だが、なぜ実感できていなかったのか。
「評価される側」という立場から抜け出せていなかったことと、前職で身についた文化の影響が大きかったのだと思う。</p>
<p>以前は役人として働いており、そこでの仕事は無謬性が極めて強く求められていた。
前例主義・形式主義・間違えないようにするための決裁というプロセス。</p>
<p>その文脈をこちらの世界に持ち込んでいたから「決裁 = レビュー」という変換をしていたのかもしれない。</p>
<h2 id="これから"><a href="https://about.tsono.org/articles/review-is-not-exam#%E3%81%93%E3%82%8C%E3%81%8B%E3%82%89">これから</a></h2>
<p>今後は、レビュー時のコメントの書き方にも、これまで以上に気を配っていきたい。
私自身が前述のような経験をしてきたからこそ、コメントを受け取る側のコンテキストによって心理的な負担の感じ方が変化することを理解している。</p>
<p>「これはあくまで一つの提案であり、私の意見が唯一の正解ではないよ」というスタンスが、コメントからも自然に伝わるようにしたい。一緒により良い選択肢を探す姿勢を言葉に込めることを意識していきます。</p><p><a href="https://about.tsono.org/articles/review-is-not-exam">元の記事を読む</a></p>]]></content:encoded></item><item><title>macOSでshift + spaceを使って入力ソースを切りかえる</title><link>https://about.tsono.org/articles/macos-shift-space</link><guid isPermaLink="true">https://about.tsono.org/articles/macos-shift-space</guid><pubDate>Wed, 02 Jul 2025 00:00:00 GMT</pubDate><description>macOSでショートカットに&quot;shift + space&quot;を割り当てる方法。</description><content:encoded><![CDATA[<h2 id="summary"><a href="https://about.tsono.org/articles/macos-shift-space#summary">Summary</a></h2>
<ol>
<li><code>open ~/Library/Preferences/com.apple.symbolichotkeys.plist</code></li>
<li><code>Root</code> > <code>AppleSymbolicHotKeys</code> > <code>61</code> > <code>value</code> > <code>parameters</code></li>
<li><code>item 2</code> を <code>131072</code> に設定する</li>
<li>PCを再起動</li>
<li><code>システム設定</code> -> <code>キーボード</code> -> <code>キーボードショートカット</code> -> <code>入力ソース</code> に <code>shift + space</code> が設定されていることを確認</li>
<li><code>shift + space</code> で入力ソースを切り替えられることを確認</li>
</ol>
<h2 id="経緯"><a href="https://about.tsono.org/articles/macos-shift-space#%E7%B5%8C%E7%B7%AF">経緯</a></h2>
<p>昨年から仕事で Windows を使うようになり、以前から私物の M1 MacBook Air で愛用していた <code>Keycron k2(英字キー)</code> をWindowsにもつなぐようになった。</p>
<p>英字配列のため IME の <code>日本語⇔英語</code> 切り替えに設定が必須。
macでは <code>control + space</code> で変換していた（<code>caps lock</code> を <code>control</code> に置き換えて）</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/00b2064b15df7952/640.avif 640w, https://about.tsono.org/images/generated/00b2064b15df7952/960.avif 960w, https://about.tsono.org/images/generated/00b2064b15df7952/1280.avif 1280w, https://about.tsono.org/images/generated/00b2064b15df7952/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/00b2064b15df7952/640.webp 640w, https://about.tsono.org/images/generated/00b2064b15df7952/960.webp 960w, https://about.tsono.org/images/generated/00b2064b15df7952/1280.webp 1280w, https://about.tsono.org/images/generated/00b2064b15df7952/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/macos-shift-space/figures/mac-key.webp" alt="macOSでの切り替え方法" width="1600" height="1200" loading="lazy" decoding="async"></picture>
<p>ところがWindowsだと（経緯は忘れたが）同様の設定ができず、結局 <code>shift + space</code> で運用することとした。</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/9e6b87980d0a6a4b/640.avif 640w, https://about.tsono.org/images/generated/9e6b87980d0a6a4b/960.avif 960w, https://about.tsono.org/images/generated/9e6b87980d0a6a4b/1280.avif 1280w, https://about.tsono.org/images/generated/9e6b87980d0a6a4b/1600.avif 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/9e6b87980d0a6a4b/640.webp 640w, https://about.tsono.org/images/generated/9e6b87980d0a6a4b/960.webp 960w, https://about.tsono.org/images/generated/9e6b87980d0a6a4b/1280.webp 1280w, https://about.tsono.org/images/generated/9e6b87980d0a6a4b/1600.webp 1600w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/macos-shift-space/figures/win-key.webp" alt="Windowsでの切り替え方法" width="1600" height="1200" loading="lazy" decoding="async"></picture>
<p>仕事用PCのほうが使用率が高いのでいつの間にか手癖が変わってしまい、mac使用時に <code>shift + space</code> を押してしまうタイプミスが頻発。
作業にならないので、入力ソースを切り替えるためのショートカットを変更しようとしたが...</p>
<h2 id="shift--space-のキーボードショートカットを設定できない"><a href="https://about.tsono.org/articles/macos-shift-space#shift--space-%E3%81%AE%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89%E3%82%B7%E3%83%A7%E3%83%BC%E3%83%88%E3%82%AB%E3%83%83%E3%83%88%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84">shift + space のキーボードショートカットを設定できない</a></h2>
<p>当方 <code>macOS 15.5</code> だが、<code>システム設定 → キーボード → キーボードショートカット</code> で <code>shift + space</code> が設定できない。
打ち込んでも反応しない。</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/9e937d3dfd60bd57/640.avif 640w, https://about.tsono.org/images/generated/9e937d3dfd60bd57/960.avif 960w, https://about.tsono.org/images/generated/9e937d3dfd60bd57/1280.avif 1280w, https://about.tsono.org/images/generated/9e937d3dfd60bd57/1372.avif 1372w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/9e937d3dfd60bd57/640.webp 640w, https://about.tsono.org/images/generated/9e937d3dfd60bd57/960.webp 960w, https://about.tsono.org/images/generated/9e937d3dfd60bd57/1280.webp 1280w, https://about.tsono.org/images/generated/9e937d3dfd60bd57/1372.webp 1372w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/macos-shift-space/figures/settings-shortcut.webp" alt="システム設定 &gt; キーボード &gt; キーボードショートカット" width="1372" height="946" loading="lazy" decoding="async"></picture>
<p>そこで調べていたところ、以下を記事を発見</p>
<p><a href="https://seorenn.tistory.com/547">macOS 한영전환키를 Shift+Space로 설정하기 (feat. Sonoma)</a></p>
<p>やはり <code>shift + space</code> は設定できないようだが、解決策が書いてある。</p>
<p><code>com.apple.symbolichotkeys.plist</code> ファイルの中にある、 <code>AppleSymbolicHotkeys</code> のうち</p>
<ul>
<li>60番が <code>前の入力ソースを選択</code></li>
<li>61番が <code>次の入力ソースを選択</code></li>
</ul>
<p>に該当し、Item2 の値を <code>131072</code> というキーコードに書き換えることで <code>shift + space</code> を登録できる模様。</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/ea6da71a44b6fcba/640.avif 640w, https://about.tsono.org/images/generated/ea6da71a44b6fcba/804.avif 804w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/ea6da71a44b6fcba/640.webp 640w, https://about.tsono.org/images/generated/ea6da71a44b6fcba/804.webp 804w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/macos-shift-space/figures/plist.webp" alt="com.apple.symbolichotkeys.plist変更後" width="804" height="395" loading="lazy" decoding="async"></picture>
<p>試してみたところ、PCを再起動することで入力ソース切り替えのショートカットに <code>shift + space</code> が反映された 🙌</p>
<picture class="article-image"><source type="image/avif" srcset="https://about.tsono.org/images/generated/b4ea21e7cd660592/640.avif 640w, https://about.tsono.org/images/generated/b4ea21e7cd660592/960.avif 960w, https://about.tsono.org/images/generated/b4ea21e7cd660592/1140.avif 1140w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><source type="image/webp" srcset="https://about.tsono.org/images/generated/b4ea21e7cd660592/640.webp 640w, https://about.tsono.org/images/generated/b4ea21e7cd660592/960.webp 960w, https://about.tsono.org/images/generated/b4ea21e7cd660592/1140.webp 1140w" sizes="(max-width: 42rem) calc(100vw - 2rem), 42rem"><img src="https://about.tsono.org/images/articles/macos-shift-space/figures/shortcut-confirm.webp" alt="システム設定 &gt; キーボード &gt; キーボードショートカット" width="1140" height="798" loading="lazy" decoding="async"></picture>
<p>これで、同じ使い心地で日本語と英語を切り替えられて快適。</p>
<p>元記事でも言及されているが、なぜショートカットに <code>shift + space</code> が登録できなんだろう。
（ほかアプリのショートカットとバッティングする可能性が高いとか？）</p>
<p>今のところ、常駐させているアプリケーション（Emacs, iTerm）とは衝突しておらず、問題なく使えている。</p><p><a href="https://about.tsono.org/articles/macos-shift-space">元の記事を読む</a></p>]]></content:encoded></item></channel></rss>