(あまりにも時間が足りず、完成させたいプロジェクトだったのですが全く終わりませんでした。反省、作り直しているリポジトリ)
GitFeedはソフトウェアエンジニアのための情報収集・交流サービスです。GitHubの静的な情報をTwitter ライクにユーザーが選択した形式で取得でき、かつTLでの発信も可能とし、エンジニアの情報収集の効率化および交流の活発化を目的とします
自分はエンジニアの情報を主にTwitterやQiitaやZennなど(たまにYouTube)で取得することが多いです。ただ最近はそこでストレスに感じることがあります。それは「AI系の発信が多すぎて疲れる」ということです。特にAI驚き屋みたいな非エンジニアのくせにこのAIがすごいとか言ってインプレッション稼ぎと情報商材を売っている輩は心底嫌いです。 自分はAIツールへのキャッチアップは生産性向上のためにもちろんすべきですが、本質はAIのモデルや性能ではなくその結果生み出される人間が介入したうえでの最終的な生成物の評価だと思っています。なので インプゾンビやポジショントークしかできないクズがいない クリーンな情報収集ツールを作ろうと考えました。エンジニアの一次情報は結局コードなのでGithubのAPIを叩き受動的に他人の活動を垂れ流し、Twitterライクではあるがクリーンなコードの情報を取得できる場を作りたいというのが第一の動機です。またエンジニアの主要な交流ツールがコードと直結しないTwitterであるということも疑問に思っています(ここはGithubでもConversationとかありますが、あれはクローズドでもう少し情報をオープンに取ってこれたらなという思想があります)。時間が余ればAIにリソースを与えてエンジニアの能力向上を促すような教師的な役割をさせたり出来たらなと思います。自分は思想が強いので少し大げさかもしれませんが、こういうことを考えているエンジニアは少なからずいるのではと思っています。
erDiagram
users {
UUID id PK
string username UK
string display_name
string avatar_url
TIMESTAMP created_at
}
follows {
%% CHECK: follower_id != followee_id
UUID follower_id PK,FK
UUID followee_id PK,FK
TIMESTAMP created_at
}
posts {
UUID id PK
UUID user_id FK
string content
TIMESTAMP created_at
TIMESTAMP updated_at
}
likes {
UUID user_id PK,FK
UUID post_id PK,FK
TIMESTAMP created_at
}
github_subscriptions {
UUID id PK
UUID user_id FK
%% XOR: (actor_remote_id IS NOT NULL) XOR (repo_remote_id IS NOT NULL)
%% Github RESTのuser/org id(nullable)
integer actor_remote_id
%% Github RESTのrepo id(nullable)
integer repo_remote_id
json filters
TIMESTAMP created_at
}
github_events {
UUID id PK
string remote_event_id
string event_type
TIMESTAMP event_time
TIMESTAMP fetched_at
integer actor_remote_id
integer repo_remote_id
string language_slug
UUID language_id FK
json payload
}
user_feed_seen {
UUID user_id FK
string remote_event_id
TIMESTAMP seen_at
%% PK(user_id, remote_event_id)
}
tags {
UUID id PK
string slug UK
string label
TIMESTAMP created_at
}
user_tag_prefs {
UUID id PK
UUID user_id FK
UUID tag_id FK
integer weight
TIMESTAMP created_at
TIMESTAMP updated_at
}
event_tags {
UUID event_id FK
UUID tag_id FK
numeric share
%% PK(event_id, tag_id)
}
users ||--o{ posts : "writes"
users ||--o{ likes : "likes"
posts ||--o{ likes : "is liked by"
users ||--o{ follows : "follows"
users ||--o{ follows : "is followed by"
users ||--o{ github_subscriptions : "creates"
users ||--o{ user_tag_prefs : "has"
tags ||--o{ user_tag_prefs : "chosen"
tags ||--o{ event_tags : "labels"
github_events ||--o{ event_tags : "has"users ||--o{ posts : "writes"
users ||--o{ likes : "likes"
posts ||--o{ likes : "is liked by"
users ||--o{ follows : "follows"
users ||--o{ follows : "is followed by"
users ||--o{ github_subscriptions : "creates"
users ||--o{ user_tag_prefs : "has"
tags ||--o{ user_tag_prefs : "chosen"
tags ||--o{ event_tags : "labels"
github_events ||--o{ event_tags : "has"
sequenceDiagram
participant S as Scheduler(1–5min)
participant Q as Queue(shards)
participant J as Fetcher Job
participant GH as GitHub API
participant DB as DB
S->>Q: enqueue targets (actor/repo)
Q->>J: pop target
J->>GH: GET events with ETag / If-Modified-Since
alt 304 Not Modified
GH-->>J: 304
J->>DB: update last_polled_at / etag
else New events
GH-->>J: events[]
J->>DB: UPSERT github_events by remote_event_id (unique)
J->>DB: update cursor (last_seen_event_time, etag)
end
EPIC := 大き目のテーマ、複数のユーザーストーリーを内包 US(User Story) := ユーザーストーリー、ユーザー視点の最小単位の要求 P0/P1/P2 := Priority 優先度
EPIC:認証
US-01(P0)
- 「Sign in with Github」でサインイン
- 初回サインインでなければ/feedへ
- 初回サインインであれば初期設定ページへ
EPIC:初期設定
US-02(P0)
- 「言語タグ」を3~5個選ぶ
- その結果Feedに重みが反映
- user_tag_prefsに保存
EPIC:Feedを見る(コード一次情報)
US-03(P0)
/feedを開く- 新しい順にGithubイベントカードが表示される
- 3種(PR, Release, Issue)のカードが表示される
- スクロールで10件ずつ(暫定)ずつ追加取得
- 取得件数が0件の場合
/discoverへの導線 US-04(P0) - Githubイベントカードから実際のgithub上のURLに遷移
- 新規タブで開く US-05(P1)
PRのみ/merge済みのみ/言語などフィルタできる- 表示が即反映
EPIC:対象を見つけてサブスクリプション
US-06(P0)
/discoverでrepo/actorを検索- サジェストから選択 US-07(P0)
- filterをセットして「Save」
- github_subscriptionにレコードが追加されFeedに反映
EPIC:自分の購読を管理
US-08(P0)
/subscriptionsで一覧が見える- 対象とfilters要約・未読件数が見える
- 0件時は
/discoverへ導線を設置 - 削除/一時停止が可能
- Next.js App Router: デファクトスタンダードでルーティングが直感的なので採用。(後から考えたらほぼCSRなのでReact Router v7+Viteとかでよかったです 2025/11/04)
- TailwindCSS: CSSを分離する必要がないため即決
- shadcn/ui: 他のUIライブラリ(MUI, chakra)は独自の思想があり、割とプレーンなものを使いたい。shadcnにチームの思想は宿らせることはできないが、プレーンなまま使う。v0とかとの互換性があるのも良き
- Zustand: Reduxは学習コストが高くcontext apiはややパフォーマンスが悪い(なぜ採用したのか分からないです。TanStack Queryを使えばよかった 2025/11/04)
- Ruby on Rails API Mode: 古い枯れた技術だが自分(TsukuneA1)が多少慣れている&wantedlyの求人数もそこそこある。学習の価値はあるので採用。あとgoとかで自分でアーキテクチャ組もうとしても恐らく破壊が起こるのでやれないしやりたくない。(破壊が起こる→理解不足で境界が曖昧なままになりそうだと考えていた。今思うとレイヤードでServiceを作るとかはやってもよかった 2025/11/04)
- omniauth
- daily.dev: 記事や動画などをスクローリングしてくる。完成度が高すぎて同路線で行くと勝負にならない
- Github: そもそもサービスとしての提供したい機能・目的が違う
- GitHub OAuth認証 - 安全なログイン・認証システム
- リポジトリデータ同期 - GitHub APIを通じた自動データ取得
- AIプロフィール解析 - OpenAI APIによるスキル・経験の自動分析
- コード品質解析 - リポジトリのコード品質評価とメトリクス算出
- エンジニアネットワーキング - スキル類似度によるエンジニア発見・マッチング
- AI チャット機能 - プロフィールに関するQ&A機能
技術的な詳細は docs ディレクトリを参照してください。
- Backend: Rails 8.0.2 (API mode) + PostgreSQL
- Frontend: Next.js 15 (App Router) + TypeScript + Tailwind CSS
- AI Integration: OpenAI GPT-3.5-turbo
- Authentication: GitHub OAuth + JWT
- External APIs: GitHub REST API, Octokit
- Go Task: タスクランナー (インストールガイド)
- pnpm: フロントエンドパッケージマネージャー
- Ruby 3.3.7: バックエンド環境
- Node.js 20+: フロントエンド環境
- PostgreSQL: データベース
### 🚀 Task による一括開発環境セットアップ
```bash
# 依存関係のインストール
task install
# 開発サーバー起動(両方同時)
task dev
# 個別起動も可能
task backend:dev # Rails (port 3000)
task frontend:dev # Next.js (port 3001)
# 全体のコード品質チェック
task ci:all
# フロントエンド(Biome + ESLint + TypeScript)
task ci:frontend
# バックエンド(RuboCop)
task ci:backend# 全体のフォーマット実行
task format
# 個別フォーマット
task frontend:format # Biome + ESLint自動修正
task backend:format # RuboCop自動修正# Git hooksを設定(初回のみ)
task hooks:install
# Pre-commit hookをテスト実行
task hooks:test
# コミット時に自動でCI相当のチェックが実行されます
git commit -m "feat: new feature" # 自動でBiome/ESLint/TypeScript/RuboCopが実行# Backend
cd backend
bundle install
rails db:create db:migrate
rails server -p 3000
# Frontend (別ターミナル)
cd frontend
pnpm install
pnpm dev # port 3001で起動アプリケーション:
- Backend API: http://localhost:3000
- Frontend: http://localhost:3001
このプロジェクトではGitHub Actionsによる自動CI/CDが設定されています:
# ローカルでのCI実行(GitHub Actions相当)
task ci:all # 全ての品質チェックを実行