GitHubはこちら → https://github.com/Yuusuke9228/news_app
第1章:既存のニュースアプリに感じていた“漠然とした違和感”
「ニュースアプリを自作しました」と聞くと、よく言われます。
え?わざわざ?SmartNewsとかYahooニュースとかあるじゃん?
…もちろん知ってます。超高機能。データ分析すごい。見やすい。AIレコメンドまである。
でも、ちょっと待ってほしい。
- 開くと動画広告が自動再生される…
- スワイプするたびに広告が挟まる…
- AIが“これおすすめ!”って出してくるけど別に読みたくない…
- フィードが重くて読み込みに時間かかる…
そう、重い・うるさい・思い通りにカスタムできない。
そんな”不満のかたまり”に気づいたとき、思ったんです。
「いっそ、自分で作った方がいいんじゃね?」
第2章:このアプリの特徴は「軽い・早い・静か・広がる」
● 軽い
フレームワークを使わず、素のPHP / JavaScript / CSSで構成。
余計なライブラリや読み込みがないので1秒以内で表示。
しかもスマホ対応済み。
● 早い
MySQLを使ってもクエリは最小限。
SQLチューニング不要で、無限スクロールがサクサク。
DB設計も最適化済み。
● 静か
広告は一切なし。通知もなし。ポップアップもなし。
「読む」ことに集中できるミニマル設計。
● 広がる
GitHubでOSS公開中。
PHP・JS・CSS・Pythonで構成されてるから拡張・改造・連携が自由。
「作って終わり」じゃなく、「作ってからが始まり」。
第3章:アーキテクチャ全体像
下記が本アプリの構成図です。

╔═════════════════════════════╗
║ フロントエンド ║ ← UI+JS+非同期通信
╚═══════╦══════════╦══════════╝
▼ ▼
╔═════════════════════════════╗
║ PHP API(api.php) ║ ← ビジネスロジック/REST通信
╚════════════════╦═══════════╝
▼
╔═════════════════════════════╗
║ MariaDB(MySQL互換) ║ ← 記事/ユーザー/履歴/カテゴリ管理
╚═════════════════════════════╝
▲
╔═════════════════════════════╗
║ Pythonスクリプト(fetch_articles.py) ║ ← RSSデータ収集・整形・登録
╚═════════════════════════════╝
1. データ収集レイヤー(Python)
fetch_articles.py
- はてなブックマークからRSS形式で人気記事を取得
- 記事メタ情報(タイトル、URL、サムネイル、説明文)を抽出
- カテゴリごとに振り分けてDBへ保存
cron
等で1時間ごとなどの定期実行を想定
2. データストアレイヤー(MySQL)
本アプリケーションではMySQLを使用しましたが、SqliteやPostgresなどでも利用可能です・
🗂 テーブル構成
テーブル名 | 目的 |
---|---|
users | ユーザー情報の管理(登録ユーザー/ゲスト) |
articles | 記事情報の保存(RSSから取得) |
categories | カテゴリー定義の管理 |
article_categories | 記事とカテゴリーの関連付け |
user_category_preferences | ユーザーのカテゴリー表示設定 |
user_article_history | 記事閲覧履歴の保存 |
user_custom_categories | ユーザー定義の独自カテゴリ |
3. バックエンドレイヤー(PHP API)
- ファイル:
api.php
- REST形式のAPIエンドポイント群
- PDOを用いた安全なDB接続・操作
- JSON形式でデータ返却
- 各アクションに応じてビジネスロジックを呼び出し
- ユーザー認証・セッション管理
- エラーハンドリング、入力検証付き
4. フロントエンドレイヤー(HTML + JS + CSS)
UI構築:
- index.php によるHTML構造
style.css
によるスタイリング- スマホ対応済(メディアクエリ)
コントローラー(main.js):
- fetch API による API 呼び出し
- DOM構築とレンダリング制御
- カテゴリ切り替えや無限スクロール実装
- ユーザーの設定・履歴・フィルタ情報を保持・管理
🔸 クロスカッティングな仕組み
✅ 認証・セッション
- セッション + Cookie ベースのユーザー管理
- ゲストと登録ユーザーを自動判定
- セッションタイムアウト処理も導入可能
✅ ログ管理
- サーバーサイドにログファイル出力機能を実装可
- Pythonログ(データ取得ログ)、PHPログ(APIアクセス履歴)を記録
✅ アプリ設定
- config.php などでDB接続/RSSソース切り替え/デバッグON/OFFなど管理
🔁 通信フロー(リクエスト〜表示まで)
- ユーザーリクエスト:
- ユーザーが
index.php
にアクセス - HTML/CSS/JS をロード
- ユーザーが
- 初期データ取得:
main.js
によりapi.php?action=init
が呼び出され、カテゴリ・初期記事を取得
- 記事描画:
- JSがレスポンスを受け取り、記事一覧を構築(HTML生成+差し込み)
- 操作とイベント処理:
- ユーザーがスクロールやカテゴリをクリック
- 非同期で追加読み込み(
fetch
)
- 履歴保存:
- 記事をクリックすると
save_history.php
にPOST - サーバーで
user_article_history
に保存
- 記事をクリックすると
🌀 非同期処理とUX向上の工夫
async/await
を活用した自然なデータ取得- スクロール最下部で追加読み込み(無限スクロール)
- 操作中も処理をブロックしないUX設計
- 画面更新は最小限(DOM差し替えのみ)
✅ 拡張性のある設計
このアーキテクチャの最大のメリットは**「切り離し可能な構成」**です。
- バックエンドだけLaravelやFastAPIに差し替える
- フロントエンドをVue.jsやReactに置き換える
- データ収集をScrapyなどに変える
- PostgreSQLやSQLiteにも対応可能
また、RSSソースを別サイトに変えたり、YouTubeのAPIを使って動画ニュースを統合するといった発展も簡単です。
第4章:使用技術スタックと構成ファイル解説
■ 使用言語とツール一覧
領域 | 使用技術 |
---|---|
フロント | HTML / CSS / JavaScript(純粋) |
バックエンド | PHP(データ取得、認証など) |
バッチ処理 | Python(記事の取得・パース・DB登録) |
データベース | MySQL(ユーザー情報・履歴・記事保存) |
UI設計 | メディアクエリベースのCSS(スマホ対応) |
その他 | GitHub Pages / XAMPP / ローカル実行対応 |
■ ファイル構成(プロジェクトルート)
コピーnews_app/
│
├── index.php # メインページ(HTML/フロントエンド表示)
├── api.php # バックエンドAPI(リクエスト処理)
├── config.php # PHP設定(DB接続情報など)
├── config.ini # Python設定ファイル(記事取得用)
├── .htaccess # Apacheサーバー設定ファイル
│
├── js/
│ └── main.js # フロントエンドJavaScript処理
│
├── images/
│ └── no-image.png # サムネイル未設定時の代替画像
│
├── css/
│ └── style.css # スタイルシート(index.phpに埋め込み)
│
├── scripts/
│ └── fetch_articles.py # はてなブックマーク記事取得スクリプト
│
└── logs/ # ログディレクトリ
├── app.log # アプリケーションログ
└── php_errors.log # PHPエラーログ
■ フロントエンド関連
1. index.php
- 役割:ユーザーが最初にアクセスする、ニュースアプリのUI全体を構成する中心ファイル。
- 主な機能:
- HTML・CSS・JavaScriptの基本構造を定義
- 記事カードの一覧表示
- カテゴリータブ、閲覧履歴モーダルの設計
- メディアクエリによるスマホ対応レスポンシブデザイン
2. js/main.js
- 役割:ニュースの読み込み・UI操作・履歴管理など、動的挙動すべてを司るJSファイル。
- 主な処理:
- REST APIとの通信(fetch)
- DOM操作(記事レンダリング、カテゴリ切り替えなど)
- イベントハンドラ(クリック、スクロール、モーダル開閉)
- ユーザー設定の保存(localStorage)
- 記事閲覧履歴の記録と表示
■ バックエンド関連
3. api.php
- 役割:フロントエンドとデータベースの橋渡しを行うRESTful APIハブ。
- 主な機能:
- ユーザー登録/ログイン/ログアウト(セッション管理)
- 記事一覧・カテゴリー取得、履歴の保存・取得
GET
/POST
に応じた分岐で各種操作に対応- JSON形式でフロントにレスポンスを返す
4. config.php
- 役割:アプリ全体の設定ファイル
- 主な内容:
- データベース接続情報(ホスト名、ユーザー名、パスワードなど)
- アプリのルートパス、タイムゾーン設定
- エラー出力の有効化(開発用)
- セキュリティ上の定数設定(例:CSRFトークンなど)
5. scripts/fetch_articles.py
- 役割:Python製のRSS収集バッチスクリプト
- 主な処理:
- はてなブックマークのRSSを定期取得
- 記事タイトル、URL、サムネイル、コメント数等をパース
- カテゴリー分類ロジックに従ってMySQLに保存
- cronやタスクスケジューラで定期実行可能
■ サーバー設定
6. .htaccess
- 役割:Apache用設定ファイル
- 主な用途:
- サブディレクトリでの正しいルーティング処理
- 404ページや403ページのカスタム設定
- ファイルのキャッシュ設定
- セキュリティ(ディレクトリ一覧の非表示など)
主要機能の具体的な実装構造
次に、アプリが提供する5つの機能について、裏側の処理フローも含めて紹介します。
1. 記事表示機能
- 処理の流れ:
api.php
のgetArticles()
関数で記事データを取得main.js
のloadArticles()
がAPIを叩いてJSON受け取りrenderArticles()
関数でDOMにニュースを出力(カード形式)
2. カテゴリー管理機能
- 処理の流れ:
api.php
のgetCategories()
でカテゴリ一覧取得- ユーザーの選好は
updateCategoryPreferences()
で保存 - フロント側は
renderCategoryTabs()
でUI表示
3. ユーザー管理機能(登録・認証・セッション)
- 処理の流れ:
- ユーザー登録 →
registerUser()
(DBにINSERT) - ログイン →
loginUser()
(セッション発行) - ログアウト →
logoutUser()
(セッション破棄)
- ユーザー登録 →
- ゲストユーザーは制限付きで使用可能(履歴非保存など)
4. 閲覧履歴機能
- 保存:
- 記事カードのクリックイベントで、
main.js
がsaveArticleHistory()
をAjax送信
- 記事カードのクリックイベントで、
- 取得・表示:
getArticleHistory()
で該当ユーザーの履歴を取得- モーダル内にレンダリング(最近見た記事一覧)
5. 記事収集処理(RSS)
- 使用スクリプト:
scripts/fetch_articles.py
- フロー:
- RSS XMLを取得(
requests
ライブラリ) - 各記事のタイトル、リンク、概要、画像URLを抽出
- テキスト分類ロジックでカテゴリ分類
- MySQLに挿入(既存チェックあり)
- RSS XMLを取得(
補足:すべての機能は**「最小構成」+「最大拡張性」**で作られている
このプロジェクトの方針はシンプルです。
「今使える最小構成でまず動かし、必要に応じてガンガン拡張する」
だからこそ、
- 初心者はそのまま使える
- 中級者は改造して楽しめる
- 上級者は再構築して活用できる
そんな“育てられるOSS”に育っています。
第5章:主な機能と実装方法
【DB構造】
-- ユーザーテーブル
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE,
password VARCHAR(255),
-- ハッシュ化されたパスワード
email VARCHAR(100) UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_login TIMESTAMP NULL,
is_guest BOOLEAN DEFAULT FALSE
);
-- カテゴリーテーブル
CREATE TABLE categories (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
slug VARCHAR(50) NOT NULL UNIQUE,
is_default BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 記事テーブル
CREATE TABLE articles (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
url VARCHAR(255) NOT NULL UNIQUE,
description TEXT,
thumbnail_url VARCHAR(255),
source_site VARCHAR(100),
bookmark_count INT DEFAULT 0,
published_at TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 記事とカテゴリーの関連付けテーブル
CREATE TABLE article_categories (
article_id INT,
category_id INT,
PRIMARY KEY (article_id, category_id),
FOREIGN KEY (article_id) REFERENCES articles(id) ON DELETE CASCADE,
FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE CASCADE
);
-- ユーザーのカテゴリー設定テーブル
CREATE TABLE user_category_preferences (
user_id INT,
category_id INT,
is_visible BOOLEAN DEFAULT TRUE,
display_order INT DEFAULT 0,
PRIMARY KEY (user_id, category_id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE CASCADE
);
-- ユーザーの記事閲覧履歴テーブル
CREATE TABLE user_article_history (
user_id INT,
article_id INT,
viewed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id, article_id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (article_id) REFERENCES articles(id) ON DELETE CASCADE
);
-- ユーザーのカスタムカテゴリーテーブル
CREATE TABLE user_custom_categories (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
name VARCHAR(50) NOT NULL,
display_order INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
-- デフォルトカテゴリーの作成
INSERT INTO
categories (name, slug, is_default)
VALUES
('総合', 'general', TRUE),
('テクノロジー', 'technology', TRUE),
('エンタメ', 'entertainment', TRUE),
('ビジネス', 'business', TRUE),
('スポーツ', 'sports', TRUE),
('科学', 'science', TRUE),
('健康', 'health', TRUE),
('ライフスタイル', 'lifestyle', TRUE);
5-1. ユーザー登録・ログイン機能(PHP+MySQL)
【ポイント】
- セッションベースでログイン管理
- パスワードは
password_hash()
で暗号化 - 登録・ログイン時に簡単なバリデーションを実装
【処理概要】
- api.php:ユーザー名+パスワードを受け取って登録
- api.php:認証チェックしてセッション発行
- api.php:ログイン済みでなければリダイレクト
5-2. 閲覧履歴保存と取得(MySQL+Ajax)
【ポイント】
- ユーザーがニュースをクリックした時点でAjax送信
save_history.php
がDBに記事タイトル・URL・時刻を保存
【クライアント側(JS)】
document.querySelectorAll('.news-link').forEach(link => {
link.addEventListener('click', e => {
fetch('save_history.php', {
method: 'POST',
body: new URLSearchParams({
title: link.dataset.title,
url: link.href
})
});
});
});
5-3. 無限スクロール(JS)
【ポイント】
IntersectionObserver
API を活用して、スクロール最下部で自動取得- ページングパラメータを使い、同じPythonスクリプトを何度も叩く
【JSコード例】
let page = 1;
let observer = new IntersectionObserver(entries => {
if (entries[0].isIntersecting) {
fetch(`get_feed.py?page=${page++}`)
.then(res => res.json())
.then(addToDOM);
}
});
observer.observe(document.querySelector('#loadTrigger'));
5-4. スマホ対応レイアウト(CSS)
【ポイント】
- メディアクエリのみで対応(CSSフレームワーク不使用)
- 画面幅600px以下でフォントやマージンを調整
【CSS例】
@media (max-width: 600px) {
.news-container {
padding: 10px;
font-size: 0.9em;
}
}
第6章:カスタマイズ方法の紹介
このアプリの魅力のひとつは、**とことん「改造しやすい」**という点です。
フレームワークを使っていないので、特定の規約に縛られることもありません。
ここでは、よくあるカスタマイズの例を紹介します。
■ 6-1. 表示するRSSフィードを変える
RSSの取得は fetch_articles.py
で行っているため、ここに任意のRSS URLを追加すればOKです。
# 人気記事を取得するカテゴリのリスト
categories = [
{"name": "総合", "url": "https://b.hatena.ne.jp/hotentry.rss"},
{"name": "テクノロジー", "url": "https://b.hatena.ne.jp/hotentry/it.rss"},
{"name": "エンタメ", "url": "https://b.hatena.ne.jp/hotentry/entertainment.rss"},
{"name": "ビジネス", "url": "https://b.hatena.ne.jp/hotentry/economics.rss"},
{"name": "スポーツ", "url": "https://b.hatena.ne.jp/hotentry/game.rss"},
{"name": "科学", "url": "https://b.hatena.ne.jp/hotentry/knowledge.rss"},
{"name": "健康", "url": "https://b.hatena.ne.jp/hotentry/life.rss"},
{"name": "ライフスタイル", "url": "https://b.hatena.ne.jp/hotentry/guide.rss"} # guide.rssに変更
]
企業内イントラのRSS、業界特化のメディアなどももちろんOK。
「自分の情報源だけに絞ったニュースアプリ」がすぐ完成します。
■ 6-2. UIテーマを自分好みに変更
style.css
は完全に自由設計。たとえば「ダークモード化」は以下のようにできます。
body {
background-color: #121212;
color: #f1f1f1;
}
a {
color: #ff9800;
}
CSS変数やテーマ切替機能を追加すれば、ダーク/ライトもボタン一つで切り替え可能になります。
第7章:GitHubでの導入方法とコントリビュートの呼びかけ
■ クローン方法(ローカル実行)
git clone https://github.com/Yuusuke9228/news_app.git
cd news_app
php -S localhost:8080
# または
python3 -m http.server 8080
その後、ブラウザで http://localhost:8080/index.php
にアクセスすれば即動作。
MySQLを有効にしたい場合は、db/
のテーブル定義をインポートしてください。
■ PR・Issue歓迎!
バグ報告・機能リクエスト・改善提案など、どんな小さなことでも大歓迎です。
例:
- RSS更新間隔を変えたい
- モバイルのUIを改善したい
- ログインをJWTで書き直したい
- 外部APIと連携したい(ChatGPT等)
→ ぜひGitHubリポジトリにアクセスして、Star・Fork・PRをお願いします!
第8章:今後の課題とアップデート構想
需要がありそうなら下記を実装しようかと考えています。
下記に挙げた内容はどれも即、実装できるくらい簡単な内容で1日もあれば全て実装できます。
● 課題
- RSS取得の失敗時のハンドリングが甘い
- ダークモード未対応
- 複数ユーザーでの同時アクセス時の挙動検証不足
- セキュリティ面(XSS対策など)も今後強化必要
● やりたいこと
- タグ/カテゴリ別フィルタリング
- お気に入り/ブックマーク機能
- 閲覧傾向によるパーソナライズ
- 動画ニュース対応(YouTube埋め込みなど)
- 通知機能(Web Push APIなど)
どれも「拡張性がある設計」にしてあるので、少しずつ育てていく予定です。
第9章:まとめ 〜ニュースは”自分で選ぶ時代”へ〜
このアプリは、以下のような人におすすめです:
- 大手ニュースアプリに疲れている人
- 情報を「自分で選びたい」と思っている人
- 軽くて速いニュースアプリを探している人
- OSSで学びたい・貢献したい人
- 技術学習の一環で実用的なサンプルが欲しい人
「ニュースを見る」から「ニュースアプリを育てる」へ。
あなたもぜひ、自分だけのニュースアプリを作ってみませんか?
▶ GitHubはこちら
https://github.com/Yuusuke9228/news_app
StarやFork、Issueの投稿お待ちしています!