# データベース設計書

## 概要

本ドキュメントは、Wikipedia iOS アプリケーションで使用されるCoreDataデータベースの設計を記述したものです。本アプリケーションは複数のCoreDataモデルを使用しており、それぞれが異なる機能ドメインを担当しています。

- **Wikipedia（WMF Framework）**: 記事、リーディングリスト、コンテンツグループなどのメインデータモデル
- **WMFData**: 記事タブ、ページビュー、Year in Review機能のデータモデル
- **Cache**: 記事キャッシュ管理のデータモデル
- **RemoteNotifications**: リモート通知管理のデータモデル
- **EventPlatformEvents**: イベントプラットフォーム用のイベント記録データモデル
- **PersistentCache**: 永続キャッシュ管理のデータモデル

## テーブル一覧

| テーブル名 | 対応エンティティ | 説明 |
| --- | --- | --- |
| WMFArticle | WMFArticle | Wikipedia記事のメタデータを保存 |
| ReadingList | ReadingList | ユーザーのリーディングリスト |
| ReadingListEntry | ReadingListEntry | リーディングリストに含まれる記事エントリ |
| WMFContentGroup | WMFContentGroup | フィード用コンテンツグループ |
| WMFContent | WMFContent | コンテンツグループの詳細コンテンツ |
| WMFKeyValue | WMFKeyValue | キーバリューストア（汎用設定保存） |
| CDArticleTab | CDArticleTab | 記事タブ情報 |
| CDArticleTabItem | CDArticleTabItem | 記事タブ内のアイテム |
| CDPage | CDPage | ページ情報 |
| CDPageView | CDPageView | ページビュー履歴 |
| CDPageSavedInfo | CDPageSavedInfo | ページ保存情報 |
| CDCategory | CDCategory | ページカテゴリ |
| CDYearInReviewReport | CDYearInReviewReport | Year in Reviewレポート |
| CDYearInReviewSlide | CDYearInReviewSlide | Year in Reviewスライド |
| CacheGroup | CacheGroup | キャッシュグループ |
| CacheItem | CacheItem | キャッシュアイテム |
| PersistentCacheGroup | PersistentCacheGroup | 永続キャッシュグループ |
| PersistentCacheItem | PersistentCacheItem | 永続キャッシュアイテム |
| RemoteNotification | RemoteNotification | リモート通知 |
| WMFEPEventRecord | WMFEPEventRecord | イベントプラットフォームイベント記録 |

## 各テーブル定義

---

## Wikipediaモデル（WMF Framework）

### 1. WMFArticle

Wikipedia記事のメタデータを保存するメインエンティティです。記事の表示情報、閲覧履歴、保存状態、位置情報などを管理します。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| key | String | NO | 記事の一意識別キー（標準化されたURL形式） |
| variant | String | YES | 言語バリアント |
| displayTitle | String | YES | 記事の表示タイトル |
| displayTitleHTMLString | String | YES | HTML形式の表示タイトル（非推奨） |
| snippet | String | YES | 記事の抜粋テキスト |
| wikidataDescription | String | YES | Wikidataからの説明文 |
| wikidataID | String | YES | WikidataのID |
| pageID | Integer 64 | YES | MediaWikiのページID |
| ns | Integer 16 | YES | 名前空間（非推奨） |
| imageURLString | String | YES | オリジナル画像のURL |
| imageWidth | Integer 32 | YES | オリジナル画像の幅 |
| imageHeight | Integer 32 | YES | オリジナル画像の高さ |
| thumbnailURLString | String | YES | サムネイル画像のURL（非推奨） |
| savedDate | Date | YES | ユーザーが保存した日時 |
| viewedDate | Date | YES | 最後に閲覧した日時 |
| viewedDateWithoutTime | Date | YES | 閲覧日（時刻なし、履歴グループ化用） |
| viewedFragment | String | YES | 最後に閲覧したセクションフラグメント |
| viewedScrollPosition | Double | NO | 最後のスクロール位置（デフォルト: 0.0） |
| wasSignificantlyViewed | Boolean | NO | 十分な時間閲覧されたか（デフォルト: NO） |
| lastModifiedDate | Date | YES | 記事の最終更新日時 |
| isDownloaded | Boolean | NO | オフライン閲覧用にダウンロード済みか（デフォルト: NO） |
| downloadRetryDate | Date | YES | ダウンロード再試行可能日時 |
| downloadAttemptCount | Integer 16 | NO | ダウンロード試行回数（デフォルト: 0） |
| errorCodeNumber | Integer 32 | YES | ダウンロードエラーコード |
| isExcludedFromFeed | Boolean | NO | フィードから除外するか（デフォルト: NO） |
| isConversionFromMobileViewNeeded | Boolean | NO | モバイルビューからの変換が必要か（デフォルト: NO） |
| isSavedMigrated | Boolean | NO | 保存マイグレーション済みか（デフォルト: NO） |
| newsNotificationDate | Date | YES | ニュース通知の日時 |
| placesSortOrder | Integer 32 | YES | 場所でのソート順序 |
| latitude | Double | NO | 緯度（デフォルト: 0.0） |
| longitude | Double | NO | 経度（デフォルト: 0.0） |
| signedQuadKey | Integer 64 | YES | 位置情報の符号付きクアッドキー |
| geoDimensionNumber | Integer 64 | NO | 地理的次元（デフォルト: 0） |
| geoTypeNumber | Integer 16 | NO | 地理タイプ（デフォルト: 0） |
| pageViews | Transformable | YES | ページビュー統計（NSDictionary） |

**リレーション:**
- readingLists: ReadingList（多対多）- 記事が所属するリーディングリスト
- previewReadingLists: ReadingList（多対多）- プレビュー用リーディングリスト

**インデックス:**
- byKeyIndex: key
- bySignedQuadKeyIndex: signedQuadKey
- housekeeperIndex: viewedDate, savedDate, isDownloaded, placesSortOrder, isExcludedFromFeed
- compoundIndex1: viewedDateWithoutTime, viewedDate
- compoundIndex2: savedDate, isDownloaded, downloadRetryDate
- compoundIndex3: readingLists, imageURLString, savedDate
- byDisplayTitleIndex: displayTitle

---

### 2. ReadingList

ユーザーが作成したリーディングリストを管理するエンティティです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| canonicalName | String | YES | リストの正規名 |
| readingListDescription | String | YES | リストの説明 |
| readingListID | Integer 64 | YES | サーバー側のリストID |
| countOfEntries | Integer 64 | NO | エントリ数（デフォルト: 0） |
| createdDate | Date | YES | 作成日時 |
| updatedDate | Date | YES | 更新日時 |
| sortOrder | Integer 64 | YES | ソート順序 |
| isDefault | Boolean | NO | デフォルトリストか（デフォルト: NO） |
| isDeletedLocally | Boolean | NO | ローカルで削除済みか（デフォルト: NO） |
| isUpdatedLocally | Boolean | NO | ローカルで更新済みか（デフォルト: NO） |
| errorCode | String | YES | エラーコード |
| color | String | YES | リストの色 |
| iconName | String | YES | アイコン名 |
| imageName | String | YES | 画像名 |

**リレーション:**
- entries: ReadingListEntry（1対多、カスケード削除）- リスト内のエントリ
- articles: WMFArticle（多対多）- 関連記事
- previewArticles: WMFArticle（多対多、順序付き）- プレビュー用記事

**インデックス:**
- byNameIndex: canonicalName
- byCreatedDateIndex: createdDate
- byUpdatedLocallyIndex: isUpdatedLocally, createdDate
- byDeletedLocallyIndex: isDeletedLocally, isDefault
- byReadingListID: readingListID

---

### 3. ReadingListEntry

リーディングリスト内の個々の記事エントリを管理するエンティティです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| readingListEntryID | Integer 64 | YES | サーバー側のエントリID |
| articleKey | String | YES | 記事キー |
| displayTitle | String | YES | 表示タイトル |
| variant | String | YES | 言語バリアント |
| createdDate | Date | YES | 作成日時 |
| updatedDate | Date | YES | 更新日時 |
| isDeletedLocally | Boolean | NO | ローカルで削除済みか（デフォルト: NO） |
| isUpdatedLocally | Boolean | NO | ローカルで更新済みか（デフォルト: NO） |
| errorCode | String | YES | エラーコード |

**リレーション:**
- list: ReadingList（多対1）- 所属するリーディングリスト

**インデックス:**
- byErrorCodeAndCreatedDateIndex: errorCode, createdDate
- byErrorCodeAndDisplayTitleIndex: errorCode, displayTitle
- byUpdatedLocallyIndex: isUpdatedLocally, createdDate
- byListAndDeletedLocallyIndex: list, isDeletedLocally
- byReadingListEntryID: readingListEntryID
- byArticleKeyIndex: articleKey

---

### 4. WMFContentGroup

Explore/フィードに表示されるコンテンツグループを管理するエンティティです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| key | String | NO | コンテンツグループの一意キー |
| contentGroupKindInteger | Integer 32 | NO | コンテンツグループの種類（デフォルト: 0） |
| contentTypeInteger | Integer 16 | NO | コンテンツタイプ（デフォルト: 1） |
| date | Date | YES | 日付 |
| midnightUTCDate | Date | NO | UTC午前0時の日付 |
| contentDate | Date | YES | コンテンツの日付 |
| contentMidnightUTCDate | Date | YES | コンテンツのUTC午前0時日付 |
| siteURLString | String | YES | サイトのURL |
| articleURLString | String | YES | 記事のURL |
| featuredContentIdentifier | String | YES | フィーチャーコンテンツの識別子 |
| countOfFullContent | Integer 64 | YES | フルコンテンツの数 |
| contentPreview | Transformable | YES | コンテンツプレビュー |
| dailySortPriority | Integer 32 | NO | 日次ソート優先度（デフォルト: 0） |
| isVisible | Boolean | NO | 表示するか（デフォルト: YES） |
| wasDismissed | Boolean | YES | 非表示にされたか |
| undoTypeInteger | Integer 16 | YES | 取り消しタイプ（デフォルト: 0） |
| location | Transformable | YES | 位置情報（CLLocation） |
| placemark | Transformable | YES | プレイスマーク（CLPlacemark） |
| placement | String | YES | 配置 |
| variant | String | YES | 言語バリアント |

**リレーション:**
- fullContent: WMFContent（1対1、カスケード削除）- 詳細コンテンツ

**インデックス:**
- byKeyIndex: key
- compoundIndex: isVisible, placement, midnightUTCDate, dailySortPriority, date
- compoundIndex1: contentGroupKindInteger, midnightUTCDate, siteURLString

---

### 5. WMFContent

コンテンツグループの詳細データを保存するエンティティです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| object | Transformable | YES | コンテンツオブジェクト |

**リレーション:**
- contentGroup: WMFContentGroup（多対1）- 所属するコンテンツグループ

---

### 6. WMFKeyValue

汎用的なキーバリューストアとして使用されるエンティティです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| key | String | NO | キー |
| group | String | YES | グループ名 |
| value | Transformable | YES | 値 |
| date | Date | YES | 日付 |

**インデックス:**
- compoundIndex: key, group, date

---

## WMFDataモデル

### 7. CDArticleTab

記事タブを管理するエンティティです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| identifier | UUID | NO | タブの一意識別子 |
| isCurrent | Boolean | NO | 現在のタブか（デフォルト: NO） |
| timestamp | Date | NO | タイムスタンプ |

**リレーション:**
- items: CDArticleTabItem（1対多、順序付き）- タブ内のアイテム

---

### 8. CDArticleTabItem

記事タブ内の個々のアイテムを管理するエンティティです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| identifier | UUID | NO | アイテムの一意識別子 |
| isCurrent | Boolean | NO | 現在のアイテムか（デフォルト: NO） |

**リレーション:**
- tab: CDArticleTab（多対1）- 所属するタブ
- page: CDPage（多対1）- 関連するページ

---

### 9. CDPage

ページ情報を管理するエンティティです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| title | String | NO | ページタイトル |
| projectID | String | NO | プロジェクトID |
| namespaceID | Integer 16 | NO | 名前空間ID（デフォルト: 0） |
| timestamp | Date | NO | タイムスタンプ |

**リレーション:**
- articleTabItems: CDArticleTabItem（1対多）- 記事タブアイテム
- pageViews: CDPageView（1対多）- ページビュー
- categories: CDCategory（多対多）- カテゴリ
- savedInfo: CDPageSavedInfo（1対1）- 保存情報

**インデックス:**
- byProjectNamespace: projectID, namespaceID
- byProjectNamespaceTitle: projectID, namespaceID, title

---

### 10. CDPageView

ページビュー履歴を管理するエンティティです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| timestamp | Date | NO | 閲覧日時 |
| numberOfSeconds | Integer 64 | YES | 閲覧秒数（デフォルト: 0） |

**リレーション:**
- page: CDPage（多対1）- 関連するページ
- previousPageView: CDPageView（多対1）- 前のページビュー
- nextPageViews: CDPageView（1対多）- 次のページビュー

---

### 11. CDPageSavedInfo

ページの保存情報を管理するエンティティです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| savedDate | Date | YES | 保存日時 |

**リレーション:**
- page: CDPage（1対1）- 関連するページ

---

### 12. CDCategory

ページカテゴリを管理するエンティティです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| title | String | NO | カテゴリタイトル |
| projectID | String | NO | プロジェクトID |

**リレーション:**
- pages: CDPage（多対多）- 関連するページ

---

### 13. CDYearInReviewReport

Year in Reviewレポートを管理するエンティティです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| year | Integer 32 | NO | 年（デフォルト: 0） |

**リレーション:**
- slides: CDYearInReviewSlide（1対多、カスケード削除）- スライド

---

### 14. CDYearInReviewSlide

Year in Reviewのスライドを管理するエンティティです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| id | String | NO | スライドID |
| year | Integer 32 | YES | 年（デフォルト: 0） |
| data | Binary | YES | スライドデータ |

**リレーション:**
- report: CDYearInReviewReport（多対1）- 所属するレポート

---

## Cacheモデル

### 15. CacheGroup

キャッシュグループを管理するエンティティです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| key | String | NO | キャッシュグループのキー |

**リレーション:**
- cacheItems: CacheItem（多対多）- キャッシュアイテム
- mustHaveCacheItems: CacheItem（多対多）- 必須キャッシュアイテム

**インデックス:**
- byKeyIndex: key

---

### 16. CacheItem

キャッシュアイテムを管理するエンティティです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| key | String | NO | キャッシュアイテムのキー |
| url | URI | YES | URL |
| variant | String | YES | バリアント |
| date | Date | NO | 日付 |
| isDownloaded | Boolean | NO | ダウンロード済みか（デフォルト: NO） |

**リレーション:**
- cacheGroups: CacheGroup（多対多）- 所属するキャッシュグループ
- mustHaveCacheGroups: CacheGroup（多対多）- 必須所属キャッシュグループ

**インデックス:**
- byDateIndex: date
- compoundIndex: key, variant

---

## PersistentCacheモデル

### 17. PersistentCacheGroup

永続キャッシュグループを管理するエンティティです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| key | String | YES | キャッシュグループのキー |

**リレーション:**
- cacheItems: PersistentCacheItem（多対多）- キャッシュアイテム
- mustHaveCacheItems: PersistentCacheItem（多対多）- 必須キャッシュアイテム

**インデックス:**
- byKeyIndex: key

---

### 18. PersistentCacheItem

永続キャッシュアイテムを管理するエンティティです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| key | String | YES | キャッシュアイテムのキー |
| url | URI | NO | URL |
| variant | String | YES | バリアント |
| date | Date | YES | 日付 |
| isDownloaded | Boolean | YES | ダウンロード済みか |

**リレーション:**
- cacheGroups: PersistentCacheGroup（多対多）- 所属するキャッシュグループ
- mustHaveCacheGroups: PersistentCacheGroup（多対1）- 必須所属キャッシュグループ

**インデックス:**
- byDateIndex: date
- compoundIndex: key, variant

---

## RemoteNotificationsモデル

### 19. RemoteNotification

リモート通知を管理するエンティティです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| id | String | NO | 通知ID |
| key | String | NO | 一意キー |
| wiki | String | NO | Wiki識別子 |
| categoryString | String | NO | カテゴリ文字列 |
| typeString | String | NO | タイプ文字列 |
| date | Date | NO | 日付 |
| isRead | Boolean | NO | 既読か（デフォルト: YES） |
| agentId | String | YES | エージェントID |
| agentName | String | YES | エージェント名 |
| messageHeader | String | YES | メッセージヘッダー |
| messageBody | String | YES | メッセージ本文 |
| messageLinks | Transformable | YES | メッセージリンク（RemoteNotificationLinks） |
| titleFull | String | YES | フルタイトル |
| titleText | String | YES | タイトルテキスト |
| titleNamespace | String | YES | タイトル名前空間 |
| titleNamespaceKey | Integer 16 | NO | タイトル名前空間キー |
| section | String | YES | セクション |
| revisionID | String | YES | リビジョンID |
| utcUnixString | String | YES | UTC Unix時刻文字列 |

**インデックス:**
- byPropertyIndex: key

**ユニーク制約:**
- key

---

## EventPlatformEventsモデル

### 20. WMFEPEventRecord

イベントプラットフォームのイベント記録を管理するエンティティです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| stream | String | NO | ストリーム名 |
| data | Binary | NO | イベントデータ |
| recorded | Date | NO | 記録日時 |
| purgeable | Boolean | NO | パージ可能か（デフォルト: NO） |

**インデックス:**
- byRecordedIndex: recorded

---

## 備考

### データモデルのバージョニング

各CoreDataモデルは複数のバージョンを持ち、マイグレーションをサポートしています：

- **Wikipedia**: バージョン1～8（最新: Wikipedia 8）
- **WMFData**: バージョン1～5（最新: WMFData 5）
- **Cache**: バージョン1～2（最新: Cache 2）
- **RemoteNotifications**: バージョン1～3（最新: RemoteNotifications 3）
- **EventPlatformEvents**: バージョン1
- **PersistentCache**: バージョン1（NewCache）

### セキュアトランスフォーマー

センシティブなデータの保存には `WMFSecureUnarchiveFromDataTransformer` が使用されており、セキュアなアーカイブ/アンアーカイブ処理が行われています。

### 同期機能

- ReadingListとReadingListEntryは、サーバーとの同期をサポートするために `isUpdatedLocally`、`isDeletedLocally`、`errorCode` などのフィールドを持っています
- これらのフラグにより、オフライン時の変更を追跡し、オンライン復帰時に同期することが可能です
