操作
バグ #227
未完了[Task4] Redmine統合機能実装 - ニュース⇄チケット連携
ステータス:
新規
優先度:
通常
担当者:
-
開始日:
2025-06-04
期日:
進捗率:
0%
予定工数:
説明
Task 4: Redmine統合機能実装¶
概要¶
ニュース機能とRedmineの統合機能を実装し、ニュースからチケット作成・関連チケット表示機能を提供する
作業ディレクトリ¶
/home/ito/task2-service/
実装ファイル構成¶
├── api/services/
│ └── redmineService.js # Redmine API統合
├── ui/src/components/redmine/
│ ├── RedmineIntegration.jsx # Redmine統合UI
│ ├── TicketCreator.jsx # チケット作成
│ ├── RelatedTickets.jsx # 関連チケット表示
│ └── index.js
├── ui/src/hooks/
│ └── useRedmine.js # Redmine統合フック
└── ui/src/services/
└── redmineAPI.js # Redmine APIクライアント
実装仕様¶
1. Redmine API統合サービス¶
// api/services/redmineService.js
class RedmineService {
constructor() {
this.baseURL = 'https://call2arm.com';
this.apiKey = 'feb66d81a5f4ff9c585ce30fce2ac06e0554aec6';
}
// ニュースからチケット作成
async createTicketFromNews(newsItem) {
const ticketData = {
issue: {
project_id: 1,
subject: `ニュース対応: ${newsItem.title}`,
description: this.formatNewsDescription(newsItem),
tracker_id: 1, // 機能
priority_id: 2, // 通常
custom_fields: [
{ id: 1, value: newsItem.url }, // ニュースURL
{ id: 2, value: newsItem.source } // ニュースソース
]
}
};
return this.createIssue(ticketData);
}
// 関連チケット検索
async searchRelatedTickets(newsTitle) {
const keywords = this.extractKeywords(newsTitle);
return this.searchIssues({
subject: keywords.join(' OR '),
limit: 10
});
}
}
2. React統合コンポーネント¶
// ui/src/components/redmine/RedmineIntegration.jsx
const RedmineIntegration = ({ news }) => {
const { createTicket, relatedTickets, loading } = useRedmine();
const handleCreateTicket = async () => {
try {
const ticket = await createTicket(news);
toast.success(`チケット #${ticket.id} を作成しました`);
} catch (error) {
toast.error('チケット作成に失敗しました');
}
};
return (
<div className="line-card p-4 mt-4">
<h3 className="line-heading text-lg mb-3">Redmine連携</h3>
{/* チケット作成ボタン */}
<button
onClick={handleCreateTicket}
className="line-btn-primary mb-4"
disabled={loading}
>
{loading ? 'チケット作成中...' : 'チケットを作成'}
</button>
{/* 関連チケット表示 */}
<RelatedTickets tickets={relatedTickets} />
</div>
);
};
3. API統合エンドポイント¶
// api/routes/news.js に追加
// ニュースからチケット作成
router.post('/:id/redmine', async (req, res) => {
try {
const news = await getNewsById(req.params.id);
const ticket = await redmineService.createTicketFromNews(news);
res.json({
success: true,
data: {
ticket: ticket.issue,
news: news
}
});
} catch (error) {
res.status(500).json({
success: false,
error: error.message
});
}
});
// 関連チケット取得
router.get('/:id/redmine/related', async (req, res) => {
try {
const news = await getNewsById(req.params.id);
const tickets = await redmineService.searchRelatedTickets(news.title);
res.json({
success: true,
data: tickets
});
} catch (error) {
res.status(500).json({
success: false,
error: error.message
});
}
});
4. カスタムフック実装¶
// ui/src/hooks/useRedmine.js
import { useState, useCallback } from 'react';
import { redmineAPI } from '../services/redmineAPI';
export const useRedmine = () => {
const [loading, setLoading] = useState(false);
const [relatedTickets, setRelatedTickets] = useState([]);
const createTicket = useCallback(async (newsItem) => {
setLoading(true);
try {
const response = await redmineAPI.createTicketFromNews(newsItem);
return response.data.ticket;
} finally {
setLoading(false);
}
}, []);
const searchRelatedTickets = useCallback(async (newsId) => {
const response = await redmineAPI.getRelatedTickets(newsId);
setRelatedTickets(response.data);
}, []);
return {
loading,
relatedTickets,
createTicket,
searchRelatedTickets
};
};
成果物¶
- RedmineService クラス実装
- RedmineIntegration コンポーネント
- TicketCreator コンポーネント
- RelatedTickets コンポーネント
- useRedmine カスタムフック
- API エンドポイント統合
- エラーハンドリング実装
機能要件¶
チケット作成機能¶
- ニュース情報をRedmineチケットとして作成
- カスタムフィールド活用 (URL、ソース等)
- プロジェクト・トラッカー・優先度設定
- 成功/失敗フィードバック
関連チケット表示¶
- ニュースタイトルベースのキーワード検索
- 関連度順ソート
- チケット詳細プレビュー
- 直接Redmineリンク
UI統合¶
- ニュースカード内統合表示
- モーダル・サイドパネル対応
- ローディング状態表示
- エラーメッセージ表示
テスト項目¶
# チケット作成API
curl -X POST http://localhost:3002/api/news/123/redmine
# 関連チケット取得
curl http://localhost:3002/api/news/123/redmine/related
# UI統合テスト
# - チケット作成ボタン動作
# - 関連チケット表示
# - エラーハンドリング
セキュリティ要件¶
- API Key適切な管理
- CORS設定確認
- 入力値サニタイズ
- 認証・認可確認
完了条件¶
- Redmine API統合完了
- チケット作成機能動作確認
- 関連チケット検索動作確認
- UI統合完了
- エラーハンドリング確認
- セキュリティ要件確認
表示するデータがありません
操作