# 機能設計書 152-ポータルアーカイブ

## 概要

本ドキュメントは、Chatwootのヘルプセンターにおける「ポータルアーカイブ」機能の設計仕様を定義する。この機能により、不要になったポータルを完全削除せずに無効化（非公開）することが可能となる。

### 本機能の処理概要

**業務上の目的・背景**：
ヘルプセンターの運用において、特定のポータルを一時的または恒久的に公開停止したい場合がある。完全削除すると関連する記事やカテゴリも失われてしまうが、アーカイブ機能を使用することで、データを保持したまま公開状態のみを変更できる。これにより、将来的な再公開や、データの監査目的での保持が可能となる。

**機能の利用シーン**：
- キャンペーン終了後のヘルプセンターを一時的に非公開にする場面
- 古いバージョンの製品ドキュメントを非公開にしつつデータを保持する場面
- 新しいポータルへの移行中に旧ポータルを段階的に非公開化する場面
- コンプライアンス要件でデータ保持が必要だが公開は停止したい場面

**主要な処理内容**：
1. ポータルのアーカイブ状態をtrueに更新
2. 公開APIからアーカイブされたポータルを除外
3. 管理画面でのアーカイブ状態表示

**関連システム・外部連携**：
- 公開API：アーカイブされたポータルへのアクセスを拒否
- Web Widget：アーカイブされたポータルのヘルプ記事は非表示

**権限による制御**：
- アーカイブ操作：管理者（Administrator）権限が必要

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 91 | ポータル一覧画面 | 主画面 | ポータルの無効化操作 |
| 98 | ポータル設定画面 | 補助画面 | アーカイブ状態の確認・変更 |

## 機能種別

状態更新処理 / フラグ切り替え

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | String | Yes | ポータルのslug | Portal存在確認 |

### 入力データソース

- URL パラメータ：ポータルのslug
- API：`PATCH /api/v1/accounts/:account_id/portals/:id/archive`

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| (なし) | - | 成功時はHTTP 200 OKのみ |

### 出力先

- HTTP レスポンス（ステータスコードのみ）

## 処理フロー

### 処理シーケンス

```
1. アーカイブ実行
   └─ リクエスト受信 → Portal取得 → 認可チェック → archived=true更新 → HTTP 200返却
```

### フローチャート

```mermaid
flowchart TD
    A[PATCH /portals/:id/archive] --> B[fetch_portal]
    B --> C{Portalが存在?}
    C -->|No| D[404 Not Found]
    C -->|Yes| E[check_authorization]
    E --> F{管理者権限?}
    F -->|No| G[403 Forbidden]
    F -->|Yes| H[portal.update archive: true]
    H --> I[HTTP 200 OK]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-152-01 | アーカイブポータル非公開 | archived=trueのポータルは公開APIで表示されない | 公開アクセス時 |
| BR-152-02 | 管理画面からのアクセス可能 | アーカイブ後も管理画面からはアクセス可能 | 管理API使用時 |
| BR-152-03 | 関連データ保持 | アーカイブしても記事・カテゴリは削除されない | アーカイブ実行時 |

### 計算ロジック

特になし

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| archive | portals | UPDATE | archivedカラムをtrueに更新 |

### テーブル別操作詳細

#### portals

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | archived | true | アーカイブフラグ有効化 |
| UPDATE | updated_at | 現在時刻 | 自動更新 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 404 | NotFound | 指定slugのPortalが存在しない | 正しいslugを指定 |
| 403 | Forbidden | 管理者権限がない | 管理者権限でアクセス |

### リトライ仕様

特になし（冪等性あり：何度実行しても同じ結果）

## トランザクション仕様

単一UPDATE文のため、暗黙的トランザクションで実行

## パフォーマンス要件

- 処理時間：50ms以内（単一レコード更新）

## セキュリティ考慮事項

- 管理者権限チェック必須
- アーカイブ操作の監査ログ記録（将来的な拡張候補）

## 備考

- 現在の実装では`archive: true`となっているが、カラム名は`archived`であるため、実装上の不整合がある可能性あり（要確認）
- アンアーカイブ（復元）機能は、通常のupdate操作で`archived: false`を設定することで実現可能

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | portal.rb | `app/models/portal.rb` | archivedカラムの定義、activeスコープ |

**読解のコツ**:
- **6行目**: `archived :boolean default(FALSE)` - デフォルトはfalse（公開状態）
- **45行目**: `scope :active, -> { where(archived: false) }` - 公開ポータル取得用スコープ

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | portals_controller.rb | `app/controllers/api/v1/accounts/portals_controller.rb` | archiveアクション |

**主要処理フロー**:
- **39-42行目**: archive - ポータルのアーカイブ実行

```ruby
def archive
  @portal.update(archive: true)
  head :ok
end
```

#### Step 3: 公開API側の制御を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | portals_controller.rb | `app/controllers/public/api/v1/portals_controller.rb` | アーカイブポータルの除外 |

**主要処理フロー**:
- **20-21行目**: `Portal.find_by!(slug: params[:slug], archived: false)` - 公開時はarchived=falseのみ取得

### プログラム呼び出し階層図

```
Api::V1::Accounts::PortalsController#archive
    │
    ├─ before_action :fetch_portal
    │      └─ Current.account.portals.find_by(slug:)
    │
    ├─ before_action :check_authorization
    │      └─ PortalPolicy (暗黙的にupdate?を使用)
    │
    └─ @portal.update(archive: true)
           └─ ActiveRecord UPDATE
```

### データフロー図

```
[入力]                     [処理]                           [出力]

PATCH Request       →   PortalsController#archive   →   HTTP 200 OK
(slug)                      │
                           ├─ fetch_portal
                           │     (slug → Portal)
                           │
                           └─ Portal.update
                                 (archived = true)
                                       ↓
                              [portals テーブル更新]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| portal.rb | `app/models/portal.rb` | モデル | archivedフィールド定義 |
| portals_controller.rb | `app/controllers/api/v1/accounts/portals_controller.rb` | コントローラー | archiveアクション |
| portals_controller.rb | `app/controllers/public/api/v1/portals_controller.rb` | コントローラー | 公開API側のアーカイブ除外 |
| portal_policy.rb | `app/policies/portal_policy.rb` | ポリシー | 認可ルール定義 |
| routes.rb | `config/routes.rb` | 設定 | archiveルート定義 |
