dashboard-feature-implementation
について
このスキルは、Orientモノレポでダッシュボード機能を実装するための包括的なガイドを提供し、バックエンドとフロントエンドの両方の変更をカバーしています。サービス、APIルート、UI要素、ナビゲーションの更新を必要とする新しいタブ、ビュー、ページ、またはコンポーネントを追加する際に使用してください。コマンドパレットやルーティングを含むフルスタック全体での適切な統合を保証します。
クイックインストール
Claude Code
推奨/plugin add https://github.com/majiayu000/claude-skill-registrygit clone https://github.com/majiayu000/claude-skill-registry.git ~/.claude/skills/dashboard-feature-implementationこのコマンドをClaude Codeにコピー&ペーストしてスキルをインストールします
ドキュメント
Dashboard Feature Implementation
Guide for adding features to the Orient dashboard across backend and frontend.
Architecture Overview
packages/dashboard/ # Backend
├── src/services/ # Business logic
│ └── <feature>Service.ts # Service with singleton pattern
└── src/server/routes/
├── <feature>.routes.ts # Express routes
└── index.ts # Route exports
packages/dashboard-frontend/ # Frontend
├── src/api.ts # API types and functions
├── src/routes.ts # Route definitions
├── src/App.tsx # Main app with routing
└── src/components/
├── Layout/Sidebar.tsx # Navigation
└── <FeatureName>Tab.tsx # Tab component
└── <FeatureName>/ # Sub-components
Implementation Checklist
Backend
- Create service in
packages/dashboard/src/services/<feature>Service.ts - Create routes in
packages/dashboard/src/server/routes/<feature>.routes.ts - Export routes in
packages/dashboard/src/server/routes/index.ts - Register routes in
packages/dashboard/src/server/routes.ts
Frontend
- Add types and API functions in
packages/dashboard-frontend/src/api.ts - Update
GlobalViewtype and routes inpackages/dashboard-frontend/src/routes.ts - Add navigation link in
packages/dashboard-frontend/src/components/Layout/Sidebar.tsx - Add route rendering and command in
packages/dashboard-frontend/src/App.tsx - Create main component
packages/dashboard-frontend/src/components/<Feature>Tab.tsx - Create sub-components in
packages/dashboard-frontend/src/components/<Feature>/
Backend Patterns
Service Pattern (Singleton)
// packages/dashboard/src/services/featureService.ts
import { createServiceLogger } from '@orient/core';
const logger = createServiceLogger('feature-service');
export class FeatureService {
constructor(private db: MessageDatabase) {}
async getData(): Promise<FeatureData> {
// Implementation
}
}
let instance: FeatureService | null = null;
export function initFeatureService(db: MessageDatabase): FeatureService {
instance = new FeatureService(db);
return instance;
}
export function getFeatureService(): FeatureService {
if (!instance) throw new Error('Service not initialized');
return instance;
}
Routes Pattern
// packages/dashboard/src/server/routes/feature.routes.ts
import { Router, Request, Response } from 'express';
import { createServiceLogger } from '@orient/core';
import { getFeatureService } from '../../services/featureService.js';
const logger = createServiceLogger('feature-routes');
export function createFeatureRoutes(
requireAuth: (req: Request, res: Response, next: () => void) => void
): Router {
const router = Router();
router.get('/data', requireAuth, async (_req: Request, res: Response) => {
try {
const service = getFeatureService();
const data = await service.getData();
res.json(data);
} catch (error) {
logger.error('Failed to get data', { error: String(error) });
res.status(500).json({ error: 'Failed to get data' });
}
});
return router;
}
Register Routes
// In routes/index.ts - add export
export { createFeatureRoutes } from './feature.routes.js';
// In routes.ts - import and register
import { createFeatureRoutes } from './routes/index.js';
import { initFeatureService } from '../services/featureService.js';
// In setupApiRoutes function:
initFeatureService(db);
router.use('/feature', createFeatureRoutes(requireAuth));
Frontend Patterns
API Types and Functions
// In packages/dashboard-frontend/src/api.ts
export interface FeatureData {
items: FeatureItem[];
total: number;
}
export async function getFeatureData(): Promise<FeatureData> {
return apiRequest('/feature/data');
}
export async function updateFeature(id: string, data: Partial<FeatureItem>): Promise<FeatureItem> {
return apiRequest(`/feature/${id}`, {
method: 'PUT',
body: JSON.stringify(data),
});
}
Route Configuration
// In packages/dashboard-frontend/src/routes.ts
// 1. Add to GlobalView union type
export type GlobalView =
| 'billing'
| 'monitoring'
| 'feature' // Add here
| 'settings';
// 2. Add to ROUTES constant
export const ROUTES = {
BILLING: '/billing',
MONITORING: '/monitoring',
FEATURE: '/feature', // Add here
SETTINGS: '/settings',
} as const;
// 3. Add to getRouteState function
if (pathname.startsWith('/feature')) {
return { ...defaultState, globalView: 'feature' };
}
// 4. Add to getRoutePath function
case 'feature':
return ROUTES.FEATURE;
Sidebar Navigation
// In Sidebar.tsx - add to GlobalView type and navigation links
// Add icon + link after existing items:
<Link
to={ROUTES.FEATURE}
className={`w-full flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-md transition-colors ${
isGlobalActive('feature')
? 'bg-primary text-primary-foreground'
: 'text-muted-foreground hover:bg-accent hover:text-accent-foreground'
}`}
>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
{/* Icon path */}
</svg>
Feature Name
</Link>
App.tsx Integration
// Import component
import FeatureTab from './components/FeatureTab';
// Add rendering
{globalView === 'feature' && <FeatureTab />}
// Add command palette entry
cmds.push({
id: 'nav-feature',
label: 'Feature Name',
description: 'Feature description',
category: 'navigation',
keywords: ['keyword1', 'keyword2'],
icon: (<svg>...</svg>),
action: () => navigate(ROUTES.FEATURE),
});
Tab Component Structure
// packages/dashboard-frontend/src/components/FeatureTab.tsx
import { useState, useEffect, useCallback } from 'react';
import { getFeatureData, type FeatureData } from '../api';
export default function FeatureTab() {
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [data, setData] = useState<FeatureData | null>(null);
const [autoRefresh, setAutoRefresh] = useState(false);
const fetchData = useCallback(async () => {
try {
setError(null);
const result = await getFeatureData();
setData(result);
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to load');
} finally {
setLoading(false);
}
}, []);
useEffect(() => { fetchData(); }, [fetchData]);
// Auto-refresh effect
useEffect(() => {
if (!autoRefresh) return;
const interval = setInterval(fetchData, 30000);
return () => clearInterval(interval);
}, [autoRefresh, fetchData]);
if (loading) return <LoadingState />;
if (error) return <ErrorState error={error} onRetry={fetchData} />;
return (
<div className="space-y-6 animate-fade-in">
<Header autoRefresh={autoRefresh} onAutoRefreshChange={setAutoRefresh} onRefresh={fetchData} />
<SummaryCards data={data} />
<DetailCards data={data} />
</div>
);
}
UI Patterns
Loading State
<div className="flex items-center justify-center py-12">
<div className="flex flex-col items-center gap-3">
<div className="spinner" />
<p className="text-sm text-muted-foreground">Loading...</p>
</div>
</div>
Error State
<div className="card p-6">
<div className="flex items-center gap-3 text-destructive">
<svg>...</svg>
<div>
<p className="font-medium">Failed to load</p>
<p className="text-sm text-muted-foreground">{error}</p>
</div>
</div>
<button onClick={onRetry} className="btn btn-secondary mt-4">
Try Again
</button>
</div>
Card Components
<div className="card p-5">
<div className="flex items-center gap-3 mb-4">
<div className="w-8 h-8 rounded-lg bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center">
<svg className="w-4 h-4 text-blue-600 dark:text-blue-400">...</svg>
</div>
<div>
<h3 className="font-semibold">Card Title</h3>
<p className="text-xs text-muted-foreground">Subtitle</p>
</div>
</div>
{/* Card content */}
</div>
Status Badges
<span
className={`px-2 py-1 text-xs font-medium rounded-full ${
status === 'success'
? 'bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400'
: status === 'error'
? 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400'
: 'bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-400'
}`}
>
{statusLabel}
</span>
Common Sub-Tabs Pattern
For features with multiple views:
// In routes.ts
export type FeatureView = 'overview' | 'details' | 'settings';
export const ROUTES = {
FEATURE: '/feature',
FEATURE_OVERVIEW: '/feature/overview',
FEATURE_DETAILS: '/feature/details',
FEATURE_SETTINGS: '/feature/settings',
};
// In App.tsx - render sub-tabs
{globalView === 'feature' && (
<div className="flex gap-1 mb-6 p-1 bg-secondary rounded-lg w-fit border border-border">
<Link to={ROUTES.FEATURE_OVERVIEW} className={...}>Overview</Link>
<Link to={ROUTES.FEATURE_DETAILS} className={...}>Details</Link>
<Link to={ROUTES.FEATURE_SETTINGS} className={...}>Settings</Link>
</div>
)}
Testing
- Type check:
pnpm exec tsc --project packages/dashboard/tsconfig.json --noEmit - Lint:
pnpm exec eslint packages/dashboard/src/... packages/dashboard-frontend/src/... - Manual test:
- Run backend:
pnpm --filter dashboard dev - Run frontend:
pnpm --filter dashboard-frontend dev - Test API:
curl http://localhost:3000/api/feature/data - Navigate to
/dashboard/featurein browser
- Run backend:
GitHub リポジトリ
関連スキル
content-collections
メタThis skill provides a production-tested setup for Content Collections, a TypeScript-first tool that transforms Markdown/MDX files into type-safe data collections with Zod validation. Use it when building blogs, documentation sites, or content-heavy Vite + React applications to ensure type safety and automatic content validation. It covers everything from Vite plugin configuration and MDX compilation to deployment optimization and schema validation.
creating-opencode-plugins
メタThis skill provides the structure and API specifications for creating OpenCode plugins that hook into 25+ event types like commands, files, and LSP operations. It offers implementation patterns for JavaScript/TypeScript modules that intercept and extend the AI assistant's lifecycle. Use it when you need to build event-driven plugins for monitoring, custom handling, or extending OpenCode's capabilities.
evaluating-llms-harness
テストThis Claude Skill runs the lm-evaluation-harness to benchmark LLMs across 60+ standardized academic tasks like MMLU and GSM8K. It's designed for developers to compare model quality, track training progress, or report academic results. The tool supports various backends including HuggingFace and vLLM models.
polymarket
メタThis skill enables developers to build applications with the Polymarket prediction markets platform, including API integration for trading and market data. It also provides real-time data streaming via WebSocket to monitor live trades and market activity. Use it for implementing trading strategies or creating tools that process live market updates.
