📊 データベース設計ドキュメント
このドキュメントでは、ログ解析機能のDBスキーマと実装方針についてまとめてるよ!✨
🛠️ 技術スタック
| 項目 | 選定 |
|---|---|
| DB | SQLite (better-sqlite3) |
| ORM | なし(生SQL) |
| 配置場所 | Electronメインプロセス(electron/database.ts) |
| アクセス | IPC経由でRendererから呼び出し |
📁 テーブル設計
1. matches - 試合テーブル
| カラム名 | 型 | 説明 |
|---|---|---|
id | TEXT PRIMARY KEY | 試合ID(log 由来は timestamp ベース、browser 由来は BattleId と同値) |
battle_id | TEXT, NULL 許可, UNIQUE(NULL 重複可) | 戦績サイト由来の BattleId。log 由来 match では NULL から始まり、saveBattleDetails で照合成功時に書き戻される(spec: data-integration-improvement A1) |
timestamp | TEXT | 試合開始日時(ISO8601) |
date | TEXT | 日付(YYYY-MM-DD形式) |
time | TEXT | 時刻(HH:MM:SS形式、後付けマイグレーション) |
type | TEXT | 試合タイプ。log 由来は Rank_2v2 / Normal_1v1 等、browser 由来は mapBattleTypeId() 経由の 2v2 / 1v1 / Unknown(spec: data-integration-improvement A2) |
duration | INTEGER | 試合時間(秒) |
log_file | TEXT | 元ログファイルパス |
created_at | TEXT | DB登録日時 |
照合フォールバック階段 (BrowserAutomationService で battle_detail を保存する経路):
findMatchByBattleId(BattleId)—matches.battle_id直引き(決定的)findMatchByOpponentUids(opponents, StartTime)— 対戦相手 UID 集合一致 + 最近接時刻- それでも miss なら
saveBattleDetails(matchId 未指定)— 時刻 ±5 分窓 + UID 一致による UPDATE
2. players - プレイヤー結果テーブル
基本カラム
| カラム名 | 型 | 説明 |
|---|---|---|
id | INTEGER PRIMARY KEY | 自動採番ID |
match_id | TEXT | 試合ID(FK: matches.id) |
uid | TEXT | プレイヤーUID |
name | TEXT | プレイヤー名 |
team | TEXT | チーム('A' or 'B') |
result | TEXT | 結果('Win' or 'Lose') |
character_id | INTEGER | 使用キャラID |
戦績詳細カラム(API連携時に取得)
| カラム名 | 型 | 説明 | 対応するJSON |
|---|---|---|---|
kill_count | INTEGER | 撃破数 | BattleInfo.BeatCnt |
death_count | INTEGER | 被撃破数 | BattleInfo.BeatedCnt |
damage | INTEGER | 与ダメージ | BattleInfo.ExportDamage |
score_before | INTEGER | 試合前スコア | UserInfo.ScoreBefore |
score_after | INTEGER | 試合後スコア | UserInfo.ScoreAfter |
is_mvp | INTEGER | MVP判定(0/1) | UserInfo.IsMvp |
rank_id | INTEGER | 段位ID | UserInfo.DaDuanId |
awake_kill_count | INTEGER | 覚醒撃破数 | BattleInfo.BeatAwakeCnt |
friendly_kill_count | INTEGER | 味方撃破数 | BattleInfo.BeatFreidnCnt |
debuff_clear_count | INTEGER | デバフ解除数 | BattleInfo.Debarrass |
avatar_url | TEXT | アバターURL | UserInfo.Avatar |
注記:
- ログ解析データには戦績詳細情報(スコア、K/D/A等)が含まれないため、これらのカラムはNULL許容
- ブラウザ自動化機能でAPI連携時に取得・更新される
3. bans - BANテーブル
| カラム名 | 型 | 説明 |
|---|---|---|
id | INTEGER PRIMARY KEY | 自動採番ID |
match_id | TEXT | 試合ID(FK: matches.id) |
character_id | INTEGER | BANされたキャラID |
banner_uid | TEXT | BANしたプレイヤーUID |
banner_name | TEXT | BANしたプレイヤー名 |
team | TEXT | チーム('A' or 'B') |
4. picks - ピックテーブル
| カラム名 | 型 | 説明 |
|---|---|---|
id | INTEGER PRIMARY KEY | 自動採番ID |
match_id | TEXT | 試合ID(FK: matches.id) |
character_id | INTEGER | ピックされたキャラID |
player_uid | TEXT | プレイヤーUID |
player_name | TEXT | プレイヤー名 |
team | TEXT | チーム('A' or 'B') |
is_candidate_fallback | INTEGER | 候補絞り込み fallback で決まった Pick かどうか(0/1)。UI でバッジ表示。spec: A8 |
candidate_character_ids | TEXT JSON | fallback 時の候補キャラ ID 配列。UI で「候補: A, B, C」と表示。 |
5. log_files - ログファイル管理テーブル
| カラム名 | 型 | 説明 |
|---|---|---|
id | INTEGER PRIMARY KEY | 自動採番ID |
file_path | TEXT UNIQUE | ログファイルパス |
file_name | TEXT | ファイル名 |
file_size | INTEGER | ファイルサイズ(bytes) |
match_count | INTEGER | 検出した試合数 |
imported_at | TEXT | インポート日時 |
status | TEXT | ステータス('pending', 'imported', 'error') |
🔌 IPC API設計
ログ解析・インポート系
typescript
// ログファイルを解析してDBに保存
db.analyzeAndSaveLog(filePath: string, myUid?: string): Promise<AnalysisResult>
// 解析済みログ一覧を取得
db.getLogFiles(): Promise<LogFileInfo[]>
// ログファイルを削除(関連試合データも削除)
db.deleteLogFile(fileId: number): Promise<void>試合データ取得系
typescript
// 試合一覧を取得(フィルタ・ページング対応)
db.getMatches(options?: GetMatchesOptions): Promise<MatchData[]>
// 試合詳細を取得
db.getMatchDetail(matchId: string): Promise<MatchWithDetails | null>統計データ取得系
typescript
// プレイヤー統計を取得
db.getPlayerStats(uid?: string): Promise<PlayerStats[]>
// キャラ統計を取得
db.getCharacterStats(type?: 'pick' | 'ban'): Promise<CharacterStats[]>
// ダッシュボードサマリーを取得
db.getDashboardSummary(uid?: string): Promise<DashboardSummary>
// 勝率推移を取得
db.getWinRateTrend(uid: string, days?: number): Promise<WinRateTrend[]>📂 ファイル構造
src/
components/
control/
LogAnalysisTab.tsx # ログ解析タブUI(新規)
LogFileList.tsx # ログファイル一覧(新規)
MatchList.tsx # 試合一覧(新規)
MatchDetail.tsx # 試合詳細(新規)
StatsDashboard.tsx # 統計ダッシュボード(新規)
utils/
logAnalyzer/
index.ts # フロント用ログ解析ユーティリティ
types.ts # 共通型定義
LogParser.ts # ログパーサー(analyze-logから移植)
StatisticsCalculator.ts # 統計計算(analyze-logから移植)
electron/
database.ts # SQLite DB操作(拡張)
preload.ts # IPC公開(拡張)
main.ts # IPCハンドラ登録(拡張)🔄 処理フロー
ログインポートフロー
1. ユーザーがログファイルを選択
2. フロント: ファイル読み込み → LogParser で解析(プレビュー表示)
3. ユーザーが「インポート」ボタンを押す
4. フロント→IPC→メイン: 解析結果をDBに保存
5. DB: matches, players, bans, picks, log_files に INSERT
6. 完了通知をフロントに返す統計表示フロー
1. ユーザーが「統計」タブを開く
2. フロント→IPC→メイン: getDashboardSummary(uid) を呼び出し
3. DB: 集計クエリを実行
4. 結果をフロントに返す → グラフ/テーブル表示戦績詳細取得フロー(ブラウザ自動化)
1. 試合終了を検出(リアルタイムログ監視 or 手動トリガー)
2. BrowserAutomationService: ブラウザを起動してログイン
3. 戦績ページ(battle/index)に遷移
4. battle_list API レスポンスをキャプチャ
5. 最新試合の battle_detail ページに遷移
URL: /pages/record/vs[BattleType]-detail/index?BattleId=...&...
6. battle_detail API レスポンスをキャプチャ
7. DB: 既存の players レコードを UPDATE(戦績詳細カラムを埋める)
8. フロントエンドに通知 → UI更新データソースの違い:
- ログ解析: 試合基本情報、チーム構成、BAN/PICK、勝敗のみ
- API連携: 上記 + K/D/A、ダメージ、スコア変動、MVP等の詳細戦績
🎯 今後の拡張候補
ログ解析機能
- [ ] キャラ別勝率の可視化(グラフ)
- [ ] 特定プレイヤーとの対戦履歴
- [ ] ログの自動監視・自動インポート
- [ ] データエクスポート機能(CSV/JSON)
戦績詳細機能(API連携)
- [x] playersテーブルに戦績詳細カラムを追加
- [ ] K/D/A統計の計算・表示
- [ ] スコア推移グラフ
- [ ] 平均ダメージ・MVP率の表示
- [ ] 試合終了後の自動データ取得
迷ったことあったら、あーしに聞いてね💖