SavvyBot Phase 5
管理ダッシュボード実装
AI / チャットボット開発フロントエンド開発 / フルスタック2025年10月24-25日2025-11-07
Next.js 15 + Supabase Authで管理ダッシュボードを実装。使用量可視化、グループ管理、設定ページを2日間で完成。プロダクションビルド1.5秒、TypeScript型エラー0件を達成。
Technologies Used
Next.js 15ReactTypeScriptTailwind CSSshadcn/uiRechartsSupabase AuthPostgreSQL RLS
SavvyBot Phase 5 ― 管理ダッシュボード実装
← Phase 3-4へ | Phase 6へ → | プロジェクト概要
概要
Phase 5では、SaaS化に向けた管理ダッシュボードを実装しました。2日間の集中開発で、公式Webサイト、認証システム、データ可視化ダッシュボードを完成させました。
達成事項:
- 公式Webサイト・ランディングページ実装
- Supabase Auth統合(email/password認証)
- 管理ダッシュボード実装(使用量、グループ管理、設定)
- データ可視化(Recharts)
- プロダクションビルド成功(1.5秒、TypeScript型エラー0件)
Phase 5.1: 公式Webサイト LP実装(完了 - 2025年10月19日)
実装内容
ランディングページ構成:
- Heroセクション: SavvyBotキャラクター画像配置、キャッチコピー
- Featuresセクション: 4つの主要機能紹介
- How to Useセクション: 3ステップガイド
- Pricingセクション: 3プラン(個人/チーム/ビジネス)
- CTAセクション: 行動喚起
- Footer: ナビゲーションリンク
技術スタック:
- Next.js 15.5.6 (App Router)
- TypeScript 5
- Tailwind CSS 4
- shadcn/ui (Button, Card, Badge)
機能:
- ✅ SEO最適化(メタデータ、OpenGraph)
- ✅ レスポンシブデザイン(モバイルファースト)
- ✅ ダークモード対応
- ✅ Vercelデプロイ準備完了
Phase 5.2: Authentication & Database(完了 - 2025年10月24日)
認証システム
Supabase Auth統合:
// lib/supabase/client.ts (クライアントサイド)
import { createBrowserClient } from '@supabase/ssr'
export const supabase = createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
// lib/supabase/server.ts (サーバーサイド)
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'
export async function createClient() {
const cookieStore = await cookies()
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
get(name: string) {
return cookieStore.get(name)?.value
},
},
}
)
}
認証フロー:
app/(auth)/login/page.tsx: ログインページapp/(auth)/signup/page.tsx: サインアップページapp/auth/callback/route.tsx: OAuth callbackハンドラーmiddleware.ts: ルート保護とリダイレクト
データベーススキーマ
migration: 20251024000000_initial_schema.sql
-- プロフィールテーブル
CREATE TABLE profiles (
id UUID PRIMARY KEY REFERENCES auth.users(id),
display_name TEXT,
email TEXT UNIQUE NOT NULL,
avatar_url TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ユーザー-グループ関連テーブル
CREATE TABLE user_groups (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES profiles(id),
group_id TEXT NOT NULL,
role TEXT NOT NULL CHECK (role IN ('owner', 'admin', 'member')),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- グループ設定テーブル
CREATE TABLE group_settings (
group_id TEXT PRIMARY KEY,
mode TEXT NOT NULL DEFAULT 'group',
auto_extraction BOOLEAN NOT NULL DEFAULT true,
auto_minutes BOOLEAN NOT NULL DEFAULT false,
auto_questions BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
Row Level Security (RLS) Policies
ユーザー別データ分離:
-- プロフィールRLS
CREATE POLICY "Users can view own profile"
ON profiles FOR SELECT
USING (auth.uid() = id);
CREATE POLICY "Users can update own profile"
ON profiles FOR UPDATE
USING (auth.uid() = id);
-- ユーザーグループRLS
CREATE POLICY "Users can view own groups"
ON user_groups FOR SELECT
USING (user_id = auth.uid());
-- 使用量ログRLS
CREATE POLICY "Users can view own usage"
ON usage_logs FOR SELECT
USING (
group_id IN (
SELECT group_id
FROM user_groups
WHERE user_id = auth.uid()
)
);
Phase 5.3: Dashboard Implementation(完了 - 2025年10月24-25日)
5.3.1: Landing Page(完了 - 2025年10月24日)
実装内容:
- ランディングページ実装(Hero, Features, CTA)
- Footerコンポーネント
- ドキュメントページ(Quick Start, Commands, FAQ)
5.3.2: Dashboard Layout(完了 - 2025年10月24日)
実装内容:
app/(dashboard)/layout.tsx: ダッシュボードシェルcomponents/dashboard/sidebar.tsx: サイドバーナビゲーションcomponents/dashboard/header.tsx: ヘッダーとユーザーメニュー
機能:
- ✅ ナビゲーションメニュー
- ✅ ユーザープロフィールドロップダウン
- ✅ サインアウト機能
- ✅ レスポンシブデザイン
5.3.3: Dashboard Home(完了 - 2025年10月24日)
実装内容:
- 概要統計表示(グループ数、会話数、トークン、コスト)
- アクティビティフィード
- クイックアクションカード
- ウェルカムメッセージ
// app/(dashboard)/dashboard/page.tsx
export default async function DashboardPage() {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
// グループ数取得
const { count: groupCount } = await supabase
.from('user_groups')
.select('*', { count: 'exact', head: true })
.eq('user_id', user!.id)
// 使用量集計
const { data: usageData } = await supabase
.from('usage_logs')
.select('total_tokens, estimated_cost')
.gte('created_at', thirtyDaysAgo.toISOString())
const totalTokens = usageData?.reduce((sum, log) => sum + log.total_tokens, 0)
const totalCost = usageData?.reduce((sum, log) => sum + log.estimated_cost, 0)
return (
<div>
<StatsCard title="グループ数" value={groupCount} />
<StatsCard title="トークン使用量" value={totalTokens.toLocaleString()} />
<StatsCard title="推定コスト" value={`¥${(totalCost * 150).toFixed(2)}`} />
</div>
)
}
5.3.4: Usage Dashboard(完了 - 2025年10月25日)
実装内容:
- 期間フィルター(7/30/90日)
- トークン使用量バーチャート(Recharts)
- コストトレンドラインチャート
- グループ別統計テーブル
- データ集計とゼロ埋め処理
コンポーネント:
app/(dashboard)/dashboard/usage/page.tsx: 使用量ページcomponents/dashboard/usage-charts.tsx: Rechartsグラフcomponents/dashboard/period-filter.tsx: 期間選択components/dashboard/group-stats-table.tsx: 統計テーブル
技術的課題と解決:
- Recharts TypeScript型定義: 公式ドキュメント参照で解決
- カスタムツールチップ:
contentプロップで実装 - 日付連続性: ゼロ埋め処理で欠損日をカバー
// ゼロ埋め処理
function fillMissingDates(data: DailyUsage[], days: number): DailyUsage[] {
const today = new Date()
const startDate = new Date(today.getTime() - days * 24 * 60 * 60 * 1000)
const filled: DailyUsage[] = []
for (let i = 0; i < days; i++) {
const date = new Date(startDate.getTime() + i * 24 * 60 * 60 * 1000)
const dateStr = date.toISOString().split('T')[0]
const existing = data.find(d => d.date === dateStr)
filled.push(existing || {
date: dateStr,
total_tokens: 0,
total_cost: 0,
request_count: 0,
})
}
return filled
}
5.3.5: Group Management UI(完了 - 2025年10月25日)
実装内容:
- グループ一覧ページ(カード表示)
- グループ詳細ページ(統計 + 設定)
- 設定エディター(権限ベース)
- モード選択(personal/group)
- 自動機能トグル(4種類)
コンポーネント:
app/(dashboard)/dashboard/groups/page.tsx: グループ一覧app/(dashboard)/dashboard/groups/[groupId]/page.tsx: グループ詳細components/dashboard/group-settings-editor.tsx: 設定エディター
権限システム:
// owner/adminのみ設定変更可能
const canEdit = userRole === 'owner' || userRole === 'admin'
<Switch
checked={settings.auto_extraction}
onCheckedChange={(checked) => handleSettingChange('auto_extraction', checked)}
disabled={!canEdit}
/>
楽観的UI更新:
const [localSettings, setLocalSettings] = useState(settings)
const handleSettingChange = async (key: string, value: any) => {
// 楽観的更新
setLocalSettings({ ...localSettings, [key]: value })
// サーバー更新
const { error } = await supabase
.from('group_settings')
.update({ [key]: value })
.eq('group_id', groupId)
if (error) {
// ロールバック
setLocalSettings(settings)
toast.error('設定の更新に失敗しました')
}
}
5.3.6: Settings Page(完了 - 2025年10月25日)
実装内容:
- ユーザープロフィール設定
- LINE連携状態表示
- 通知設定(メール通知トグル)
- アカウント管理(パスワード変更、アカウント削除)
コンポーネント:
app/(dashboard)/dashboard/settings/page.tsx: 設定ページcomponents/dashboard/user-profile-settings.tsx: プロフィール設定components/dashboard/line-connection-status.tsx: LINE連携状態components/dashboard/notification-settings.tsx: 通知設定components/dashboard/account-management.tsx: アカウント管理
セキュリティ機能:
- 2段階確認フロー(アカウント削除)
- パスワード変更(Supabase Auth Admin API)
- リアルタイムDB更新
5.3.7: Final Testing & Integration(完了 - 2025年10月25日)
達成事項:
- ✅ 全20ルートの動作確認
- ✅ 全10ダッシュボードコンポーネントの検証
- ✅ ナビゲーションフローの確認
- ✅ プロダクションビルド成功(1.5秒)
- ✅ TypeScript型チェック完了(0エラー)
- ✅ ESLint検証完了(0エラー in dashboard code)
ビルド統計:
✓ Compiled successfully in 1464ms
✓ All 20 routes generated
✓ 0 TypeScript errors
✓ 0 ESLint errors (dashboard)
Total Bundle Size: 102 kB (shared)
Largest Page: /dashboard/usage (105 kB - Recharts)
All Other Pages: < 6 kB each
Phase 5の成果
完了した機能
認証・認可:
- Email/passwordサインアップ・ログイン
- セッション管理
- ルート保護
- ロールベース権限制御(owner/admin/member)
データ可視化:
- 使用量ダッシュボード(トークン・コスト・グラフ)
- 期間フィルター(7/30/90日)
- Rechartsチャート(バー・ライン)
- グループ別統計テーブル
グループ管理:
- グループ一覧・詳細表示
- グループ設定エディター
- モード切替(personal/group)
- 自動機能トグル
設定管理:
- ユーザープロフィール編集
- LINE連携状態表示
- 通知設定
- アカウント管理
UI/UX特徴
- モダンなデザイン(shadcn/ui)
- ダークモード対応
- レスポンシブレイアウト
- アクセシブルフォーム
- 一貫したデザインシステム
技術的成果
- プロダクションビルド: 1.5秒
- バンドルサイズ: 最適化済み
- 静的ページ生成: 100%成功
- TypeScript型安全性: 100%
- RLSによるマルチテナント実装
- 楽観的UI更新パターン
Phase 5完了日: 2025年10月25日 開発期間: 2日間(10月24-25日) 主な技術的成果: Next.js 15、Supabase Auth、Recharts統合、RLS実装、プロダクションビルド成功