577 lines
15 KiB
Markdown
577 lines
15 KiB
Markdown
# Posimai Brain プロジェクト: 実装ロードマップ
|
||
|
||
**作成日**: 2026-02-23
|
||
**目的**: Chrome 100タブ問題の解決 + AI自動整理システム
|
||
**方針**: 段階的実装、最小構成から開始
|
||
|
||
---
|
||
|
||
## 🎯 **プロジェクト目標**
|
||
|
||
### **解決したい課題**
|
||
|
||
1. **情報の洪水**
|
||
- Chrome 100タブ常時開きっぱなし
|
||
- Slack DM / LINE Keepへの手動転送
|
||
- カテゴリ分けなし → 必要な記事を探せない
|
||
|
||
2. **共同開発者との情報共有**
|
||
- 手動でURLを送る手間
|
||
- 文脈情報が欠落
|
||
- 過去の共有記事を探せない
|
||
|
||
3. **関連情報の取得**
|
||
- 記事を読んだ後、関連情報を手動で検索
|
||
- 最新動向のキャッチアップに時間がかかる
|
||
|
||
### **理想の状態**
|
||
|
||
```
|
||
スマホで気になる記事を見つける
|
||
↓
|
||
「共有」ボタン → 「Posimai Brain」選択 (1タップ)
|
||
↓
|
||
AIが自動で要約・カテゴリ分け・関連情報取得
|
||
↓
|
||
Synology Chatに通知 + ダッシュボードに蓄積
|
||
↓
|
||
共同開発者も自動で閲覧可能
|
||
```
|
||
|
||
---
|
||
|
||
## 🏗️ **3フェーズ実装計画**
|
||
|
||
### **Phase 1: データパイプライン構築(今週: 3-4時間)**
|
||
|
||
#### **目標**: Chromeタブを閉じられるようにする
|
||
|
||
#### **アーキテクチャ**
|
||
|
||
```
|
||
[スマホ共有]
|
||
↓
|
||
[iOS/Android ショートカット]
|
||
↓
|
||
[Vercel Webhook API] (無料枠)
|
||
↓
|
||
[PostgreSQL (Synology)]
|
||
↓
|
||
[Synology Chat 通知]
|
||
```
|
||
|
||
#### **実装タスク**
|
||
|
||
**Task 1.1: Synology PostgreSQL + Chat セットアップ (30分)**
|
||
|
||
```bash
|
||
# SSH接続
|
||
ssh admin@100.76.7.3
|
||
|
||
# PostgreSQL起動(既存docker-compose.ymlを使用)
|
||
cd /volume1/docker/posimai-stack
|
||
nano docker-compose.yml
|
||
```
|
||
|
||
**追加サービス**:
|
||
```yaml
|
||
services:
|
||
# 既存のpostgres, redisに追加
|
||
|
||
# Posimai Brain用テーブル初期化
|
||
postgres_init:
|
||
image: postgres:16-alpine
|
||
depends_on:
|
||
postgres:
|
||
condition: service_healthy
|
||
volumes:
|
||
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
|
||
environment:
|
||
PGPASSWORD: ${POSTGRES_PASSWORD}
|
||
command: >
|
||
psql -h postgres -U posimai -d posimai_db -f /docker-entrypoint-initdb.d/init.sql
|
||
```
|
||
|
||
**init.sql**:
|
||
```sql
|
||
-- Posimai Brain テーブル
|
||
CREATE TABLE IF NOT EXISTS brain_articles (
|
||
id SERIAL PRIMARY KEY,
|
||
url TEXT NOT NULL UNIQUE,
|
||
title TEXT,
|
||
content TEXT,
|
||
summary TEXT,
|
||
category VARCHAR(50),
|
||
importance INT DEFAULT 0,
|
||
tags TEXT[],
|
||
related_urls TEXT[],
|
||
created_at TIMESTAMP DEFAULT NOW(),
|
||
updated_at TIMESTAMP DEFAULT NOW(),
|
||
shared_by VARCHAR(50) DEFAULT 'maita'
|
||
);
|
||
|
||
-- インデックス
|
||
CREATE INDEX idx_category ON brain_articles(category);
|
||
CREATE INDEX idx_created_at ON brain_articles(created_at DESC);
|
||
CREATE INDEX idx_tags ON brain_articles USING GIN(tags);
|
||
|
||
-- 全文検索用
|
||
CREATE INDEX idx_content_search ON brain_articles USING gin(to_tsvector('japanese', content));
|
||
```
|
||
|
||
**Synology Chat セットアップ**:
|
||
1. DSM → パッケージセンター → **Chat** インストール
|
||
2. Chat起動 → **統合** → **Incoming Webhook** 作成
|
||
3. Webhook URL をメモ: `https://your-synology.tail72e846.ts.net/webapi/entry.cgi?api=...`
|
||
|
||
**Task 1.2: Vercel Webhook API 作成 (1.5時間)**
|
||
|
||
```bash
|
||
# ローカルPCで実行
|
||
cd C:\Users\maita\posimai-project
|
||
mkdir posimai-brain-api
|
||
cd posimai-brain-api
|
||
npm init -y
|
||
npm install @vercel/node pg node-fetch
|
||
```
|
||
|
||
**api/save-article.js**:
|
||
```javascript
|
||
import { Pool } from 'pg';
|
||
|
||
const pool = new Pool({
|
||
host: process.env.DB_HOST,
|
||
port: 5432,
|
||
database: 'posimai_db',
|
||
user: 'posimai',
|
||
password: process.env.DB_PASSWORD,
|
||
ssl: false // Tailscale経由のため
|
||
});
|
||
|
||
export default async function handler(req, res) {
|
||
if (req.method !== 'POST') {
|
||
return res.status(405).json({ error: 'Method not allowed' });
|
||
}
|
||
|
||
const { url, source = 'mobile' } = req.body;
|
||
|
||
if (!url) {
|
||
return res.status(400).json({ error: 'URL required' });
|
||
}
|
||
|
||
try {
|
||
// Phase 1: URLのみ保存
|
||
const result = await pool.query(
|
||
'INSERT INTO brain_articles (url, title) VALUES ($1, $2) ON CONFLICT (url) DO NOTHING RETURNING id',
|
||
[url, `Article from ${source}`]
|
||
);
|
||
|
||
// Synology Chat通知
|
||
if (result.rows.length > 0) {
|
||
await fetch(process.env.SYNOLOGY_CHAT_WEBHOOK, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
text: `📌 新しい記事を保存しました\n${url}`
|
||
})
|
||
});
|
||
}
|
||
|
||
res.status(200).json({ success: true, id: result.rows[0]?.id });
|
||
} catch (error) {
|
||
console.error(error);
|
||
res.status(500).json({ error: error.message });
|
||
}
|
||
}
|
||
```
|
||
|
||
**vercel.json**:
|
||
```json
|
||
{
|
||
"version": 2,
|
||
"builds": [
|
||
{ "src": "api/**/*.js", "use": "@vercel/node" }
|
||
],
|
||
"env": {
|
||
"DB_HOST": "100.76.7.3",
|
||
"DB_PASSWORD": "@db-password",
|
||
"SYNOLOGY_CHAT_WEBHOOK": "@synology-chat-webhook"
|
||
}
|
||
}
|
||
```
|
||
|
||
**デプロイ**:
|
||
```bash
|
||
vercel --prod
|
||
# Secrets設定
|
||
vercel secrets add db-password "your_db_password"
|
||
vercel secrets add synology-chat-webhook "your_webhook_url"
|
||
```
|
||
|
||
**Task 1.3: スマホショートカット作成 (30分)**
|
||
|
||
**iOS (Shortcuts アプリ)**:
|
||
1. ショートカットアプリ起動
|
||
2. 新規ショートカット → 「入力を受け取る」
|
||
3. アクション追加:
|
||
- **URL の内容を取得** (入力: ショートカットの入力)
|
||
- **Web を取得**:
|
||
- URL: `https://your-vercel-app.vercel.app/api/save-article`
|
||
- メソッド: POST
|
||
- 本文: JSON `{"url": "ショートカットの入力"}`
|
||
- **通知を表示**: "記事を保存しました"
|
||
|
||
**Android (HTTP Shortcuts アプリ)**:
|
||
1. Google Playから「HTTP Shortcuts」インストール
|
||
2. 新規ショートカット作成:
|
||
- URL: `https://your-vercel-app.vercel.app/api/save-article`
|
||
- Method: POST
|
||
- Body: `{"url": "{url}"}`
|
||
- Share target: ON
|
||
|
||
**成功基準**:
|
||
- [ ] スマホから記事URLを共有 → ショートカット実行
|
||
- [ ] PostgreSQLにURLが保存される
|
||
- [ ] Synology Chatに通知が届く
|
||
- [ ] Chromeタブを閉じられる
|
||
|
||
---
|
||
|
||
### **Phase 2: AI知能統合(来週: 4-6時間)**
|
||
|
||
#### **目標**: 自動要約・カテゴリ分け・関連情報取得
|
||
|
||
#### **アーキテクチャ拡張**
|
||
|
||
```
|
||
[Vercel Webhook]
|
||
↓
|
||
[Article Scraper] (Vercel Functionまたはn8n)
|
||
↓
|
||
[Gemini API]
|
||
- 要約生成(3行)
|
||
- カテゴリ判定(技術/日本酒/本業/AI/その他)
|
||
- 重要度スコア(1-10)
|
||
- タグ抽出
|
||
- 関連情報検索
|
||
↓
|
||
[PostgreSQL 更新]
|
||
↓
|
||
[Synology Chat通知] - リッチ要約付き
|
||
```
|
||
|
||
#### **実装タスク**
|
||
|
||
**Task 2.1: Article Scraper追加 (2時間)**
|
||
|
||
**api/save-article.js 更新**:
|
||
```javascript
|
||
import { JSDOM } from 'jsdom';
|
||
import { Readability } from '@mozilla/readability';
|
||
|
||
async function scrapeArticle(url) {
|
||
const response = await fetch(url);
|
||
const html = await response.text();
|
||
const dom = new JSDOM(html, { url });
|
||
const reader = new Readability(dom.window.document);
|
||
const article = reader.parse();
|
||
|
||
return {
|
||
title: article.title,
|
||
content: article.textContent.slice(0, 5000), // 最初の5000文字
|
||
excerpt: article.excerpt
|
||
};
|
||
}
|
||
```
|
||
|
||
**Task 2.2: Gemini API統合 (2-3時間)**
|
||
|
||
```javascript
|
||
import { GoogleGenerativeAI } from '@google/generative-ai';
|
||
|
||
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
|
||
|
||
async function analyzeWithGemini(title, content) {
|
||
const model = genAI.getGenerativeModel({
|
||
model: 'gemini-2.0-flash-exp',
|
||
generationConfig: { responseMimeType: 'application/json' }
|
||
});
|
||
|
||
const prompt = `
|
||
以下の記事を分析してください:
|
||
|
||
タイトル: ${title}
|
||
本文: ${content}
|
||
|
||
以下のJSON形式で回答してください:
|
||
{
|
||
"summary": "3行要約(各行60文字以内)",
|
||
"category": "技術|日本酒|本業|AI|その他",
|
||
"importance": 1-10のスコア,
|
||
"tags": ["タグ1", "タグ2", "タグ3"],
|
||
"related_keywords": ["関連キーワード1", "関連キーワード2"]
|
||
}
|
||
`;
|
||
|
||
const result = await model.generateContent(prompt);
|
||
return JSON.parse(result.response.text());
|
||
}
|
||
```
|
||
|
||
**Task 2.3: Synology Chat通知拡張 (1時間)**
|
||
|
||
```javascript
|
||
// リッチ通知フォーマット
|
||
const chatMessage = {
|
||
text: `📰 **新しい記事**\n${analysis.category}`,
|
||
attachments: [{
|
||
title: article.title,
|
||
title_link: url,
|
||
text: analysis.summary,
|
||
color: getCategoryColor(analysis.category),
|
||
fields: [
|
||
{ title: '重要度', value: `${analysis.importance}/10`, short: true },
|
||
{ title: 'タグ', value: analysis.tags.join(', '), short: true }
|
||
]
|
||
}]
|
||
};
|
||
```
|
||
|
||
**成功基準**:
|
||
- [ ] URLから記事本文を自動取得
|
||
- [ ] Gemini APIで要約・カテゴリ・タグ生成
|
||
- [ ] PostgreSQLに全データ保存
|
||
- [ ] Synology Chatにリッチ通知
|
||
|
||
---
|
||
|
||
### **Phase 3: Posimai Dashboard作成(2週目: 1週間)**
|
||
|
||
#### **目標**: 検索・フィルタ・共有可能なWebダッシュボード
|
||
|
||
#### **技術スタック**
|
||
|
||
- **フレームワーク**: Flutter Web (日本酒アプリの知識流用)
|
||
- **デプロイ**: Vercel (または Synology Web Station)
|
||
- **API**: Vercel Serverless Functions
|
||
- **認証**: 簡易パスワード(共同開発者と共有)
|
||
|
||
#### **デザインシステム: Posimai UIテンプレ**
|
||
|
||
**カラーパレット** (日本酒アプリから流用):
|
||
```dart
|
||
// lib/theme/posimai_colors.dart
|
||
class PosimaiColors {
|
||
// メインカラー: 和風トーン
|
||
static const primary = Color(0xFF2C3E50); // 濃紺
|
||
static const accent = Color(0xFFD4A574); // 琥珀
|
||
static const background = Color(0xFFF5F1E8); // 和紙
|
||
|
||
// カテゴリ別カラー
|
||
static const tech = Color(0xFF3498DB); // 技術: 青
|
||
static const sake = Color(0xFFE74C3C); // 日本酒: 赤
|
||
static const business = Color(0xFF2ECC71); // 本業: 緑
|
||
static const ai = Color(0xFF9B59B6); // AI: 紫
|
||
static const other = Color(0xFF95A5A6); // その他: グレー
|
||
}
|
||
```
|
||
|
||
**コンポーネント構成**:
|
||
```
|
||
lib/
|
||
├── main.dart
|
||
├── theme/
|
||
│ ├── posimai_colors.dart
|
||
│ └── posimai_theme.dart
|
||
├── widgets/
|
||
│ ├── article_card.dart # 記事カード
|
||
│ ├── category_chip.dart # カテゴリチップ
|
||
│ ├── search_bar.dart # 検索バー
|
||
│ └── filter_drawer.dart # フィルタドロワー
|
||
├── screens/
|
||
│ ├── home_screen.dart # 記事一覧
|
||
│ ├── article_detail_screen.dart # 記事詳細
|
||
│ └── search_screen.dart # 検索画面
|
||
└── services/
|
||
├── api_service.dart # API通信
|
||
└── database_service.dart # ローカルキャッシュ
|
||
```
|
||
|
||
**主要機能**:
|
||
|
||
1. **記事一覧画面**
|
||
- カテゴリ別フィルタ
|
||
- 日付順・重要度順ソート
|
||
- 無限スクロール
|
||
|
||
2. **検索機能**
|
||
- 全文検索(PostgreSQL tsvector)
|
||
- タグ検索
|
||
- カテゴリ絞り込み
|
||
|
||
3. **記事詳細画面**
|
||
- 要約表示
|
||
- 元記事リンク
|
||
- 関連記事表示
|
||
- 共有ボタン(URL生成)
|
||
|
||
4. **ダークモード**
|
||
- システム設定連動
|
||
- 手動切り替え
|
||
|
||
#### **実装タスク**
|
||
|
||
**Task 3.1: Flutter Webプロジェクト作成 (2時間)**
|
||
|
||
```bash
|
||
cd C:\Users\maita\posimai-project
|
||
mkdir 01_active
|
||
cd 01_active
|
||
flutter create posimai_brain_dashboard --platforms=web
|
||
cd posimai_brain_dashboard
|
||
```
|
||
|
||
**Task 3.2: Posimai UIテンプレ実装 (1日)**
|
||
|
||
```dart
|
||
// lib/theme/posimai_theme.dart
|
||
ThemeData posimaiLightTheme = ThemeData(
|
||
useMaterial3: true,
|
||
colorScheme: ColorScheme.light(
|
||
primary: PosimaiColors.primary,
|
||
secondary: PosimaiColors.accent,
|
||
surface: PosimaiColors.background,
|
||
),
|
||
// ... 日本酒アプリのテーマを流用
|
||
);
|
||
```
|
||
|
||
**Task 3.3: API接続・記事一覧表示 (2日)**
|
||
|
||
```dart
|
||
// lib/services/api_service.dart
|
||
class ApiService {
|
||
static const baseUrl = 'https://your-vercel-app.vercel.app/api';
|
||
|
||
Future<List<Article>> getArticles({
|
||
String? category,
|
||
String? query,
|
||
int limit = 50,
|
||
}) async {
|
||
final response = await http.get(
|
||
Uri.parse('$baseUrl/articles').replace(queryParameters: {
|
||
if (category != null) 'category': category,
|
||
if (query != null) 'q': query,
|
||
'limit': limit.toString(),
|
||
}),
|
||
);
|
||
// ... JSONパース
|
||
}
|
||
}
|
||
```
|
||
|
||
**Task 3.4: Vercelデプロイ (30分)**
|
||
|
||
```bash
|
||
cd posimai_brain_dashboard
|
||
flutter build web --release
|
||
cd build/web
|
||
vercel --prod
|
||
```
|
||
|
||
**成功基準**:
|
||
- [ ] Flutter Webでダッシュボード表示
|
||
- [ ] カテゴリフィルタ動作
|
||
- [ ] 全文検索動作
|
||
- [ ] モバイル・デスクトップ対応
|
||
- [ ] ダークモード切替
|
||
- [ ] Vercelで公開
|
||
- [ ] 共同開発者がURLアクセス可能
|
||
|
||
---
|
||
|
||
## 🎨 **Posimai UIテンプレートの転用計画**
|
||
|
||
Phase 3で作成した **Posimai Dashboard Template** は以下に転用可能:
|
||
|
||
1. **テック管理ダッシュボード**
|
||
- GitHub連携
|
||
- 技術記事管理
|
||
|
||
2. **RFM分析ダッシュボード**
|
||
- 顧客データ可視化
|
||
- kintone連携(収益化案件用)
|
||
|
||
3. **香道アプリ管理画面**
|
||
- 香木データベース
|
||
- 履歴管理
|
||
|
||
**テンプレート共通コンポーネント**:
|
||
```
|
||
00_core/ui_components/
|
||
├── posimai_theme/ # カラー・テーマ定義
|
||
├── data_table.dart # データテーブル
|
||
├── chart_widget.dart # グラフ表示
|
||
├── export_button.dart # CSVエクスポート
|
||
└── auth_wrapper.dart # 簡易認証
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 **開発スケジュール**
|
||
|
||
| Week | フェーズ | タスク | 所要時間 | 成果物 |
|
||
|------|---------|--------|---------|--------|
|
||
| **Week 1** | Phase 1 | データパイプライン | 3-4h | Chromeタブ解放 |
|
||
| **Week 2** | Phase 2 | AI知能統合 | 4-6h | 自動要約・通知 |
|
||
| **Week 3-4** | Phase 3 | Dashboard作成 | 30-40h | 検索・共有可能UI |
|
||
|
||
**合計**: 40-50時間(2-3週間)
|
||
|
||
---
|
||
|
||
## 🎯 **成功指標**
|
||
|
||
### **Phase 1完了時**
|
||
- [ ] Chromeタブ100 → 10以下
|
||
- [ ] 1日5-10記事を自動保存
|
||
- [ ] Synology Chatで確認可能
|
||
|
||
### **Phase 2完了時**
|
||
- [ ] AI要約精度80%以上
|
||
- [ ] カテゴリ自動分類精度90%以上
|
||
- [ ] 情報収集時間50%削減
|
||
|
||
### **Phase 3完了時**
|
||
- [ ] 共同開発者が週1回以上アクセス
|
||
- [ ] 過去記事検索時間90%削減
|
||
- [ ] テンプレートを他プロジェクトに転用
|
||
|
||
---
|
||
|
||
## 🚀 **次のアクション**
|
||
|
||
### **今すぐ(今日)**
|
||
|
||
1. ✅ Synology Chat インストール
|
||
2. ✅ PostgreSQL テーブル作成
|
||
3. ✅ Incoming Webhook URL取得
|
||
|
||
### **今週中**
|
||
|
||
1. ⏳ Vercel API デプロイ
|
||
2. ⏳ スマホショートカット作成
|
||
3. ⏳ Phase 1 動作確認
|
||
|
||
### **来週**
|
||
|
||
1. ⏳ Gemini API統合
|
||
2. ⏳ AI自動要約テスト
|
||
3. ⏳ Phase 2 完成
|
||
|
||
---
|
||
|
||
**作成者**: Claude (Sonnet 4.5) + Antigravity + Gemini の総合判断
|
||
**方針**: 段階的実装、実用性優先、テンプレート化で横展開
|
||
|