docs: add server.js refactor plan for shared AI context
- 現状構造・セクション別行数・共有変数依存マップを記録 - 目標構造(lib/ + routes/ 分割案)を設計 - 実施タイミング判断基準・フェーズ別手順を記載 - CLAUDE.md / AGENTS.md の参照ドキュメントリストに追加 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e3e6ebca7d
commit
8fdc047b7f
|
|
@ -60,6 +60,7 @@ npm run deploy:dev # git push + scp + systemctl restart(git push だけでは
|
|||
| `docs/design-system.md` | カラートークン・デザインシステム |
|
||||
| `docs/new-app-guide.md` | 新規アプリ作成チェックリスト |
|
||||
| `docs/disaster-recovery.md` | PC 消失時の復元手順 |
|
||||
| `docs/server-refactor-plan.md` | server.js 分割設計・実施タイミング・手順 |
|
||||
| `posimai-dashboard/src/data/projects.json` | 全アプリのステータス・スタック |
|
||||
| `memory/MEMORY.md` | AI 記憶(変更後は claude-memory リポジトリへも push すること)|
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ npm run deploy:dev # git push + scp + systemctl restart(git push だけでは
|
|||
| `docs/design-system.md` | カラートークン・デザインシステム |
|
||||
| `docs/new-app-guide.md` | 新規アプリ作成チェックリスト |
|
||||
| `docs/disaster-recovery.md` | PC 消失時の復元手順 |
|
||||
| `docs/server-refactor-plan.md` | server.js 分割設計・実施タイミング・手順 |
|
||||
| `posimai-dashboard/src/data/projects.json` | 全アプリのステータス・スタック |
|
||||
| `memory/MEMORY.md` | AI 記憶(変更後は claude-memory リポジトリへも push すること)|
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,266 @@
|
|||
# server.js リファクタリング計画
|
||||
|
||||
最終更新: 2026-04-10
|
||||
対象: Claude Code / Cursor / Gemini / 全 AI エージェント
|
||||
|
||||
**このドキュメントは `server.js` の現状分析・分割設計・実施タイミング判断基準を一元管理します。
|
||||
リファクタリング作業を始める前に必ず読んでください。**
|
||||
|
||||
---
|
||||
|
||||
## 0. 現状サマリー
|
||||
|
||||
| 項目 | 内容 |
|
||||
|------|------|
|
||||
| ファイル | `/server.js`(リポジトリルート) |
|
||||
| 行数 | **3091行**(2026-04-10 計測) |
|
||||
| 役割 | VPS 上で動く Node.js/Express バックエンド。全アプリの API を1ファイルに集約 |
|
||||
| 問題 | テストが書けない・障害切り分けが困難・新機能追加のたびにファイルが肥大化 |
|
||||
| 状態 | **現時点では本番稼働中・障害なし。即時分割は不要。** |
|
||||
|
||||
---
|
||||
|
||||
## 1. 現在の内部構造(セクション別行数)
|
||||
|
||||
```
|
||||
server.js (3091行)
|
||||
├── L1–27 require / app 初期化
|
||||
├── L28–84 Auth helpers(WebAuthn dynamic import、インメモリレートリミッター)
|
||||
├── L85–126 JWT config + session helpers
|
||||
├── L127–173 Express middleware(CORS など)
|
||||
├── L174–260 DB pool (pg) + Gemini + API Key 認証マップ
|
||||
├── L261–481 共有ユーティリティ(extractSource、charset 正規化、SSRF guard、
|
||||
│ fetchMeta、fetchFullTextViaJina、analyzeWithGemini)
|
||||
├── L482–721 initDB(PostgreSQL スキーマ全定義 — 240行)
|
||||
├── L722–769 Express Router 生成 + /health
|
||||
│
|
||||
├── ── ルートグループ ─────────────────────────────────────────────
|
||||
├── L770–1106 Auth: Magic Link + session(337行)
|
||||
├── L926–1106 Auth: Google OAuth / GitHub OAuth(181行)※上記と連続
|
||||
├── L1107–1354 Auth: Passkey / WebAuthn(248行)
|
||||
│ 合計 Auth routes: 585行
|
||||
│
|
||||
├── L1355–1612 Brain articles(GET/POST/PATCH/DELETE + save + history = 258行)
|
||||
├── L1613–1685 Journal routes(posts + public + AI tag suggestion + upload = 170行)
|
||||
├── L1686–1782 Site Config routes(96行)
|
||||
├── L1783–1884 Habit routes(102行)
|
||||
├── L1885–1930 Pulse routes(46行)
|
||||
├── L1931–1967 Lens history routes(37行)
|
||||
│
|
||||
├── L1968–2118 Feed Media + Feed Articles routes(151行)
|
||||
├── L2119–2288 TTS(VOICEVOX)routes + サーバー側自動プリウォーム(170行)
|
||||
│
|
||||
├── L2289–2320 Events前処理(32行)
|
||||
├── L2321–2775 Together routes(groups / join / share / feed / comments / search = 455行)
|
||||
├── L2625–2775 Atlas proxy(GitHub / Vercel / Tailscale scan = 151行)※上記と連続
|
||||
│
|
||||
├── L2776–2884 Doorkeeper + connpass(app-level、router 外 = 109行)
|
||||
├── L2885–2889 静的ファイル(/uploads)
|
||||
├── L2891–2989 Stripe webhook(99行)
|
||||
│
|
||||
└── L2990–3091 router マウント + サーバー起動 + Feed 背景ジョブ(102行)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 共有変数の依存マップ
|
||||
|
||||
分割時に「どの変数をどのファイルに置くか」の判断基準。
|
||||
|
||||
| 変数 / 関数 | 宣言行 | 参照箇所数 | 参照元セクション |
|
||||
|------------|--------|-----------|----------------|
|
||||
| `pool` (pg Pool) | L174 | **108箇所** | 全ルートファイル |
|
||||
| `authMiddleware` | L197付近 | **46箇所** | 全認証必須ルート |
|
||||
| `genAI` (Gemini) | L191 | 2箇所 | brain.js のみ |
|
||||
| `webauthnChallenges` (Map) | L40 | 15箇所 | auth routes のみ |
|
||||
| `rateLimitStores` / `rateLimit()` | L51 | 多数 | auth routes 中心 |
|
||||
| `isSsrfSafe()` | L294 | 5箇所 | brain.js / together.js |
|
||||
| `fetchMeta()` | L304 | brain + together |
|
||||
| `fetchFullTextViaJina()` | L372 | brain + together |
|
||||
| `analyzeWithGemini()` | L416 | brain のみ |
|
||||
| `JWT_SECRET` | L86 | auth 全体 |
|
||||
| `WEBAUTHN_RP_*` | L92 | auth/passkey のみ |
|
||||
|
||||
**結論**: `pool` と `authMiddleware` を共有モジュールに切り出せば、残りのルート分割は機械的に行える。
|
||||
|
||||
---
|
||||
|
||||
## 3. 目標とする分割後の構造
|
||||
|
||||
```
|
||||
server.js ← 100行以内(エントリポイント + マウントのみ)
|
||||
lib/
|
||||
db.js ← pool + initDB をエクスポート
|
||||
auth.js ← JWT_SECRET / createToken / authMiddleware / session helpers
|
||||
rateLimit.js ← インメモリレートリミッター(webauthnChallenges も含める)
|
||||
fetch.js ← isSsrfSafe / fetchMeta / fetchFullTextViaJina / analyzeWithGemini
|
||||
routes/
|
||||
auth.js ← Magic Link + OAuth(Google/GitHub)+ Passkey/WebAuthn
|
||||
brain.js ← articles / save / history / AI 分析
|
||||
journal.js ← journal posts + site config
|
||||
habit.js ← habit + pulse + lens history
|
||||
feed.js ← feed media + feed articles + TTS + feed バックグラウンドジョブ
|
||||
together.js ← groups / join / share / comments / search
|
||||
events.js ← Doorkeeper + connpass(app-level も含めて統合)
|
||||
atlas.js ← GitHub / Vercel / Tailscale scan proxy
|
||||
stripe.js ← webhook のみ
|
||||
```
|
||||
|
||||
**各ファイルの想定行数**: 100–600行。神ファイルは完全に消える。
|
||||
|
||||
---
|
||||
|
||||
## 4. 実施タイミングの判断基準
|
||||
|
||||
### やらなくていい条件(すべて揃っている間は待つ)
|
||||
|
||||
- 本番で分割に起因する障害が出ていない
|
||||
- 新しいルートグループを追加する予定がない
|
||||
- 商用化タスク(Stripe 課金・ユーザー招待・モバイル)が残っている
|
||||
|
||||
### 開始するべきタイミング(どれか1つ該当したら着手)
|
||||
|
||||
| トリガー | 理由 |
|
||||
|---------|------|
|
||||
| **新ルートグループを追加するとき**(例: posimai-station の API) | 新ファイルを作るついでに既存も整理。追加コストがほぼゼロ |
|
||||
| **auth.js だけバグが続いて server.js 内のデバッグが辛い** | 問題のある1ルートだけ先に切り出す部分分割でも OK |
|
||||
| **Node.js バージョンアップや pg ライブラリ更新のとき** | どうせ動作確認が必要なので、そのタイミングで進める |
|
||||
| **server.js が 3500行を超えたとき** | 純粋に限界。この時点で強制着手 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 実施手順(着手するときはこの順番で)
|
||||
|
||||
### フェーズ 1: 共有レイヤーの切り出し(低リスク・1–2時間)
|
||||
|
||||
ルートは一切触らない。共有変数をモジュールに切り出すだけ。
|
||||
|
||||
```bash
|
||||
mkdir lib routes
|
||||
```
|
||||
|
||||
**lib/db.js**
|
||||
```js
|
||||
'use strict';
|
||||
const { Pool } = require('pg');
|
||||
|
||||
const pool = new Pool({
|
||||
host: process.env.DB_HOST || 'db',
|
||||
port: parseInt(process.env.DB_PORT || '5432'),
|
||||
user: process.env.DB_USER || 'gitea', // TODO: 'posimai' に変更
|
||||
password: process.env.DB_PASSWORD || '',
|
||||
database: 'posimai_brain',
|
||||
max: 15,
|
||||
idleTimeoutMillis: 30000,
|
||||
connectionTimeoutMillis: 5000,
|
||||
});
|
||||
pool.on('error', (err) => console.error('[DB] Unexpected pool error:', err.message));
|
||||
|
||||
async function initDB() { /* server.js L482–721 をそのまま移動 */ }
|
||||
|
||||
module.exports = { pool, initDB };
|
||||
```
|
||||
|
||||
**lib/auth.js**
|
||||
```js
|
||||
// JWT_SECRET, JWT_TTL_SECONDS, createToken, authMiddleware, session helpers
|
||||
module.exports = { JWT_SECRET, createToken, authMiddleware };
|
||||
```
|
||||
|
||||
**lib/rateLimit.js**
|
||||
```js
|
||||
// rateLimitStores, rateLimit(), webauthnChallenges, cleanup interval
|
||||
module.exports = { rateLimit, webauthnChallenges };
|
||||
```
|
||||
|
||||
**lib/fetch.js**
|
||||
```js
|
||||
// isSsrfSafe, fetchMeta, fetchFullTextViaJina, analyzeWithGemini, extractSource
|
||||
module.exports = { isSsrfSafe, fetchMeta, fetchFullTextViaJina, analyzeWithGemini };
|
||||
```
|
||||
|
||||
server.js 側の変更は `require` 置き換えのみ:
|
||||
```js
|
||||
const { pool, initDB } = require('./lib/db');
|
||||
const { authMiddleware } = require('./lib/auth');
|
||||
```
|
||||
|
||||
**動作確認**:
|
||||
```bash
|
||||
node server.js
|
||||
curl http://localhost:PORT/api/health
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### フェーズ 2: ルートの切り出し(中リスク・1ルート1PR)
|
||||
|
||||
**独立度が高い順(この順番で進める)**:
|
||||
|
||||
```
|
||||
1. routes/stripe.js 99行 依存: pool のみ。最も安全
|
||||
2. routes/atlas.js 151行 依存: なし(外部API プロキシのみ)
|
||||
3. routes/events.js 141行 依存: なし(外部API フェッチのみ)
|
||||
4. routes/together.js 455行 依存: pool + authMiddleware + isSsrfSafe
|
||||
5. routes/feed.js 321行 依存: pool + authMiddleware(feed job は起動後アタッチ)
|
||||
6. routes/habit.js 185行 依存: pool + authMiddleware
|
||||
7. routes/brain.js 258行 依存: pool + authMiddleware + fetch + genAI
|
||||
8. routes/journal.js 266行 依存: pool + authMiddleware
|
||||
9. routes/auth.js 585行 依存: webauthnChallenges + rateLimit(フェーズ1完了後)
|
||||
```
|
||||
|
||||
**各ルートファイルの形式**:
|
||||
```js
|
||||
'use strict';
|
||||
const { Router } = require('express');
|
||||
const { pool } = require('../lib/db');
|
||||
const { authMiddleware } = require('../lib/auth');
|
||||
// ...
|
||||
|
||||
const router = Router();
|
||||
router.get('/xxx', authMiddleware, async (req, res) => { ... });
|
||||
module.exports = router;
|
||||
```
|
||||
|
||||
**server.js でのマウント**:
|
||||
```js
|
||||
const stripeRouter = require('./routes/stripe');
|
||||
app.use('/brain/api/stripe', stripeRouter);
|
||||
app.use('/api/stripe', stripeRouter);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### フェーズ 2 の注意点(ハマりやすい箇所)
|
||||
|
||||
1. **feed バックグラウンドジョブ**(L2998–3091)は routes/feed.js に移すが、`startFeedJob()` の呼び出しは server.js の起動後に行う必要がある。`module.exports = { router, startFeedJob }` の形式にする。
|
||||
|
||||
2. **Doorkeeper / connpass の二重定義**(L2776–2884 が router 外の app-level)は events.js に統合し、router 内に移動する。`/brain/api/events/*` と `/api/events/*` の両マウントを忘れずに。
|
||||
|
||||
3. **auth routes の webauthnChallenges** は auth.js ルートファイルと lib/rateLimit.js(またはlib/auth.js)が共有するため、フェーズ1の lib 切り出し完了後でないと移動できない。必ずフェーズ1の後に行う。
|
||||
|
||||
---
|
||||
|
||||
## 6. やらないこと(スコープ外)
|
||||
|
||||
| 項目 | 理由 |
|
||||
|------|------|
|
||||
| TypeScript 化 | 全書き直しになる。現在の優先度では対費用効果が出ない |
|
||||
| テストコード追加 | 分割と同時にやると範囲が広がりすぎる。分割後の別タスク |
|
||||
| DB_USER: 'gitea' の修正 | サーバー側 PostgreSQL ユーザー変更が伴う。別タスク |
|
||||
| console.log 整理 | 分割と無関係。別タスク |
|
||||
| インメモリ state の永続化 | スキーマ変更が必要。別タスク(CLAUDE.md 要確認事項) |
|
||||
|
||||
---
|
||||
|
||||
## 7. 検討中の追加改善(分割後の次フェーズ候補)
|
||||
|
||||
- **DB_USER を 'gitea' から 'posimai' に変更**(PostgreSQL ユーザー作成が必要)
|
||||
- **webauthnChallenges / rateLimitStores の Redis 移行**(再起動耐性・スケール対応)
|
||||
- **console.log を構造化ログ(pino 等)に統一**
|
||||
- **ルートごとのエラーハンドリング統一**(現状は各ルートで個別 try/catch)
|
||||
|
||||
---
|
||||
|
||||
*このドキュメントは作業開始時・完了時に更新すること。*
|
||||
*分割を実施した AI は「フェーズ X 完了」「完了日」「担当 AI」を末尾に追記してください。*
|
||||
Loading…
Reference in New Issue