Hubpin
自分の発信(ブログ・Zenn・X・GitHub・自作アプリ)を1枚のページに集約するハブサイト。
手書きの HTML で運用していたものを、コードを触らずに更新できる形に作り直しました。
デモログインはアカウント登録なしで使えます。カードの追加・編集・並び替えと、その結果が公開ページへ反映されるところまで試せます。 デモのデータはログインのたびに初期状態へ戻るので、どこをどう触っても大丈夫です。
なぜ作ったか
発信する場所が増えるたびに、リンクをまとめたページを手で書き足していました。 2026年5月に作った、手書きの HTML です。
7月に、そのページのブログカードだけ古い URL のままになっていることに気づきました。 ブログのアドレスを変えたときに張り替えたつもりで、1枚だけ漏れていた。 気づいたのは2ヶ月後で、その間ずっと古いリンクが載ったままでした。
カードが増えるほど、手で直す場所も増えます。 このサイトは、その1枚を直すために HTML を触らなくて済むようにしたものです。
数字で見る
41
読み込むファイル数
フォントの読み込み方を直して3.5分の1に
290 kB
フォントの通信量
1,538kBから5分の1に。必要な字だけ配るようにした
3 媒体
自動で取り込む発信元
ブログ・Zenn・GitHubの新着が1日1回入る
8 本
自分で見つけて残した改善
完成後のレビューで出た73件を整理した
上の2つは、公開したあとに自分のページを測り直して直した前後の差です。 フォントを必要な字だけに絞り、読み込み方を変えたことで、開くまでに流れる通信が減りました。 その後、外部の記事を取り込む機能を足したぶん少し増えていて、削る作業は課題として残してあります。 手書き版とは測定条件を揃えられていないので、比較はしていません。
動いているものを止めずに載せ替えた
手書き版は同じドメインで動いていて、1作目のアプリの説明ページや画像も同居していました。 ドメインごと新しいサーバーに向けると、関係のないページまで一緒に引っ越すことになります。
そこで、新しいものは別のアドレスで公開して、 トップページだけをそこへ転送する形にしました。 同居していたページ・画像・メールはそのまま残っています。
見た目は移植せず、組み直しました。 手書き版の CSS は「どのカードをどこに置くか」を名前で書いた固定の表になっていて、 カードの枚数がデータで変わる作りとは両立しません。 そのまま持ち込むと、手で直す場所が HTML から CSS に移るだけでした。
カードは3種類ある
外部へ飛ぶカード、記事の一覧が入るカード、開くと説明が出るカードの3つがあります。 カードの左上にある丸が、その見分けになっています。 塗りつぶしなら外部へ飛び、中が空いていればその場で開きます。
記事の一覧が入るカードは、ブログ・Zenn・GitHub から1日1回まとめて取り込みます。 新しく書いたものは、こちらが何もしなくても載ります。
画面に出ないところを確かめた
このサイトは自分1人で使いますが、データの作りは複数人が使う前提にしてあります。 そうすると「他人のカードを書き換えられないこと」を確かめる必要が出てきます。
データベース側に、持ち主でなければ触れない規則を入れました。 規則が効いていることは画面で確かめられます。 他人のカードを書き換えようとすると、エラーにならず「0件変更」で終わります。 自分のカードなら同じ操作で7件変わります。
確かめ方は、書き換えを試すSQLに「期待: 0行(エラーではない)」とコメントを書いて実行し、 結果が想定どおりかを見る形にしました。 はじめから出来ていたわけではありません。 途中で規則の抜けが見つかり、塞いでから、塞がっていることをこの方法で確かめました。
入れなかったものの話
安全のための設定を3つ入れました。同時に、もう1つの設定はあえて入れませんでした。 入れると仕組みが複雑になり、このサイトの売りである「あらかじめ作っておいたページをそのまま配る」やり方と噛み合わなくなるためです。 入れた3つは、どのページでも同じ値を返すだけなので、その配り方と両立します。
入れた設定の1つは「このページを他人のサイトに埋め込ませない」というものでした。 守りたかったのはログイン画面1つです。
その3週間後、この掲載ページ用の画面写真を撮ろうとして、自分がその設定に止められました。 撮影のために自分のページを埋め込もうとして、拒否されたためです。 設定を入れたことより、効いていることが自分で分かったことのほうが収穫でした。
技術と開発プロセス
- フレームワーク
- Next.js 16(App Router)/ React 19 / TypeScript
- データベース・認証
- Supabase(PostgreSQL)
- 外部フィード取得
- Vercel Cron(1日1回)/ RSS・REST API
- スタイル
- Tailwind CSS v4
- テスト
- Vitest / React Testing Library
- CI
- GitHub Actions(ESLint / Prettier / テスト / ビルド)
- ホスティング
- Vercel
- 要件を先に決めて文書に残し、作る範囲を確定させてから着手した
- 1つの機能につき1つの Pull Request。自動チェックが全部通らないと反映できない設定にしている
- 工程ごとに見積時間と実績時間を記録し、差が出た理由を残している
- 完成後に AI で6つの観点からコードを見直し、73件の指摘を8本の課題に整理した。うち安全に関わる1件はその日のうちに直した
課題を8本残したままにしているのは、直し切れなかったからではありません。 1件ずつ「どのファイルの何行目か」「なぜ問題か」「どれくらいかかるか」まで書いてあります。 テストについても、本数ではなく「何を守っているか」を README に書くようにしました。 通っている本数より、通っていない範囲が分かることのほうが大事だと考えています。
これから
今は自分1人で使っていますが、データの作りは複数人が使う前提で組んであります。
この先やりたいのは、カードをドラッグして並び替えられるようにすることと、 ページごとの画像を自動で作ることです。 完成後の見直しで出た改善も、8本を課題として残してあります。
作りながら決めている部分が多いので、形は変わるかもしれません。