Home

Hubpin

自分の発信(ブログ・Zenn・X・GitHub・自作アプリ)を1枚のページに集約するハブサイト。
手書きの HTML で運用していたものを、コードを触らずに更新できる形に作り直しました。

デモログインはアカウント登録なしで使えます。カードの追加・編集・並び替えと、その結果が公開ページへ反映されるところまで試せます。 デモのデータはログインのたびに初期状態へ戻るので、どこをどう触っても大丈夫です。

Hubpinの公開ページ。7枚のカードが2列に並び、ブログとZennのカードには最新記事のタイトルが3件ずつ、GitHubのカードにはリポジトリ名が3件入っている
タブレット幅で開いたところ。同じ画面が、端末の設定に合わせて明るさを切り替えます。

なぜ作ったか

発信する場所が増えるたびに、リンクをまとめたページを手で書き足していました。 2026年5月に作った、手書きの HTML です。

7月に、そのページのブログカードだけ古い URL のままになっていることに気づきました。 ブログのアドレスを変えたときに張り替えたつもりで、1枚だけ漏れていた。 気づいたのは2ヶ月後で、その間ずっと古いリンクが載ったままでした。

カードが増えるほど、手で直す場所も増えます。 このサイトは、その1枚を直すために HTML を触らなくて済むようにしたものです。

作り直す前の手書きHTML版のハブページ。大小のカードが組み合わさったレイアウトで、Portfolio・Blog・Plate Calculator・X・Zenn・GitHub・Roadmapの7枚が並んでいる
作り直す前。手書きの HTML で、カードを1枚足すたびに HTML と CSS の両方を直していました。

数字で見る

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本を課題として残してあります。

作りながら決めている部分が多いので、形は変わるかもしれません。

実際に触ってみてください