お知らせ管理
概要説明
お知らせ管理機能により、管理者はシステム全体のお知らせを作成、表示、更新、削除することができます。これらのお知らせは、管理者とシステムユーザー間のコミュニケーションチャネルとして機能し、重要な情報、更新、または通知を提供します。この機能はテキストや画像を含むリッチコンテンツをサポートし、クラウドストレージへの画像アップロードに専用の機能を提供しています。
アクティビティ図
---
config:
theme: base
layout: dagre
flowchart:
curve: linear
htmlLabels: true
themeVariables:
edgeLabelBackground: "transparent"
---
flowchart TD
%% Main components
AdminUser[管理者ユーザー]
AdminInterface[お知らせ管理インターフェース]
ActionSelect{アクション選択}
%% Action components
ViewAnnouncements[お知らせ一覧]
AnnouncementDetails[お知らせ詳細]
CreateForm[お知らせ作成フォーム]
EditForm[お知らせ編集フォーム]
DeleteConfirm{削除確認}
%% Processing components
EnterContent[コンテンツ入力]
EditContent[コンテンツ編集]
ImageAddCheck{画像追加?}
ImageChangeCheck{画像追加/変更?}
UploadImages[画像アップロード]
SaveAnnouncement[お知らせ保存]
DeleteFromDB[データベースから削除]
%% Flow connections with numbered steps
AdminUser --- Step1[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>1</span>
<p style='margin-top: 8px'>インターフェースにアクセス</p>
</div>
]
Step1 --> AdminInterface
AdminInterface --- Step2[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>2</span>
<p style='margin-top: 8px'>アクション選択</p>
</div>
]
Step2 --> ActionSelect
ActionSelect --- Step3A[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>3A</span>
<p style='margin-top: 8px'>お知らせ表示</p>
</div>
]
Step3A --> ViewAnnouncements
ActionSelect --- Step3B[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #99cc66 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>3B</span>
<p style='margin-top: 8px'>詳細表示</p>
</div>
]
Step3B --> AnnouncementDetails
ActionSelect --- Step3C[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #cc66cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>3C</span>
<p style='margin-top: 8px'>お知らせ作成</p>
</div>
]
Step3C --> CreateForm
ActionSelect --- Step3D[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #cc9966 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>3D</span>
<p style='margin-top: 8px'>お知らせ更新</p>
</div>
]
Step3D --> EditForm
ActionSelect --- Step3E[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #cc6666 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>3E</span>
<p style='margin-top: 8px'>お知らせ削除</p>
</div>
]
Step3E --> DeleteConfirm
CreateForm --- Step4C[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #cc66cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>4C</span>
<p style='margin-top: 8px'>コンテンツ入力</p>
</div>
]
Step4C --> EnterContent
EditForm --- Step4D[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #cc9966 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>4D</span>
<p style='margin-top: 8px'>コンテンツ編集</p>
</div>
]
Step4D --> EditContent
EnterContent --- Step5C[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #cc66cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>5C</span>
<p style='margin-top: 8px'>画像確認</p>
</div>
]
Step5C --> ImageAddCheck
EditContent --- Step5D[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #cc9966 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>5D</span>
<p style='margin-top: 8px'>画像確認</p>
</div>
]
Step5D --> ImageChangeCheck
ImageAddCheck --- Step6C1[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #cc66cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>6C</span>
<p style='margin-top: 8px'>画像アップロード</p>
</div>
]
Step6C1 -->|はい| UploadImages
ImageChangeCheck --- Step6D1[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #cc9966 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>6D</span>
<p style='margin-top: 8px'>画像アップロード</p>
</div>
]
Step6D1 -->|はい| UploadImages
ImageAddCheck --- Step6C2[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #cc66cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>6C</span>
<p style='margin-top: 8px'>アップロードスキップ</p>
</div>
]
Step6C2 -->|いいえ| SaveAnnouncement
ImageChangeCheck --- Step6D2[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #cc9966 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>6D</span>
<p style='margin-top: 8px'>アップロードスキップ</p>
</div>
]
Step6D2 -->|いいえ| SaveAnnouncement
UploadImages --- Step7CD[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #9966cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>7</span>
<p style='margin-top: 8px'>保存</p>
</div>
]
Step7CD --> SaveAnnouncement
SaveAnnouncement --- Step8CD[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #9966cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>8</span>
<p style='margin-top: 8px'>インターフェースに戻る</p>
</div>
]
Step8CD --> AdminInterface
DeleteConfirm --- Step4E[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #cc6666 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>4E</span>
<p style='margin-top: 8px'>レコード削除</p>
</div>
]
Step4E -->|確認| DeleteFromDB
DeleteFromDB --- Step5E[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #cc6666 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>5E</span>
<p style='margin-top: 8px'>インターフェースに戻る</p>
</div>
]
Step5E --> AdminInterface
DeleteConfirm -.->|キャンセル| AdminInterface
%% Styling
style AdminUser fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
style AdminInterface fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
style ActionSelect fill:#f5f0ff,stroke:#9966cc,stroke-width:2px
style ViewAnnouncements fill:#f0f8e6,stroke:#339933,stroke-width:2px
style AnnouncementDetails fill:#f0f8e6,stroke:#339933,stroke-width:2px
style CreateForm fill:#f0f8e6,stroke:#339933,stroke-width:2px
style EditForm fill:#f0f8e6,stroke:#339933,stroke-width:2px
style EnterContent fill:#fff0f5,stroke:#cc6699,stroke-width:2px
style EditContent fill:#fff0f5,stroke:#cc6699,stroke-width:2px
style ImageAddCheck fill:#f5f0ff,stroke:#9966cc,stroke-width:2px
style ImageChangeCheck fill:#f5f0ff,stroke:#9966cc,stroke-width:2px
style UploadImages fill:#ffe6cc,stroke:#ff9900,stroke-width:2px
style SaveAnnouncement fill:#ffe6cc,stroke:#ff9900,stroke-width:2px
style DeleteConfirm fill:#f5f0ff,stroke:#9966cc,stroke-width:2px
style DeleteFromDB fill:#ffe6cc,stroke:#ff9900,stroke-width:2px
style Step1 fill:transparent,stroke:transparent,stroke-width:1px
style Step2 fill:transparent,stroke:transparent,stroke-width:1px
style Step3A fill:transparent,stroke:transparent,stroke-width:1px
style Step3B fill:transparent,stroke:transparent,stroke-width:1px
style Step3C fill:transparent,stroke:transparent,stroke-width:1px
style Step3D fill:transparent,stroke:transparent,stroke-width:1px
style Step3E fill:transparent,stroke:transparent,stroke-width:1px
style Step4C fill:transparent,stroke:transparent,stroke-width:1px
style Step4D fill:transparent,stroke:transparent,stroke-width:1px
style Step4E fill:transparent,stroke:transparent,stroke-width:1px
style Step5C fill:transparent,stroke:transparent,stroke-width:1px
style Step5D fill:transparent,stroke:transparent,stroke-width:1px
style Step5E fill:transparent,stroke:transparent,stroke-width:1px
style Step6C1 fill:transparent,stroke:transparent,stroke-width:1px
style Step6C2 fill:transparent,stroke:transparent,stroke-width:1px
style Step6D1 fill:transparent,stroke:transparent,stroke-width:1px
style Step6D2 fill:transparent,stroke:transparent,stroke-width:1px
style Step7CD fill:transparent,stroke:transparent,stroke-width:1px
style Step8CD fill:transparent,stroke:transparent,stroke-width:1px
API: お知らせ管理API
ケースドキュメント
ケース1: お知らせ一覧の取得
説明
管理者はシステム内のすべてのお知らせのページ分けされたリストを取得します。
シーケンス図
sequenceDiagram
participant Admin as 管理者
participant API as お知らせコントローラー
participant Repository as お知らせリポジトリ
participant DB as データベース
Note over Admin,DB: ステップ1: お知らせリストのリクエスト
Admin->>API: GET /api/admin/announcements (クエリパラメータ付き)
Note over API,Repository: ステップ2: お知らせの取得
API->>Repository: getPaginated(params)
Repository->>DB: お知らせのクエリ
DB-->>Repository: 該当お知らせを返す
Repository-->>API: ページ分けされた結果を返す
Note over API,Admin: ステップ3: お知らせリストの返却
API-->>Admin: 200 OK (お知らせコレクション)
ステップ
ステップ1: お知らせリストのリクエスト
- 説明: 管理者はオプションのページネーションを使用してお知らせのリストをリクエスト
- リクエスト:
GET /api/admin/announcements - クエリパラメータ:
per_page: ページあたりのアイテム数page: ページ番号- その他の潜在的なフィルタ(実装によって異なる)
ステップ2: お知らせの取得
- 説明: システムはデータベースからお知らせを取得
- アクション:
- ページネーションと任意のフィルタを適用
- お知らせを順番に取得(おそらく最新のものが最初)
ステップ3: お知らせリストの返却
- 説明: ページ分けされたお知らせリストを返す
- レスポンス:
- 成功:
200 OKとお知らせコレクションおよびページネーションメタデータ - エラー: 適切なエラーメッセージ
- 成功:
エラー処理
- ログ
- お知らせリスト取得失敗はアプリケーションログに記録
- エラー詳細:
ステータスコード エラーメッセージ 説明 400 例外メッセージを含む一般的なエラー 予期しないエラーが発生した場合
ケース2: 特定のお知らせの表示
説明
管理者が特定のお知らせの詳細を表示します。
シーケンス図
sequenceDiagram
participant Admin as 管理者
participant API as お知らせコントローラー
participant Model as お知らせモデル
participant DB as データベース
Note over Admin,DB: ステップ1: お知らせ詳細のリクエスト
Admin->>API: GET /api/admin/announcements/{id}
Note over API,Model: ステップ2: お知らせの取得
API->>Model: IDでお知らせをロード
Model->>DB: IDによるクエリ
DB-->>Model: お知らせデータを返す
Note over API,Admin: ステップ3: お知らせ詳細の返却
API-->>Admin: 200 OK (お知らせリソース)
ステップ
ステップ1: お知らせ詳細のリクエスト
- 説明: 管理者が特定のお知らせの詳細をリクエスト
- リクエスト:
GET /api/admin/announcements/{id}
ステップ2: お知らせの取得
- 説明: システムはIDによってお知らせを取得
- アクション: 完全なお知らせレコードを取得
ステップ3: お知らせ詳細の返却
- 説明: お知らせの詳細を返す
- レスポンス:
- 成功:
200 OKとお知らせリソース - エラー: お知らせが見つからない場合は適切なエラーメッセージ
- 成功:
エラー処理
- ログ
- エラーが発生した場合はログに記録
- エラー詳細:
ステータスコード エラーメッセージ 説明 404 "お知らせが見つかりません" 要求されたお知らせが存在しない場合 400 例外メッセージを含む一般的なエラー 予期しないエラーが発生した場合
ケース3: 新しいお知らせの作成
説明
管理者がシステムに新しいお知らせを作成します。
シーケンス図
sequenceDiagram
participant Admin as 管理者
participant API as お知らせコントローラー
participant Repository as お知らせリポジトリ
participant Event as お知らせ作成イベント
participant DB as データベース
Note over Admin,DB: ステップ1: お知らせ作成の送信
Admin->>API: POST /api/admin/announcements (announcement_data)
Note over API,API: ステップ2: 入力検証
API->>API: リクエストデータを検証
Note over API,Repository: ステップ3: お知らせ作成
API->>Repository: create(validated_data)
Repository->>DB: 新しいお知らせを保存
DB-->>Repository: 作成されたお知らせを返す
Note over API,Event: ステップ4: イベント発火
API->>Event: event(AnnouncementCreated)
Note over API,Admin: ステップ5: レスポンス返却
Repository-->>API: お知らせデータを返す
API-->>Admin: 201 Created (お知らせリソース)
ステップ
ステップ1: お知らせ作成の送信
- 説明: 管理者が新しいお知らせを作成するフォームを送信
- リクエスト:
POST /api/admin/announcements - 必須フィールド:
- title: お知らせのタイトル
- content: お知らせの内容(HTMLを含む場合あり)
- 実装によって必要なその他のフィールド
ステップ2: 入力検証
- 説明: システムがすべての入力データを検証
- アクション: StoreAnnouncementRequestから検証ルールを実行
- 発生しうるエラー: 検証失敗
ステップ3: お知らせ作成
- 説明: システムが新しいお知らせを作成
- アクション: データベースにお知らせレコードを保存
ステップ4: イベント発火
- 説明: システムがお知らせ作成イベントを発火
- アクション: 潜在的なリスナーのためにAnnouncementCreatedイベントを発火
- 目的: システムの他の部分が新しいお知らせに反応できるようにする
ステップ5: レスポンス返却
- 説明: 作成されたお知らせデータを返す
- レスポンス:
- 成功:
201 Createdとお知らせデータ - エラー: 適切なエラーメッセージ
- 成功:
エラー処理
- ログ
- お知らせ作成失敗はアプリケーションログに記録
- エラー詳細:
ステータスコード エラーメッセージ 説明 400 "error.announcement.create" お知らせ作成が失敗した場合
ケース4: お知らせの更新
説明
管理者が既存のお知らせを更新します。
シーケンス図
sequenceDiagram
participant Admin as 管理者
participant API as お知らせコントローラー
participant Repository as お知らせリポジトリ
participant Event as お知らせ更新イベント
participant DB as データベース
Note over Admin,DB: ステップ1: お知らせ更新の送信
Admin->>API: PUT /api/admin/announcements/{id} (updated_data)
Note over API,API: ステップ2: 入力検証
API->>API: リクエストデータを検証
Note over API,Repository: ステップ3: お知らせ更新
API->>Repository: update(id, validated_data)
Repository->>DB: お知らせレコードを更新
DB-->>Repository: 更新されたお知らせを返す
Note over API,Admin: ステップ4: レスポンス返却
Repository-->>API: お知らせデータを返す
API-->>Admin: 200 OK (お知らせリソース)
ステップ
ステップ1: お知らせ更新の送信
- 説明: 管理者がお知らせ情報を更新するフォームを送信
- リクエスト:
PUT /api/admin/announcements/{id} - 更新可能フィールド:
- title: お知らせのタイトル
- content: お知らせの内容
- status: お知らせのステータス
- 実装によって許可されるその他のフィールド
ステップ2: 入力検証
- 説明: システムがすべての入力データを検証
- アクション: UpdateAnnouncementRequestから検証ルールを実行
- 発生しうるエラー: 検証失敗
ステップ3: お知らせ更新
- 説明: システムがお知らせ情報を更新
- アクション: 新しいデータでお知らせレコードを更新
ステップ4: レスポンス返却
- 説明: 更新されたお知らせデータを返す
- レスポンス:
- 成功:
200 OKと更新されたお知らせデータ - エラー: 適切なエラーメッセージ
- 成功:
エラー処理
- ログ
- お知らせ更新失敗はアプリケーションログに記録
- エラー詳細:
ステータスコード エラーメッセージ 説明 400 "error.announcement.update" お知らせ更新が失敗した場合
ケース5: お知らせの削除
説明
管理者がシステムからお知らせを削除します。
シーケンス図
sequenceDiagram
participant Admin as 管理者
participant API as お知らせコントローラー
participant Model as お知らせモデル
participant DB as データベース
Note over Admin,DB: ステップ1: お知らせ削除リクエスト
Admin->>API: DELETE /api/admin/announcements/{id}
Note over API,Model: ステップ2: お知らせ削除
API->>Model: delete()
Model->>DB: お知らせレコードを削除
DB-->>Model: 削除を確認
Note over API,Admin: ステップ3: レスポンス返却
API-->>Admin: 200 OK (成功メッセージ)
ステップ
ステップ1: お知らせ削除リクエスト
- 説明: 管理者がお知らせを削除するリクエスト
- リクエスト:
DELETE /api/admin/announcements/{id}
ステップ2: お知らせ削除
- 説明: システムがデータベースからお知らせを削除
- アクション: お知らせレコードを削除
ステップ3: レスポンス返却
- 説明: 削除成功を確認
- レスポンス:
- 成功:
200 OKと成功メッセージ - エラー: 削除が失敗した場合は適切なエラーメッセージ
- 成功:
エラー処理
- ログ
- お知らせ削除失敗はログに記録
- エラー詳細:
ステータスコード エラーメッセージ 説明 400 "error.announcement.delete" 削除が失敗した場合
ケース6: お知らせ内容用の画像アップロード
説明
管理者がお知らせ内容で使用する画像をアップロードします。
シーケンス図
sequenceDiagram
participant Admin as 管理者
participant API as お知らせコントローラー
participant Storage as クラウドストレージ
participant DB as データベース
Note over Admin,DB: ステップ1: 画像アップロードの送信
Admin->>API: POST /api/admin/announcements/upload-image (画像ファイル)
Note over API,API: ステップ2: 画像検証
API->>API: 画像ファイルを検証
Note over API,Storage: ステップ3: 画像処理と保存
API->>API: ユニークなファイル名を生成
API->>Storage: クラウドストレージにアップロード
Storage-->>API: 画像URLを返す
Note over API,Admin: ステップ4: レスポンス返却
API-->>Admin: 200 OK (画像URL)
ステップ
ステップ1: 画像アップロードの送信
- 説明: 管理者がお知らせ用の画像ファイルをアップロード
- リクエスト:
POST /api/admin/announcements/upload-image - 必須フィールド:
- image: 画像ファイル(multipart/form-data)
ステップ2: 画像検証
- 説明: システムがアップロードされた画像を検証
- アクション: ファイルが存在し、要件を満たしているか確認
- 発生しうるエラー: ファイルがない、無効なファイルタイプ、ファイルが大きすぎる
ステップ3: 画像処理と保存
- 説明: システムが画像を処理して保存
- アクション:
- ユニークなファイル名を生成(UUIDを使用)
- ストレージパスを決定
- コンテンツタイプとキャッシングメタデータを設定
- パブリック可視性でクラウドストレージにアップロード
ステップ4: レスポンス返却
- 説明: 保存された画像へのURLを返す
- レスポンス:
- 成功:
200 OKと画像URLおよびファイル名 - エラー: 適切なエラーメッセージ
- 成功:
エラー処理
- ログ
- 画像アップロード失敗はアプリケーションログに記録
- エラー詳細:
ステータスコード エラーメッセージ 説明 400 "error.announcement.no_image_uploaded" 画像ファイルが提供されていない場合 500 "error.announcement.upload_image_failed" クラウドストレージへのアップロードが失敗した場合 400 例外メッセージを含む一般的なエラー アップロード中のその他のエラー
追加メモ
- お知らせ管理機能は、お知らせのコンテンツフィールドにHTMLを使用したリッチコンテンツをサポートしています
- 画像はGoogle Cloud Storageでホストされ、お知らせでの表示のためにパブリックアクセスが可能です
- クラウドストレージでの衝突を防ぐため、UUIDを使用してユニークなファイル名が生成されます
- 画像アセットの最適なパフォーマンスのために、適切なコンテンツタイプとキャッシュ制御ヘッダーが設定されています
- お知らせはアプリケーションの他の部分で監視できるシステムイベントをトリガーする場合があります
- エラー処理には、トラブルシューティング用のスタックトレースを含む詳細なログ記録が含まれています
関連データベーステーブルとフィールド
erDiagram
announcements {
bigint id PK "主キー"
string title "お知らせタイトル"
text content "お知らせ内容(HTML許可)"
bigint created_by FK "users.idへの参照"
string status "お知らせステータス(例:下書き、公開済み)"
timestamp created_at "レコード作成タイムスタンプ"
timestamp updated_at "レコード最終更新タイムスタンプ"
}
users {
bigint id PK "主キー"
string name "ユーザーのフルネーム"
string email "ユーザーのメールアドレス(一意)"
timestamp created_at "アカウント作成タイムスタンプ"
timestamp updated_at "最終更新タイムスタンプ"
}
announcements }|--|| users : created_by