SMART-CONTACT 全体管理画面 要件定義書¶
| 項目 | 内容 |
|---|---|
| プロジェクト名 | SMART-CONTACT |
| バージョン | 1.0 |
| 作成日 | 2026-02-17 |
| ステータス | 開発中 (develop ブランチ) |
| 対象スコープ | Admin Panel (/admin/*) |
1. 概要¶
SMART-CONTACT の運営者向け管理画面。ユーザー管理、KPI可視化、通知配信、送信ログ監視、サブスクリプション管理など、SaaS運営に必要なCRM機能を提供する。
| 項目 | 内容 |
|---|---|
| ルート | /admin/* |
| ミドルウェア |
auth + verified + admin (is_admin = true) |
| フレームワーク | Laravel Inertia.js + React (TypeScript) |
| UIコンポーネント | shadcn/ui + Tailwind CSS 4 |
| チャート | Recharts |
| アニメーション | Framer Motion |
| テーブル | TanStack Table v8 |
| 認証方式 | Laravel セッション認証 (Cookie) |
| デザイン | セクション 4.9 デザインシステム準拠 (ダーク/ライト切替対応) |
1.1 アクセス制御¶
app/Http/Middleware/EnsureUserIsAdmin.php
-> users.is_admin = true のみアクセス可
-> false の場合は 403 Forbidden を返却
管理画面へのアクセスには以下の3つのミドルウェアを通過する必要がある。
- auth -- ログイン済みであること
- verified -- メール認証済みであること
-
admin --
is_admin = trueであること
2. KPIダッシュボード¶
FR-ADMIN-001: KPIサマリーカード¶
画面上部に主要10指標をカード形式でリアルタイム表示する。各カードはカウントアップアニメーション、前日比/前月比の矢印バッジ (緑: 上昇 / 赤: 下降) を含む。非同期更新API (GET /admin/kpi/summary) で30秒ごとにポーリングまたは手動リフレッシュ可能。
| # | 指標 | 算出方法 | 表示例 |
|---|---|---|---|
| 1 | 総ユーザー数 |
users テーブルの全件数 |
1,234 |
| 2 | 有料ユーザー数 |
subscriptions で stripe_status = active のユーザー数 |
456 |
| 3 | Premium (ホワイト) ユーザー数 |
is_white_user = true のユーザー数 |
12 |
| 4 | トライアルユーザー数 |
trial_ends_at > now() かつサブスクリプション未契約 |
78 |
| 5 | DAU (日次アクティブユーザー) |
user_activity_logs で当日ログインまたは実行があったユニークユーザー数 |
89 |
| 6 | WAU (週次アクティブユーザー) | 直近7日間のユニークアクティブユーザー数 | 234 |
| 7 | MAU (月次アクティブユーザー) | 直近30日間のユニークアクティブユーザー数 | 567 |
| 8 | MRR (月次経常収益) | アクティブなサブスクリプションの月額合計 | \1,234,000 |
| 9 | 解約率 (Churn Rate) | 直近30日間の解約数 / 前月アクティブ数 x 100 | 3.2% |
| 10 | 総送信数 (今月) |
contact_mail_logs + 拡張機能からの実行報告 (user_activity_logs の execution_complete) の今月合計 |
12,345 |
KPIカードUI仕様:
- 数値は
font-variant-numeric: tabular-numsで等幅表示 - 数値変化時にカウントアップアニメーション (Framer Motion
animate, 500ms easeOut) - 前日比/前月比を矢印 + 色付きバッジで表示 (緑: 上昇 / 赤: 下降)
- カードの上辺にアクセントカラーのグラデーションライン (高さ2px)
- 各指標に対応するLucideアイコン + アクセントカラー背景の円形アイコンエリア
FR-ADMIN-002: KPIグラフ¶
ダッシュボード下部に5種類のグラフを表示する。各グラフはデータ取得API (GET /admin/kpi/chart/{type}) から期間パラメータ付きでJSON取得する。
| # | グラフ | 種別 | 内容 | 期間選択 |
|---|---|---|---|---|
| 1 | ユーザー数推移 | 折れ線グラフ (Line) | 累計 / 新規 / 解約 の3本線 | 7日 / 30日 / 90日 / 1年 |
| 2 | DAU/MAU推移 | 折れ線グラフ (Line) | DAUとMAUの2本線 | 30日 / 90日 / 1年 |
| 3 | 売上推移 | 棒グラフ (Bar) | MRR月次推移 | 6ヶ月 / 1年 |
| 4 | 送信数推移 | 棒グラフ (Bar) | フォーム送信 / メール送信 の積み上げ | 7日 / 30日 |
| 5 | コンバージョンファネル | ファネルチャート (Funnel) | 登録 -> トライアル -> 有料 の転換率 | 30日 / 90日 |
グラフUI仕様:
- Recharts ベース、ダークテーマ対応 (背景透明、グリッド線
rgba(255, 255, 255, 0.05)) - ツールチップ: ダーク背景 + ゴールドアクセント
- エリアチャートはグラデーションフィル (
linearGradientゴールド -> 透明) - 初回表示時に左からフェードインアニメーション (800ms)
- 期間セレクターはタブ形式 (shadcn/ui Tabs)
3. ユーザー管理¶
FR-ADMIN-003: ユーザー一覧¶
TanStack Table v8 ベースのデータテーブルでユーザーを一覧表示する。
| 項目 | 内容 |
|---|---|
| 表示項目 | ID, 名前, メール, ユーザー種別バッジ, ステータス, 登録日, 最終アクティブ日 |
| 検索 | 名前・メールアドレスでの部分一致検索 (サーバーサイド) |
| フィルター | ユーザー種別 (Premium / 有料 / トライアル / 無料 / BAN)、ステータス (アクティブ / 非アクティブ / BAN) |
| ソート | 登録日 (デフォルト降順), 最終アクティブ日, 送信数 |
| ページネーション | 20件/ページ、件数表示 + ページ番号 + 前後ボタン |
| 一括操作 | チェックボックス選択 -> 一括BAN, 一括通知送信 |
ユーザー種別バッジ:
| 種別 | バッジスタイル |
|---|---|
| Premium | ゴールド光沢 (shimmer アニメーション) |
| Standard | シルバー |
| Trial | ブルー |
| Free | グレー |
BANユーザーの行表示: 赤い Banned バッジ + 行背景に薄い赤オーバーレイ (rgba(239, 68, 68, 0.08))
FR-ADMIN-004: ユーザー詳細¶
ユーザー詳細画面は6セクションのタブまたはアコーディオンレイアウトで構成する。
| # | セクション | 表示内容 |
|---|---|---|
| 1 | 基本情報 | 名前, メール, ユーザー種別バッジ, 登録日, 最終ログイン日, BANステータス |
| 2 | サブスクリプション | プラン名, ステータス, 開始日, 次回請求日, デバイス上限数, Stripe顧客ID |
| 3 | デバイス一覧 | 登録デバイス (UUID, デバイス名, 最終アクセス日)。個別削除ボタン付き |
| 4 | 利用統計 | 総送信数, 今月送信数, フォーム送信/メール送信の内訳, 成功率, 日別送信グラフ (ミニチャート) |
| 5 | アクティビティログ | 直近のログイン・実行・設定変更等のタイムライン (最新50件)。タイムライン形式 (左にドット付き縦線、アクション種別ごとに色分け) |
| 6 | 管理者メモ | 自由記述のメモ欄 (対応履歴等の記録用)。users.admin_memo に保存。リアルタイム自動保存 (debounce 1秒) |
FR-ADMIN-005: BAN (利用停止)¶
BAN実行¶
ユーザー詳細画面またはー覧の一括操作から実行する。BAN実行時は確認モーダルで理由入力を必須とする。
BAN時の処理 (4ステップ):
| Step | 処理 | 対象 |
|---|---|---|
| 1 |
users.banned_at に現在のタイムスタンプを設定 |
users テーブル |
| 2 |
users.ban_reason にBAN理由を記録 |
users テーブル |
| 3 | 該当ユーザーの全 Sanctum トークンを削除 (即時ログアウト) |
personal_access_tokens テーブル |
| 4 | 該当ユーザーの全デバイス情報を無効化 |
user_devices テーブル |
BAN解除¶
-
banned_atをNULLに戻す -
ban_reasonは履歴として保持 (クリアしない) - ユーザーは再ログイン可能になる
拡張機能側の挙動¶
ライセンスチェック (POST /api/check-license) 時に banned_at IS NOT NULL を検出した場合:
{
"status": "denied",
"reason": "account_banned",
"message": "このアカウントは利用停止されています。管理者にお問い合わせください。"
}
拡張機能側ではエラーメッセージを表示し、全操作をブロックする。
FR-ADMIN-006: ユーザー編集¶
| 操作 | 説明 | 対象カラム |
|---|---|---|
| ユーザー種別変更 | Premium <-> Standard の切り替え | users.is_white_user |
| デバイス上限変更 | デバイス登録可能台数の手動調整 | users.stripe_subscription_quantity |
| パスワードリセット | パスワードリセットメールを送信 (Laravel 標準の Password::sendResetLink) |
- |
| デバイス削除 | 個別デバイスの登録解除 (デバイス枠が1つ空く) |
user_devices テーブル |
4. 通知管理¶
FR-ADMIN-007: 通知種別¶
| 種別 | target_type |
対象 | 使用例 |
|---|---|---|---|
| 全体お知らせ | all |
全ユーザー | メンテナンス告知、新機能リリース、利用規約変更 |
| セグメント通知 | segment |
ユーザー種別指定 | プラン別のお知らせ (例: トライアル終了リマインド、Premium向け新機能案内) |
| 個別通知 | individual |
特定ユーザー1名 | サポート対応、警告通知、アカウント関連の連絡 |
セグメント指定値:
target_segment |
対象ユーザー |
|---|---|
premium |
is_white_user = true のユーザー |
paid |
subscriptions.stripe_status = active のユーザー |
trial |
trial_ends_at > now() かつサブスクリプション未契約のユーザー |
free |
上記いずれにも該当しないユーザー |
FR-ADMIN-008: 通知データ構造¶
interface AdminNotification {
id: number;
title: string; // 通知タイトル (最大255文字)
body: string; // 通知本文 (Markdown対応)
type: 'info' | 'warning' | 'maintenance' | 'update';
target_type: 'all' | 'segment' | 'individual';
target_segment?: 'premium' | 'paid' | 'trial' | 'free';
target_user_id?: number; // 個別通知の場合のユーザーID
is_published: boolean; // 公開状態 (true: 公開 / false: 下書き)
published_at?: string; // 公開日時 (予約投稿対応、ISO 8601)
expires_at?: string; // 表示期限 (ISO 8601、NULL = 無期限)
created_by: number; // 作成した管理者のユーザーID
created_at: string;
updated_at: string;
}
通知種別 (type) 別の表示スタイル:
type |
アイコン | 左ボーダーカラー | 用途 |
|---|---|---|---|
info |
Info (Lucide) |
青 (#3B82F6) |
一般的なお知らせ |
warning |
AlertTriangle (Lucide) |
黄 (#F59E0B) |
注意喚起 |
maintenance |
Wrench (Lucide) |
紫 (#8B5CF6) |
メンテナンス告知 |
update |
Sparkles (Lucide) |
緑 (#22C55E) |
新機能・アップデート |
通知作成画面のUI:
- Markdown -> HTML リアルタイム分割プレビュー (左: エディタ / 右: プレビュー)
- 予約投稿の日時ピッカー (date-fns)
- 対象タイプ切り替え時にフォームフィールドが動的に変化
FR-ADMIN-009: 通知のユーザー側表示¶
| 項目 | 内容 |
|---|---|
| 取得API |
GET /api/notices (拡張機能から定期取得) |
| 表示場所 | 拡張機能ダッシュボードの上部バナー |
| 既読管理 | Chrome Storage に既読通知IDリスト (readNoticeIds: number[]) を保存 |
| 未読バッジ | ダッシュボードタブに未読件数を赤いバッジで表示 |
取得条件 (サーバーサイドクエリ):
WHERE is_published = true
AND published_at <= NOW()
AND (expires_at IS NULL OR expires_at > NOW())
AND (
target_type = 'all'
OR (target_type = 'segment' AND target_segment = {ユーザーのセグメント})
OR (target_type = 'individual' AND target_user_id = {ログインユーザーID})
)
ORDER BY published_at DESC
5. 送信ログ管理¶
FR-ADMIN-010: 送信ログ一覧¶
サーバー経由メール送信 (POST /api/send-contact-mail) の全履歴を管理・検索する。データソースは contact_mail_logs テーブル。
| 項目 | 内容 |
|---|---|
| 表示項目 | ID, ユーザー名, 送信先メール (to_email), 件名 (subject), 送信元URL (source_url), ステータス (status), 送信日時 (sent_at) |
| 検索 | 送信先メール, ユーザー名, 送信元URL での部分一致検索 (サーバーサイド) |
| フィルター | ステータス (success / failed), 期間指定 (日付範囲ピッカー) |
| ソート | 送信日時 (デフォルト降順), ユーザー名, ステータス |
| ページネーション | 20件/ページ |
| 詳細表示 | 行クリックまたは展開ボタンで以下を表示: |
- 送信本文 (body) のフル表示 |
|
- 送信者名 (from_name) + 送信元メール (from_email) |
|
- エラー詳細 (error_message) -- 失敗時のみ |
|
- 送信元URL (source_url) のリンク表示 |
ステータス表示:
status |
バッジ | 色 |
|---|---|---|
success |
成功 | 緑 (#22C55E) |
failed |
失敗 | 赤 (#EF4444) |
6. サブスクリプション管理¶
FR-ADMIN-011: サブスクリプション一覧¶
| 項目 | 内容 |
|---|---|
| 表示項目 | ユーザー名, プラン名, ステータス, 数量 (デバイス数), 開始日, 次回請求日, 月額金額 |
| フィルター | ステータス (active / trialing / canceled / past_due) |
| ページネーション | 20件/ページ |
| 集計 (ヘッダー) | ステータス別ユーザー数のサマリーカード, MRR合計 |
ステータスバッジ:
stripe_status |
バッジ | 色 |
|---|---|---|
active |
Active | 緑 |
trialing |
Trial | 青 |
canceled |
Canceled | グレー |
past_due |
Past Due | 赤 |
FR-ADMIN-012: 手動サブスクリプション操作¶
Stripeを介さず管理画面から直接ユーザーの契約状態を変更する操作。操作時は確認モーダルを表示し、アクティビティログに記録する。
| 操作 | 説明 | 対象カラム |
|---|---|---|
| Premium付与 |
is_white_user = true に設定。Stripeサブスクリプションに関係なく無制限利用可能にする |
users.is_white_user |
| トライアル延長 | トライアル終了日を任意の日付に変更 (日付ピッカーで選択) | users.trial_ends_at |
| デバイス枠変更 | デバイス登録可能台数を任意の値に手動調整 | users.stripe_subscription_quantity |
7. アクティビティログ¶
FR-ADMIN-013: システム全体のアクティビティ¶
全ユーザーの操作をタイムライン形式で監視する。データソースは user_activity_logs テーブル。
7種のアクション種別:
| # | アクション種別 (action) |
記録タイミング | 記録内容 (details JSON) |
タイムラインの色 |
|---|---|---|---|---|
| 1 | login |
ログイン成功時 | IP, デバイス名, user_agent | 青 (#3B82F6) |
| 2 | logout |
ログアウト時 | - | グレー (#6B7280) |
| 3 | license_check |
ライセンスチェック時 | デバイスUUID, 結果 (allowed / denied), 拒否理由 |
黄 (#F59E0B) |
| 4 | execution_start |
バッチ実行開始時 | URL件数, テンプレートID, テストモードフラグ | 紫 (#8B5CF6) |
| 5 | execution_complete |
バッチ実行完了時 | 成功数, 失敗数, メール送信数, 所要時間(秒) | 緑 (#22C55E) |
| 6 | mail_sent |
メール送信時 | 送信先メール, 結果 (success / failed) |
ゴールド (#D4AF37) |
| 7 | ban |
BAN実行/解除時 | 対象ユーザーID, 理由, 操作 (ban / unban), 管理者ID |
赤 (#EF4444) |
一覧画面のUI:
- TanStack Table v8 によるテーブル表示
- 検索: ユーザー名, アクション種別でフィルター
- フィルター: アクション種別のマルチセレクト, 期間指定
- ソート: 記録日時 (デフォルト降順)
- ページネーション: 50件/ページ
- ユーザー詳細内のアクティビティログはタイムライン形式 (左にドット付き縦線、色分け)
保持期間: 90日間 (古いログは日次バッチで自動削除)
8. システム設定¶
FR-ADMIN-014: 管理画面から変更可能なシステム設定¶
5つの設定項目を管理画面から変更可能。設定値はDBの system_settings テーブル (key-value 形式) またはキャッシュに保存する。変更時は即座に反映され、アクティビティログに記録される。
| # | 設定 | キー | 型 | 説明 | デフォルト |
|---|---|---|---|---|---|
| 1 | メール送信レート制限 | rate_limit_per_minute |
integer | ユーザーあたり1分間のメール送信上限 |
10 件/分 |
| 2 | デフォルトトライアル日数 | default_trial_days |
integer | 新規ユーザー登録時のトライアル期間 |
14 日 |
| 3 | デフォルトデバイス上限 | default_device_limit |
integer | 無料ユーザー / 新規ユーザーのデバイス登録上限 |
1 台 |
| 4 | メンテナンスモード | maintenance_mode |
boolean |
true の場合、拡張機能からのAPI呼び出しを一時停止し、メンテナンス中メッセージを返す |
false (OFF) |
| 5 | 全体お知らせバナー | global_banner |
string | 即時表示の緊急お知らせテキスト。空でない場合、拡張機能と管理画面にバナー表示 | 空文字列 |
設定画面UI:
- フォームは React Hook Form + Zod バリデーション
- 各設定項目の説明テキストをラベル下に表示
- メンテナンスモードは確認モーダル付きトグルスイッチ
- 保存ボタン押下で
PUT /admin/settingsを実行 - 保存成功時にトースト通知 (shadcn/ui Sonner)
9. 画面一覧¶
| # | 画面 | URL | 説明 |
|---|---|---|---|
| 1 | ログイン | /admin/login |
管理者ログイン (共通ログイン画面からリダイレクト) |
| 2 | ダッシュボード | /admin |
KPIサマリーカード + グラフ |
| 3 | ユーザー一覧 | /admin/users |
検索・フィルター付きユーザーリスト |
| 4 | ユーザー詳細 | /admin/users/{id} |
詳細情報・編集・BAN操作 |
| 5 | 通知一覧 | /admin/notifications |
通知の管理 (一覧・削除) |
| 6 | 通知作成 | /admin/notifications/create |
新規通知の作成 (Markdownエディタ + プレビュー) |
| 7 | 送信ログ | /admin/mail-logs |
メール送信履歴の検索・閲覧 |
| 8 | サブスクリプション | /admin/subscriptions |
契約状況一覧 + 手動操作 |
| 9 | アクティビティログ | /admin/activity-logs |
システム全体の操作ログ |
| 10 | システム設定 | /admin/settings |
運営パラメータの変更 |
10. ルーティング¶
管理画面はInertia.jsで構築するため、以下はサーバーサイドルート (Webミドルウェア + auth + verified + admin ガード) で提供する。
| # | メソッド | URL | 説明 |
|---|---|---|---|
| 1 | GET |
/admin |
KPIダッシュボード |
| 2 | GET |
/admin/users |
ユーザー一覧 |
| 3 | GET |
/admin/users/{id} |
ユーザー詳細 |
| 4 | PUT |
/admin/users/{id} |
ユーザー情報更新 (種別変更・デバイス上限変更・メモ保存) |
| 5 | POST |
/admin/users/{id}/ban |
BAN実行 |
| 6 | POST |
/admin/users/{id}/unban |
BAN解除 |
| 7 | POST |
/admin/users/{id}/reset-password |
パスワードリセットメール送信 |
| 8 | DELETE |
/admin/users/{id}/devices/{deviceId} |
デバイス削除 |
| 9 | POST |
/admin/users/bulk-ban |
一括BAN実行 |
| 10 | POST |
/admin/users/bulk-notify |
一括通知送信 |
| 11 | GET |
/admin/notifications |
通知一覧 |
| 12 | GET |
/admin/notifications/create |
通知作成画面 |
| 13 | POST |
/admin/notifications |
通知作成 (保存) |
| 14 | GET |
/admin/notifications/{id}/edit |
通知編集画面 |
| 15 | PUT |
/admin/notifications/{id} |
通知編集 (保存) |
| 16 | DELETE |
/admin/notifications/{id} |
通知削除 |
| 17 | GET |
/admin/mail-logs |
送信ログ一覧 |
| 18 | GET |
/admin/mail-logs/{id} |
送信ログ詳細 |
| 19 | GET |
/admin/subscriptions |
サブスクリプション一覧 |
| 20 | GET |
/admin/activity-logs |
アクティビティログ一覧 |
| 21 | GET |
/admin/settings |
システム設定表示 |
| 22 | PUT |
/admin/settings |
システム設定更新 |
| 23 | GET |
/admin/kpi/summary |
KPIサマリーJSON (非同期更新用) |
| 24 | GET |
/admin/kpi/chart/{type} |
KPIグラフデータJSON (type: users, active, revenue, sends, funnel) |
11. 固有デザイン仕様¶
管理画面は基本デザインシステム (セクション 4.9) に準拠しつつ、以下の管理画面固有のデザインを適用する。
11.1 BANステータス表示¶
| 要素 | 仕様 |
|---|---|
| バッジ | 赤背景 (bg-red-500/20) + 赤テキスト (text-red-400) で Banned テキスト |
| テーブル行 | 行全体に薄い赤オーバーレイ (rgba(239, 68, 68, 0.08)) |
| ユーザー詳細 | ヘッダーに赤い警告バナー (BAN理由 + BAN日時を表示) |
.user-row--banned {
background: rgba(239, 68, 68, 0.08);
border-left: 3px solid #EF4444;
}
.badge--banned {
background: rgba(239, 68, 68, 0.2);
color: #F87171;
font-weight: 600;
padding: 2px 8px;
border-radius: 9999px;
font-size: 12px;
}
11.2 ユーザー種別バッジ¶
| 種別 | 背景 | テキスト色 | 特殊効果 |
|---|---|---|---|
| Premium | linear-gradient(135deg, #D4AF37, #F5D060, #D4AF37) |
#1A1A1A |
shimmer アニメーション (CSS @keyframes shimmer でゴールド光沢が左から右に移動、3秒ループ) |
| Standard | rgba(168, 162, 158, 0.2) |
#A8A29E |
なし |
| Trial | rgba(59, 130, 246, 0.2) |
#60A5FA |
なし |
| Free | rgba(107, 114, 128, 0.2) |
#9CA3AF |
なし |
@keyframes shimmer {
0% { background-position: -200% center; }
100% { background-position: 200% center; }
}
.badge--premium {
background: linear-gradient(
90deg,
#D4AF37 0%,
#F5D060 25%,
#D4AF37 50%,
#F5D060 75%,
#D4AF37 100%
);
background-size: 200% auto;
animation: shimmer 3s linear infinite;
color: #1A1A1A;
font-weight: 700;
}
11.3 KPIカードアイコン¶
各KPI指標に対応するLucideアイコンと、アクセントカラー背景の円形アイコンエリアを表示する。
| 指標 | Lucideアイコン | アイコン背景色 |
|---|---|---|
| 総ユーザー数 | Users |
rgba(212, 175, 55, 0.15) |
| 有料ユーザー数 | CreditCard |
rgba(34, 197, 94, 0.15) |
| Premium数 | Crown |
rgba(212, 175, 55, 0.15) |
| トライアル数 | Clock |
rgba(59, 130, 246, 0.15) |
| DAU | Activity |
rgba(168, 85, 247, 0.15) |
| WAU | TrendingUp |
rgba(168, 85, 247, 0.15) |
| MAU | BarChart3 |
rgba(168, 85, 247, 0.15) |
| MRR | DollarSign |
rgba(34, 197, 94, 0.15) |
| 解約率 | UserMinus |
rgba(239, 68, 68, 0.15) |
| 総送信数 | Send |
rgba(59, 130, 246, 0.15) |
アイコンエリアCSS:
.kpi-icon-area {
width: 48px;
height: 48px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
}
.kpi-icon-area svg {
width: 24px;
height: 24px;
}
11.4 アクティビティタイムライン¶
ユーザー詳細内のアクティビティログはタイムライン形式で表示する。
| 要素 | 仕様 |
|---|---|
| 縦線 | 左マージン24pxの位置に、点線 (border-left: 2px dotted rgba(255, 255, 255, 0.1)) で縦に接続 |
| ドット | 各ログエントリの左側に直径10pxの円形ドット。アクション種別ごとに色分け (セクション7の色定義に準拠) |
| エントリ | ドットの右側にアクション名 + タイムスタンプ + 詳細テキスト |
| 間隔 | エントリ間は16pxの垂直マージン |
.timeline-line {
position: absolute;
left: 24px;
top: 0;
bottom: 0;
border-left: 2px dotted rgba(255, 255, 255, 0.1);
}
.timeline-dot {
width: 10px;
height: 10px;
border-radius: 50%;
position: absolute;
left: 20px;
box-shadow: 0 0 0 3px var(--bg-card);
}
.timeline-entry {
padding-left: 48px;
margin-bottom: 16px;
}
11.5 通知プレビュー¶
通知作成・編集画面では、Markdown入力とHTMLプレビューのリアルタイム分割表示を提供する。
| 要素 | 仕様 |
|---|---|
| レイアウト | 左右50:50の分割レイアウト (レスポンシブ時は上下に切り替え) |
| 左パネル (エディタ) | Markdown テキストエリア。シンタックスハイライトなし、等幅フォント (font-family: monospace) |
| 右パネル (プレビュー) | Markdown -> HTML 変換のリアルタイムレンダリング。通知カードのスタイルを適用した状態で表示 |
| 変換タイミング | 入力から300msのdebounce後にプレビュー更新 |
| Markdown対応記法 | 見出し (#), 太字 (**), リスト (-), リンク ([text](url)), コードブロック, 改行 |
付録A: 関連テーブル定義 (参照)¶
管理画面が参照・操作する主要テーブル。詳細は database/schema.md を参照。
| テーブル | 管理画面での用途 |
|---|---|
users |
ユーザー管理 (CRUD, BAN, 種別変更) |
user_devices |
デバイス一覧表示・削除 |
subscriptions |
サブスクリプション一覧・集計 |
admin_notifications |
通知の作成・編集・削除・公開管理 |
user_activity_logs |
アクティビティログ一覧・KPI算出 (DAU/WAU/MAU) |
contact_mail_logs |
送信ログ一覧・検索 |
personal_access_tokens |
BAN時のトークン一括削除 |
付録B: ユーザー種別判定ロジック¶
管理画面内でユーザー種別バッジを表示する際の判定ロジック。
type UserType = 'premium' | 'standard' | 'trial' | 'free';
function getUserType(user: User): UserType {
// 1. Premium (ホワイトユーザー)
if (user.is_white_user) return 'premium';
// 2. Standard (有料サブスクリプション)
if (user.subscription?.stripe_status === 'active') return 'standard';
// 3. Trial (トライアル期間中)
if (user.trial_ends_at && new Date(user.trial_ends_at) > new Date()) return 'trial';
// 4. Free (上記いずれにも該当しない)
return 'free';
}