プロジェクト

全般

プロフィール

ユーザー管理画面 要件定義書

項目 内容
プロジェクト名 SMART-CONTACT
バージョン 1.0
作成日 2026-02-17
ステータス 開発中 (develop ブランチ)

1. 概要

ユーザー向けWebダッシュボードであり、Chrome拡張機能のアカウント設定画面からリンクされる管理画面である。ユーザーは本画面からプロフィール編集、契約・請求管理、デバイス管理、利用統計の確認、運営からのお知らせ閲覧を行う。

項目 内容
ルートプレフィックス /dashboard/*
ミドルウェア auth, verified
認証方式 Session認証 (Cookie)
フレームワーク Laravel Inertia.js + React + TypeScript
UIコンポーネント shadcn/ui (Radix UI ベース)
スタイリング Tailwind CSS 4
チャートライブラリ Recharts
アニメーション Framer Motion
アイコン Lucide React
テーブル TanStack Table v8
フォーム React Hook Form + Zod
デザイン ダーク/ライト切替対応 (デザインシステム準拠)

2. 画面一覧

画面 URL 説明
ユーザーダッシュボード /dashboard 利用状況サマリー + お知らせ
プロフィール /dashboard/profile 名前・メール・パスワード変更
契約・請求管理 /dashboard/billing プラン確認・変更、請求履歴、カード情報
デバイス管理 /dashboard/devices 登録デバイス一覧・削除・再紐付け
利用統計 /dashboard/stats 送信実績グラフ (日次/月次)
お知らせ /dashboard/notices 運営からの通知一覧

3. 機能要件

FR-USER-WEB-001: ユーザーダッシュボード (/dashboard)

ログイン後のトップ画面。ユーザーの利用状況を一覧できるサマリーページ。

ウェルカムヘッダー

項目 内容
表示内容 ユーザー名 + プラン種別バッジ
プランバッジ Premium: ゴールド光沢 / Standard: シルバー / Trial: ブルー
表示例 こんにちは、山田太郎さん + Premium バッジ

利用サマリーカード

4枚のKPIカードを横並びで表示する。

カード 算出方法 表示例
今月の送信数 当月の user_activity_logs (execution_complete) から合計 128 件
成功率 成功数 / 総送信数 × 100 94.5%
残りデバイス枠 デバイス上限 - 登録済みデバイス数 1 台
契約残日数 trial_ends_at または subscriptions.ends_at までの日数 23 日 (Premium は 無期限)

送信数グラフ

項目 内容
種別 棒グラフ (Bar Chart)
期間 直近7日間の日別送信数
データソース user_activity_logs (execution_complete)
ライブラリ Recharts

お知らせバナー

項目 内容
表示件数 未読通知の最新3件
表示要素 type バッジ + タイトル + 公開日
クリック動作 /dashboard/notices へ遷移
未読判定 admin_notifications.idreadNoticeIds に含まれないもの

クイックリンク

リンク先 説明
/dashboard/profile プロフィール編集
/dashboard/devices デバイス管理
/dashboard/billing プラン変更

FR-USER-WEB-002: プロフィール (/dashboard/profile)

ユーザーの基本情報を表示・編集する画面。

基本情報セクション

フィールド バリデーション 備考
名前 text 必須, 最大255文字 インライン編集可能
メールアドレス email 必須, ユニーク, 最大255文字 変更時にメール認証を再送

パスワード変更セクション

フィールド バリデーション
現在のパスワード password 必須, 現在のパスワードと一致
新しいパスワード password 必須, 最小8文字
パスワード確認 password 必須, 新しいパスワードと一致

メール変更フロー

1. ユーザーが新しいメールアドレスを入力
2. サーバーが確認メールを新アドレスに送信
3. email_verified_at を NULL にリセット
4. ユーザーが確認リンクをクリック
5. email_verified_at にタイムスタンプを設定
6. メール変更完了

FR-USER-WEB-003: 契約・請求管理 (/dashboard/billing)

サブスクリプションの状態確認、プラン変更、請求履歴の閲覧を行う画面。

現在のプラン表示

表示項目 データソース 表示例
プラン名 is_white_user / subscriptions.stripe_price Premium / Standard
ステータス subscriptions.stripe_status active / trialing / canceled
次回請求日 Stripe API から取得 2026-03-17
デバイス上限数 stripe_subscription_quantity 3 台

プラン変更

項目 内容
操作 デバイス枠の増減 (quantity 変更)
実装方式 Stripe Checkout Session または Stripe Customer Portal へ遷移
増枠 即時反映、日割り課金
減枠 次回請求日に反映

請求履歴

表示項目 データソース
請求日 Stripe Invoice created
金額 Stripe Invoice amount_paid
ステータス Stripe Invoice status (paid / open / void)
PDF Stripe Invoice invoice_pdf URL

Stripe Invoice API を利用して一覧取得する。ページネーション対応 (10件/ページ)。

支払い方法

項目 内容
表示 カードブランド + 末尾4桁 (users.pm_type, users.pm_last_four)
カード変更 Stripe Customer Portal へ遷移

解約

項目 内容
即時解約 サブスクリプションを即座にキャンセル。残期間のアクセスは不可
期末解約 現在の請求期間終了時にキャンセル (ends_at を設定)
確認ダイアログ 解約理由の選択 + 確認ボタン
解約後の表示 解約済み (xxxx年xx月xx日まで利用可能)

FR-USER-WEB-004: デバイス管理 (/dashboard/devices)

登録済みデバイスの一覧表示と管理を行う画面。

デバイス一覧

表示項目 データソース 表示例
デバイス名 user_devices.device_name Chrome on MacOS
UUID user_devices.device_uuid (マスク表示) 550e****-****-****-****-****55440000
最終アクセス日時 user_devices.last_active_at 2026-02-17 14:30
登録日 user_devices.created_at 2026-01-15

操作

操作 説明
デバイス削除 個別のデバイスを削除 (デバイス枠が1つ空く)
削除確認 このデバイスを削除しますか?再度このブラウザで利用するにはデバイス枠が必要です。

上限表示

項目 内容
表示形式 プログレスバー + テキスト
テキスト例 使用中 2 / 上限 3 台
プログレスバー ゴールドグラデーション (使用率に応じて色変化: 80%超で警告色)
Premium 無制限 表示 (プログレスバー非表示)

デバイス名変更

項目 内容
編集方式 インライン編集 (テキストクリックで入力モードに切替)
バリデーション 最大100文字
保存 blur またはEnterキーで即時保存

FR-USER-WEB-005: 利用統計 (/dashboard/stats)

送信実績のグラフ表示と分析を行う画面。

送信数推移グラフ

項目 内容
種別 棒グラフ (Bar Chart)
切り替え 日別 / 月別 トグルスイッチ
データソース user_activity_logs (execution_complete)

送信内訳グラフ

項目 内容
種別 積み上げ棒グラフ (Stacked Bar Chart)
内訳 フォーム送信 (ゴールド) vs メール送信 (シルバー)
データソース user_activity_logs.detailssuccess / mail_sent

成功率推移グラフ

項目 内容
種別 折れ線グラフ (Line Chart)
Y軸 0% ~ 100%
データソース 成功数 / 総送信数 × 100

期間選択

期間 説明
7日 直近7日間 (デフォルト)
30日 直近30日間
90日 直近90日間
全期間 ユーザー登録日からの全データ

期間選択はセグメントボタン (タブ形式) で切り替える。選択中の期間はゴールドアクセントでハイライト。


FR-USER-WEB-006: お知らせ (/dashboard/notices)

運営からのお知らせ通知を一覧表示する画面。

通知一覧

表示項目 データソース 備考
タイトル admin_notifications.title クリックで詳細展開
type バッジ admin_notifications.type info / warning / maintenance / update
公開日 admin_notifications.published_at 2026-02-17 形式
既読/未読 readNoticeIds (Chrome Storage またはサーバー管理) 未読は左に青ドット表示

取得条件

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))

type バッジ

type ラベル
info お知らせ 青 (#3B82F6)
warning 重要 黄 (#F59E0B)
maintenance メンテナンス 紫 (#8B5CF6)
update アップデート 緑 (#22C55E)

既読/未読管理

項目 内容
未読表示 タイトル左に青いドット + 太字
既読化 通知詳細を展開した時点で既読にマーク
保存先 サーバー側で管理 (ユーザーごとの既読テーブル or JSON)

本文レンダリング

項目 内容
形式 Markdown
レンダリング react-markdown またはサーバーサイドで HTML 変換
サニタイズ XSS対策として rehype-sanitize を適用

4. 固有デザイン仕様

ユーザーパネルに固有のリッチUIデザイン要素。デザインシステム (カラートークン・アニメーション等) は全体共通仕様に準拠する。

プランカード

項目 仕様
現在のプラン ゴールドボーダー (2px solid #D4AF37) で囲み
グロー効果 box-shadow: 0 0 20px rgba(212, 175, 55, 0.3)
他のプラン 通常ボーダー + ホバーで薄いハイライト
アニメーション 選択時にスケールアップ + ボーダーフェードイン

デバイス枠プログレスバー

項目 仕様
バー色 ゴールドグラデーション (linear-gradient(90deg, #D4AF37, #F5D060))
背景 rgba(255, 255, 255, 0.08)
高さ 8px, border-radius: 4px
警告表示 使用率80%超で赤グラデーション (linear-gradient(90deg, #EF4444, #F87171))
アニメーション 初回表示時に左から右へスライドイン (500ms, easeOut)

請求履歴ステータスドット

ステータス アニメーション
paid 緑 (#22C55E) 緑の点滅パルスアニメーション (1.5s loop)
open 黄 (#F59E0B) なし (静的)
void グレー (#6B7280) なし (静的)
@keyframes pulse-dot {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.6; transform: scale(1.2); }
}
.status-dot-active {
  animation: pulse-dot 1.5s ease-in-out infinite;
}

お知らせカード

type アイコン 左ボーダー色 背景ティント
info Info (Lucide) 青 (#3B82F6) rgba(59, 130, 246, 0.05)
warning AlertTriangle (Lucide) 黄 (#F59E0B) rgba(245, 158, 11, 0.05)
maintenance Wrench (Lucide) 紫 (#8B5CF6) rgba(139, 92, 246, 0.05)
update Sparkles (Lucide) 緑 (#22C55E) rgba(34, 197, 94, 0.05)

カードの左ボーダーは border-left: 4px solid {color} で表現する。

統計数値

項目 仕様
数値フォント text-4xl font-bold font-variant-numeric: tabular-nums
カウントアップ Framer Motion animate で0から目標値まで500msかけてカウントアップ
前期比バッジ 上昇: 緑背景 + ArrowUp アイコン / 下降: 赤背景 + ArrowDown アイコン
バッジ形式 +12.3% または -5.1% のテキスト
アニメーション バッジ出現時にフェードイン + スライドアップ (200ms)

5. ルーティング

すべてのルートは Laravel Inertia.js を使用した GET リクエストでレンダリングする。

メソッド URL Inertia コンポーネント 説明
GET /dashboard Dashboard/Index ユーザーダッシュボード
GET /dashboard/profile Dashboard/Profile プロフィール編集
PUT /dashboard/profile - プロフィール更新 (API)
PUT /dashboard/profile/password - パスワード変更 (API)
GET /dashboard/billing Dashboard/Billing 契約・請求管理
POST /dashboard/billing/checkout - Stripe Checkout セッション作成 (API)
POST /dashboard/billing/portal - Stripe Customer Portal セッション作成 (API)
POST /dashboard/billing/cancel - サブスクリプション解約 (API)
GET /dashboard/devices Dashboard/Devices デバイス管理
PUT /dashboard/devices/{id} - デバイス名変更 (API)
DELETE /dashboard/devices/{id} - デバイス削除 (API)
GET /dashboard/stats Dashboard/Stats 利用統計
GET /dashboard/stats/data - 統計データ JSON (非同期取得用)
GET /dashboard/notices Dashboard/Notices お知らせ一覧
POST /dashboard/notices/{id}/read - お知らせ既読マーク (API)

ミドルウェア設定

// routes/web.php

Route::middleware(['auth', 'verified'])->prefix('dashboard')->group(function () {
    // ダッシュボード
    Route::get('/', [DashboardController::class, 'index'])->name('dashboard');

    // プロフィール
    Route::get('/profile', [ProfileController::class, 'edit'])->name('dashboard.profile');
    Route::put('/profile', [ProfileController::class, 'update'])->name('dashboard.profile.update');
    Route::put('/profile/password', [ProfileController::class, 'updatePassword'])->name('dashboard.profile.password');

    // 契約・請求管理
    Route::get('/billing', [BillingController::class, 'index'])->name('dashboard.billing');
    Route::post('/billing/checkout', [BillingController::class, 'checkout'])->name('dashboard.billing.checkout');
    Route::post('/billing/portal', [BillingController::class, 'portal'])->name('dashboard.billing.portal');
    Route::post('/billing/cancel', [BillingController::class, 'cancel'])->name('dashboard.billing.cancel');

    // デバイス管理
    Route::get('/devices', [DeviceController::class, 'index'])->name('dashboard.devices');
    Route::put('/devices/{device}', [DeviceController::class, 'update'])->name('dashboard.devices.update');
    Route::delete('/devices/{device}', [DeviceController::class, 'destroy'])->name('dashboard.devices.destroy');

    // 利用統計
    Route::get('/stats', [StatsController::class, 'index'])->name('dashboard.stats');
    Route::get('/stats/data', [StatsController::class, 'data'])->name('dashboard.stats.data');

    // お知らせ
    Route::get('/notices', [NoticeController::class, 'index'])->name('dashboard.notices');
    Route::post('/notices/{notice}/read', [NoticeController::class, 'markAsRead'])->name('dashboard.notices.read');
});

6. Inertia コンポーネント構成

resources/js/pages/Dashboard/
├── Index.tsx              # ダッシュボード (FR-USER-WEB-001)
├── Profile.tsx            # プロフィール (FR-USER-WEB-002)
├── Billing.tsx            # 契約・請求管理 (FR-USER-WEB-003)
├── Devices.tsx            # デバイス管理 (FR-USER-WEB-004)
├── Stats.tsx              # 利用統計 (FR-USER-WEB-005)
├── Notices.tsx            # お知らせ (FR-USER-WEB-006)
└── components/
    ├── DashboardLayout.tsx    # 共通レイアウト (サイドバー + ヘッダー)
    ├── SummaryCard.tsx        # KPIサマリーカード
    ├── PlanBadge.tsx          # プラン種別バッジ
    ├── DeviceProgressBar.tsx  # デバイス枠プログレスバー
    ├── NoticeBanner.tsx       # お知らせバナー
    ├── NoticeCard.tsx         # お知らせカード (type別デザイン)
    ├── SendChart.tsx          # 送信数グラフ
    ├── SuccessRateChart.tsx   # 成功率グラフ
    ├── BreakdownChart.tsx     # 送信内訳グラフ
    └── PeriodSelector.tsx     # 期間選択セグメントボタン