N.Hayashida

自分用の開発基盤をつくる
依存ゼロで、スマホから全部を見る

個人開発 / ツール個人開発(設計・実装・運用)2026年7月〜(運用中)2026-08-08

抱えているプロジェクトの進捗を自動で集めて表示するダッシュボードと、生成したレポートを外出先から読むための閲覧ハブ。どちらもPythonの標準ライブラリだけで書き、フレームワークもビルド工程も使っていません。メール表示を25秒から0.46秒にした話や、iOSの音声許可に苦しんだ話を書きます。

25s0.46s

メール表示の応答時間

Technologies

Pythonhttp.serverTailscaleWSLPostgreSQLIMAP

プロジェクト概要

私はいま、業務と個人あわせて30ほどのプロジェクトを並行して抱えています。それぞれにディレクトリがあり、記録があり、次にやることがあります。

問題は、それらを一覧できる場所がなかったことです。どれが進んでいてどれが止まっているのか、自分でも把握できなくなっていました。

そこで2つのツールを作りました。ひとつは全プロジェクトの進捗を自動収集して表示するダッシュボード。もうひとつは、生成したレポートを外出先のスマートフォンから読むための閲覧ハブです。どちらも自分ひとりのために作った、完全な個人ツールです。

設計方針
依存をゼロにする

最初に決めたのは、外部パッケージを一切使わないということでした。

Pythonの標準ライブラリだけでサーバーを書き、フロントエンドはフレームワークを使わず、CSSはHTMLに直接埋め込む。ビルド工程もありません。

理由は単純で、自分ひとりが使うツールに、壊れる要素を増やしたくなかったからです。パッケージが増えれば、そのアップデートで動かなくなる可能性が生まれます。実際、別のプロジェクトで依存ライブラリの自動更新に足をすくわれた経験がありました。

この判断は正解だったと思っています。片方は4,000行を超える規模になりましたが、依存パッケージは今もゼロです。環境を作り直しても、Pythonさえあれば動きます。

ただし見た目まで素朴でいいとは思いませんでした。デザインについては、広く使われているUIライブラリのデザインシステムだけを移植しています。ライブラリ自体はビルド前提で導入できないので、色や角丸のスケール、余白の取り方、コンポーネントの様式といった設計だけを読み取って、埋め込みCSSで再現しました。絵文字は全部やめて線画のアイコンに統一しています。

何が自動で集まるか

進捗の入力は一切しません。すべて自動で集めます。

各プロジェクトのファイル更新日時を走査して、最終活動日と活動レベル(稼働中・直近・低活動・休眠)を判定します。56日分の活動をスパークラインで表示し、バージョン管理されているものはコミット履歴やブランチ、未コミット数も拾います。

説明文と「次にやること」は、各プロジェクトの記録ファイルから決まった優先順位で自動抽出しています。進捗ファイルを正本として最優先で読むというルールを決めて、各プロジェクト側もその書式に合わせるようにしました。ツールに合わせて記録の書き方を揃えた形です。

走査はアクセスのたびに行いますが、60秒のキャッシュを挟み、期限が切れていても古い内容をすぐ返してから裏で更新する方式にしています。表示を待たされることはありません。

細かいところでは、依存ライブラリのフォルダなどを丸ごと無視する処理と、未来の日付を持つ壊れたファイルを活動と数えないガードを入れています。後者は、共有サーバー由来のPDFに西暦2446年の更新日時を持つものが実在したためです。

「動いているか」と「自分が止めているか」は別物

運用してしばらくして、一覧では足りないことに気づきました。

きっかけは、期限を3日過ぎた判断が、一覧では平常表示のままだったことです。そのプロジェクトは他の作業で更新されていたので「稼働中」と表示されており、私の判断待ちで止まっている部分が完全に埋もれていました。

活動の有無と、自分がボトルネックになっているかどうかは、まったく別の情報です。そこで判断待ちと期限だけを全プロジェクトから抜き出す画面を追加しました。現在14件の判断待ちと2件の期限が並んでいます。

この抽出はAIを使わず、決め打ちのルールだけでやっています。応答が即時で、コストもかからないからです。ただしルールベースなので精度の作り込みが必要で、取り消し線は無条件で完了扱いにする、「済」の判定は打ち消し表現を考慮する、済欄がない表は全行を未了とみなす、箇条書きの折り返しは前の項目に連結する、といった調整を重ねました。

横断検索も同じ考え方です。全プロジェクトのテキストファイルをその場で検索してプロジェクト別にまとめて返します。AIに聞くより速く、コストもかかりません。AIを使わなくていいところでは使わない、という線引きは意識的にやっています。

遅さの真因は、たいてい想像と違う

会社のメールをこのダッシュボードから読めるようにしたところ、「メールを見に行くのに時間がかかる」という不満が自分の中で出てきました。

計測すると、初回表示に25秒かかっていました。

原因を追いかけたら、メールを1通開くたびに、最新200通の全文をダウンロードしていました。一覧を作るのに全文は要りません。

修正は2段階です。まず一覧の取得を、古い内容を即座に返してから裏で更新する方式に変え、起動時に先読みしておくようにしました。これで25秒が0.46秒になりました。次に個別表示を、指定した1通だけを取得する方式に変え、10分のキャッシュを追加。19秒が0.36秒になっています。

Fig.01
要らないものまで取るのをやめた変更前:一覧で全件取得25秒変更後:必要な分だけ取得一覧:必要分だけ取得+起動時に先読み個別:1通だけ取得+10分キャッシュ0.46秒個別表示 19秒 → 0.36秒処理を速くしたのではなく、処理しないものを決めた

キャッシュ更新中にロックを握らない、という細かい配慮も入れました。1人が待たされている間、他の処理まで止まるのを防ぐためです。

体感で「遅い」と思ったときに、想像で原因を決めずに実際の処理を追いかける。当たり前のことですが、この件は自分にとって良い教訓になりました。

スマホで動かすということ

このツールは基本的にスマートフォンから使います。通勤中や外出先で状況を確認したいからです。ここで一番手こずったのがiOSでした。

効果音が鳴らないという問題がありました。調べていくと、iOSが音声の再生を許可するのはタップが完了したイベントの中だけです。タッチの開始時点やページ表示時点で音声の準備をすると、権限がない状態になり、以後ずっと無音になります。処理する場所を移して解決しました。

さらに厄介だったのが、iOSは画面遷移のたびに音声の許可をリセットすることです。これに対しては、そもそも遷移をなくすという方針を取りました。レポートは画面遷移ではなく、その場で重ねて表示する方式にして、戻る操作は重ねた表示を閉じる動作に変換しています。回避策というより、設計を変えた形です。

振動も一筋縄ではいきませんでした。標準の振動APIがiOSでは効かないため、チェックボックスの切り替えを利用する方法で実現しています。

そのほか、片手で操作できるよう画面下部にタブバーを固定し、ドロワーはJavaScriptを使わずCSSだけで開閉し、プロジェクトの選択は検索ボックスをやめて標準の選択UIに変えました。スマホで文字入力をさせないというのは、意外と効きます。

こうした不具合はデスクトップでは一つも再現しません。そのため、変更したら必ず構文チェック、再起動、疎通確認、そして幅500pxのスクリーンショット確認まで通す、という手順を固定しました。この確認を省いた回に「入力欄が下部のタブバーに潜り込む」という不具合を見逃しています。

外から安全に見るための構成

自宅のPC上で動かし、外部からは閉域ネットワーク経由でのみ到達できるようにしています。インターネットへの公開機能は絶対に使いません。扱っているファイルには業務の情報が含まれるためです。

ここでも環境の壁がありました。ネットワークサービスがシステム権限で動いている一方、サーバーは仮想環境の中にあり、どちらの経路でも直接は届きません。切り分けの結果、ユーザー権限で動く中継プロセスだけが仮想環境に到達できるとわかり、間に中継を1段挟む構成にしました。中継は起動時に仮想環境のアドレスを解決し、接続に失敗したら再解決するので、再起動にも追従します。

認証は暗証番号方式ですが、当初はブラウザ側に平文で保存していました。これは指摘を受けて作り直し、照合に成功したらトークンを発行してCookieで保持する方式に変更。トークンはサーバーのメモリ上にだけ置くので、再起動すれば全て失効します。連続5回失敗すると5分間ロックする処理も入れました。

現在の使われ方

毎朝5時半に、その日の予定と各プロジェクトの状況をまとめた要約が自動生成されます。出勤直後に30秒で読める分量にしてあり、音声で読み上げることもできます。画面を見られない移動中のためです。

このほか、ロック画面のウィジェットで利用枠の残量を確認できるようにしたり、夜間に処理を予約しておく機能を追加したりしています。作りたい機能というより、使っていて面倒だったところを順番に潰していったら増えたという感じです。

レポート閲覧のほうは、全プロジェクトを走査して実務レポート約41件を一覧表示し、ファイル名やプロジェクト名で絞り込めます。メールに添付する前の確認にも使っています。

このプロジェクトで得たもの

自分のために作るツールは、要件定義が要らない代わりに、不満を感じた瞬間が仕様になります。期限が埋もれた、メールが遅い、音が鳴らない。そのたびに直していった結果が現在の形です。

依存ゼロという制約は、最初は縛りのつもりでしたが、今は資産だと感じています。1年後も同じように動く見込みがあること、それ自体が個人ツールにとっては価値でした。

そして、自分の作業環境を自分で作れると、仕事の進め方そのものを設計できます。これはツールを買ってきて使うのとは、別の種類の自由だと思っています。

Outcomes & Results

  • 進捗の手入力をゼロにし、全プロジェクトの状態を自動収集
  • メール表示を25秒から0.46秒へ、個別表示を19秒から0.36秒へ改善
  • 外部パッケージの依存ゼロを維持したままダッシュボードを構築
  • 判断待ち・期限を横断抽出する機能を追加(判断待ち14件を可視化)
  • ログオン時の自動起動で常駐化し、日々の運用に定着

Challenges Overcome

  • 仮想環境の制約で、外部からサーバーに到達できなかった
  • iOSでは画面遷移のたびに音声の許可がリセットされる
  • メールを開くたびに最新200通の全文をダウンロードしていた
  • 期限が3日過ぎても一覧では平常表示のままだった

Key Learnings

  • 依存ゼロは制約ではなく資産になる。壊れる要素が少ないほど長く動く
  • 遅いと感じたら体感ではなく処理を計測する。真因は想像と違うことが多い
  • スマホ実機でしか出ない不具合がある。確認の手順そのものを固定する
  • 「動いているか」と「自分が止めているか」は別の情報。後者は埋もれやすい
#Python#自作ツール#ダッシュボード#モバイル対応#パフォーマンス改善