Skip to main content

phase-6-ui-integration

Implement frontend UI and integrate with backend APIs — state management and API clients. Triggers: UI integration, frontend-backend, API client default: bkit:pipeline-guide frontend: bkit:frontend-architect

インストールへ移動

ソース情報

リポジトリ
ww-w-ai/bkit-claude-code
ソースの最終更新活動
2026年8月8日 20:14
検出された SKILL.md の言語
英語
スター
601
フォーク
154

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
phase-6-ui-integration
classification
capability
classification-reason
Pattern guidance may overlap with model's built-in knowledge as it improves
deprecation-risk
medium
effort
medium
description
Implement frontend UI and integrate with backend APIs — state management and API clients. Triggers: UI integration, frontend-backend, API client default: bkit:pipeline-guide frontend: bkit:frontend-architect
allowed-tools
["Read","Write","Edit","Glob","Grep","Bash"]
user-invocable
false
next-skill
phase-7-seo-security
pdca-phase
do
task-template
[Phase-6] {feature}
# Phase 6: UI Implementation + API Integration > Actual UI implementation and API integration ## Purpose Implement actual screens using design system components and integrate with APIs. ## What to Do in This Phase 1. **Page Implementation**: Develop each screen 2. **State Management**: Handle client state 3. **API Integration**: Call backend APIs 4. **Error Handling**: Handle loading and error states ## Deliverables ``` src/ ├── pages/ # Page components │ ├── index.tsx │ ├── login.tsx │ └── ... ├── features/ # Feature-specific components │ ├── auth/ │ ├── product/ │ └── ... └── hooks/ # API call hooks ├── useAuth.ts └── useProducts.ts docs/03-analysis/ └── ui-qa.md # QA results ``` ## PDCA Application - **Plan**: Define screens/features to implement - **Design**: Component structure, state management design - **Do**: UI implementation + API integration - **Check**: Zero Script QA - **Act**: Fix bugs and proceed to Phase 7 ## Level-wise Application | Level | Application Method | |-------|-------------------| | Starter | Static UI only (no API integration) | | Dynamic | Full integration | | Enterprise | Full integration + optimization | ## API Client Architecture ### Why is a Centralized API Client Needed? | Problem (Scattered API Calls) | Solution (Centralized Client) | |------------------------------|------------------------------| | Duplicate error handling logic | Common error handler | | Distributed auth token handling | Automatic token injection | | Inconsistent response formats | Standardized response types | | Multiple changes when endpoint changes | Single point of management | | Difficult testing/mocking | Easy mock replacement | ### 3-Layer API Client Structure ``` ┌─────────────────────────────────────────────────────────┐ │ UI Components │ │ (pages, features, hooks) │ ├─────────────────────────────────────────────────────────┤ │ Service Layer │ │ (Domain-specific API call functions) │ │ authService, productService, orderService, ... │ ├─────────────────────────────────────────────────────────┤ │ API Client Layer │ │ (Common settings, interceptors, error handling) │ │ apiClient (axios/fetch wrapper) │ └─────────────────────────────────────────────────────────┘ ``` ### Folder Structure ``` src/ ├── lib/ │ └── api/ │ ├── client.ts # API client (axios/fetch wrapper) │ ├── interceptors.ts # Request/response interceptors │ └── error-handler.ts # Error handling logic ├── services/ │ ├── auth.service.ts # Auth-related APIs │ ├── product.service.ts # Product-related APIs │ └── order.service.ts # Order-related APIs ├── types/ │ ├── api.types.ts # Common API types │ ├── auth.types.ts # Auth domain types │ └── product.types.ts # Product domain types └── hooks/ ├── useAuth.ts # Hooks using Service └── useProducts.ts ``` --- ## API Client Implementation ### 1. Basic API Client (lib/api/client.ts) ```typescript // lib/api/client.ts import { ApiError, ApiResponse } from '@/types/api.types'; const BASE_URL = process.env.NEXT_PUBLIC_API_URL || '/api'; interface RequestConfig extends RequestInit { params?: Record<string, string>; } class ApiClient { private baseUrl: string; constructor(baseUrl: string) { this.baseUrl = baseUrl; } private async request<T>( endpoint: string, config: RequestConfig = {} ): Promise<ApiResponse<T>> { const { params, ...init } = config; // URL parameter handling const url = new URL(`${this.baseUrl}${endpoint}`); if (params) { Object.entries(params).forEach(([key, value]) => { url.searchParams.append(key, value); }); } // Default header settings const headers = new Headers(init.headers); if (!headers.has('Content-Type')) { headers.set('Content-Type', 'application/json'); } // Automatic auth token injection const token = this.getAuthToken(); if (token) { headers.set('Authorization', `Bearer ${token}`); } try { const response = await fetch(url.toString(), { ...init, headers, }); return this.handleResponse<T>(response); } catch (error) { throw this.handleNetworkError(error); } } private async handleResponse<T>(response: Response): Promise<ApiResponse<T>> { const data = await response.json(); if (!response.ok) { throw new ApiError( data.error?.code || 'UNKNOWN_ERROR', data.error?.message || 'An error occurred', response.status, data.error?.details ); } return data as ApiResponse<T>; } private handleNetworkError(error: unknown): ApiError { if (error instanceof TypeError && error.message === 'Failed to fetch') { return new ApiError('NETWORK_ERROR', 'Please check your network connection.', 0); } return new ApiError('UNKNOWN_ERROR', 'An unknown error occurred.', 0); } private getAuthToken(): string | null { if (typeof window === 'undefined') return null; return localStorage.getItem('auth_token'); } // HTTP method wrappers get<T>(endpoint: string, params?: Record<string, string>) { return this.request<T>(endpoint, { method: 'GET', params }); } post<T>(endpoint: string, body?: unknown) { return this.request<T>(endpoint, { method: 'POST', body: JSON.stringify(body), }); } put<T>(endpoint: string, body?: unknown) { return this.request<T>(endpoint, { method: 'PUT', body: JSON.stringify(body), }); } patch<T>(endpoint: string, body?: unknown) { return this.request<T>(endpoint, { method: 'PATCH', body: JSON.stringify(body), }); } delete<T>(endpoint: string) { return this.request<T>(endpoint, { method: 'DELETE' }); } } export const apiClient = new ApiClient(BASE_URL); ``` ### 2. Common Type Definitions (types/api.types.ts) ```typescript // types/api.types.ts // ===== Standard API Response Format (matches Phase 4) ===== /** Success response */ export interface ApiResponse<T> { data: T; meta?: { timestamp: string; requestId?: string; }; } /** Paginated response */ export interface PaginatedResponse<T> extends ApiResponse<T[]> { pagination: { page: number; limit: number; total: number; totalPages: number; }; } /** Error response */ export interface ApiErrorResponse { error: { code: string; message: string; details?: Array<{ field: string; message: string; }>; }; } // ===== Error Class ===== export class ApiError extends Error { constructor( public code: string, message: string, public status: number, public details?: Array<{ field: string; message: string }> ) { super(message); this.name = 'ApiError'; } /** Check if validation error */ isValidationError(): boolean { return this.code === 'VALIDATION_ERROR' && !!this.details; } /** Check if auth error */ isAuthError(): boolean { return this.status === 401 || this.code === 'UNAUTHORIZED'; } /** Check if forbidden error */ isForbiddenError(): boolean { return this.status === 403 || this.code === 'FORBIDDEN'; } /** Check if not found error */ isNotFoundError(): boolean { return this.status === 404 || this.code === 'NOT_FOUND'; } } // ===== Common Error Codes ===== export const ERROR_CODES = { // Client errors VALIDATION_ERROR: 'VALIDATION_ERROR', UNAUTHORIZED: 'UNAUTHORIZED', FORBIDDEN: 'FORBIDDEN', NOT_FOUND: 'NOT_FOUND', CONFLICT: 'CONFLICT', // Server errors INTERNAL_ERROR: 'INTERNAL_ERROR', SERVICE_UNAVAILABLE: 'SERVICE_UNAVAILABLE', // Network errors NETWORK_ERROR: 'NETWORK_ERROR', TIMEOUT_ERROR: 'TIMEOUT_ERROR', } as const; export type ErrorCode = typeof ERROR_CODES[keyof typeof ERROR_CODES]; ``` --- ## Service Layer Pattern ### Domain-specific Service Separation ```typescript // services/auth.service.ts import { apiClient } from '@/lib/api/client'; import { User, LoginRequest, LoginResponse, SignupRequest } from '@/types/auth.types'; export const authService = { /** Login */ login(credentials: LoginRequest) { return apiClient.post<LoginResponse>('/auth/login', credentials); }, /** Signup */ signup(data: SignupRequest) { return apiClient.post<User>('/auth/signup', data); }, /** Logout */ logout() { return apiClient.post<void>('/auth/logout'); }, /** Get current user info */ getMe() { return apiClient.get<User>('/auth/me'); }, /** Refresh token */ refreshToken() { return apiClient.post<LoginResponse>('/auth/refresh'); }, }; // services/product.service.ts import { apiClient } from '@/lib/api/client'; import { Product, ProductFilter, CreateProductRequest } from '@/types/product.types'; import { PaginatedResponse } from '@/types/api.types'; export const productService = { /** Get product list */ getList(filter?: ProductFilter) { const params = filter ? { page: String(filter.page || 1), limit: String(filter.limit || 20), ...(filter.category && { category: filter.category }), ...(filter.search && { search: filter.search }), } : undefined; return apiClient.get<PaginatedResponse<Product>>('/products', params); }, /** Get product details */ getById(id: string) { return apiClient.get<Product>(`/products/${id}`); }, /** Create product */ create(data: CreateProductRequest) { return apiClient.post<Product>('/products', data); }, /** Update product */ update(id: string, data: Partial<CreateProductRequest>) { return apiClient.patch<Product>(`/products/${id}`, data); }, /** Delete product */ delete(id: string) { return apiClient.delete<void>(`/products/${id}`); }, }; ``` --- ## Error Handling Pattern ### Global Error Handler ```typescript // lib/api/error-handler.ts import { ApiError, ERROR_CODES } from '@/types/api.types'; import { toast } from 'sonner'; // or another toast library interface ErrorHandlerOptions { showToast?: boolean; redirectOnAuth?: boolean; customMessages?: Record<string, string>; } export function handleApiError( error: unknown, options: ErrorHandlerOptions = {} ): void { const { showToast = true, redirectOnAuth = true, customMessages = {} } = options; if (!(error instanceof ApiError)) { console.error('Unexpected error:', error); if (showToast) { toast.error('An unknown error occurred.'); } return; } // Use custom message if available const message = customMessages[error.code] || error.message; // Handle by error type
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る