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
Ir a la instalación Skills Marketplace Descubre y explora habilidades de IA creadas por la comunidad.
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Copiar promptMostrar detalles del prompt Un comando directo omite el prompt de revisión. Revisa el origen antes de ejecutarlo.
npx skills add https://github.com/popup-studio-ai/bkit-claude-code --skill phase-6-ui-integrationEl comando permanece en una sola línea. Desplázate horizontalmente para revisarlo antes de copiarlo.
¿Prefieres una copia local? Descarga los archivos que SkillsMP tiene disponibles ahora.
Descargar Zip Descargando... Más de este repositorio bkend.ai authentication — email/social login, JWT tokens, RBAC, session management.
Triggers: bkend auth, bkend login, bkend signup, bkend JWT, bkend RBAC
bkend.ai project tutorials (todo to SaaS) and common error troubleshooting.
Triggers: bkend tutorial, bkend cookbook, bkend troubleshooting
bkend.ai database — CRUD, column types, filtering, sorting, relations, indexing.
Triggers: bkend table, bkend CRUD, bkend column, bkend relation, bkend data
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
Page Implementation : Develop each screen
State Management : Handle client state
API Integration : Call backend APIs
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)
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;
const url = new URL (`${this .baseUrl} ${endpoint} ` );
if (params) {
Object .entries (params).forEach (([key, value] ) => {
url.searchParams .append (key, value);
});
}
const headers = new Headers (init.headers );
if (!headers.has ('Content-Type' )) {
headers.set ('Content-Type' , 'application/json' );
}
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' );
}
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)
export interface ApiResponse <T> {
data : T;
meta ?: {
timestamp : string ;
requestId ?: string ;
};
}
export interface PaginatedResponse <T> extends ApiResponse <T[]> {
pagination : {
page : number ;
limit : number ;
total : number ;
totalPages : number ;
};
}
export interface ApiErrorResponse {
error : {
code : string ;
message : string ;
details ?: Array <{
field : string ;
message : string ;
}>;
};
}
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' ;
}
isValidationError (): boolean {
return this .code === 'VALIDATION_ERROR' && !!this .details ;
}
isAuthError (): boolean {
return this .status === 401 || this .code === 'UNAUTHORIZED' ;
}
isForbiddenError (): boolean {
return this .status === 403 || this .code === 'FORBIDDEN' ;
}
isNotFoundError (): boolean {
return this .status === 404 || this .code === 'NOT_FOUND' ;
}
}
export const ERROR_CODES = {
VALIDATION_ERROR : 'VALIDATION_ERROR' ,
UNAUTHORIZED : 'UNAUTHORIZED' ,
FORBIDDEN : 'FORBIDDEN' ,
NOT_FOUND : 'NOT_FOUND' ,
CONFLICT : 'CONFLICT' ,
INTERNAL_ERROR : 'INTERNAL_ERROR' ,
SERVICE_UNAVAILABLE : 'SERVICE_UNAVAILABLE' ,
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
import { apiClient } from '@/lib/api/client' ;
import { User , LoginRequest , LoginResponse , SignupRequest } from '@/types/auth.types' ;
export const authService = {
login (credentials : LoginRequest ) {
return apiClient.post <LoginResponse >('/auth/login' , credentials);
},
signup (data : SignupRequest ) {
return apiClient.post <User >('/auth/signup' , data);
},
logout ( ) {
return apiClient.post <void >('/auth/logout' );
},
getMe ( ) {
return apiClient.get <User >('/auth/me' );
},
refreshToken ( ) {
return apiClient.post <LoginResponse >('/auth/refresh' );
},
};
import { apiClient } from '@/lib/api/client' ;
import { Product , ProductFilter , CreateProductRequest } from '@/types/product.types' ;
import { PaginatedResponse } from '@/types/api.types' ;
export const productService = {
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);
},
getById (id : string ) {
return apiClient.get <Product >(`/products/${id} ` );
},
create (data : CreateProductRequest ) {
return apiClient.post <Product >('/products' , data);
},
update (id : string , data : Partial <CreateProductRequest > ) {
return apiClient.patch <Product >(`/products/${id} ` , data);
},
delete (id : string ) {
return apiClient.delete <void >(`/products/${id} ` );
},
};
Error Handling Pattern
Global Error Handler
import { ApiError , ERROR_CODES } from '@/types/api.types' ;
import { toast } from 'sonner' ;
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 ;
}
const message = customMessages[error.code ] || error.message ;
switch (error.code ) {
case ERROR_CODES .UNAUTHORIZED :
if (redirectOnAuth && typeof window !== 'undefined' ) {
localStorage .removeItem ('auth_token' );
window .location .href = '/login' ;
}
break ;
case ERROR_CODES .FORBIDDEN :
if (showToast) toast.error ('You do not have permission.' );
break ;
case ERROR_CODES .NOT_FOUND :
if (showToast) toast.error ('The requested resource was not found.' );
break ;
case ERROR_CODES .VALIDATION_ERROR :
break ;
case ERROR_CODES .NETWORK_ERROR :
if (showToast) toast.error ('Please check your network connection.' );
break ;
default :
if (showToast) toast.error (message);
}
if (process.env .NODE_ENV === 'development' ) {
console .error (`[API Error] ${error.code} :` , {
message : error.message ,
status : error.status ,
details : error.details ,
});
}
}
Error Handling in Hooks
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' ;
import { productService } from '@/services/product.service' ;
import { handleApiError } from '@/lib/api/error-handler' ;
import { ProductFilter } from '@/types/product.types' ;
export function useProducts (filter ?: ProductFilter ) {
return useQuery ({
queryKey : ['products' , filter],
queryFn : () => productService.getList (filter),
throwOnError : false ,
meta : {
errorHandler : (error : unknown ) => handleApiError (error),
},
});
}
export function useCreateProduct ( ) {
const queryClient = useQueryClient ();
return useMutation ({
mutationFn : productService.create ,
onSuccess : () => {
queryClient.invalidateQueries ({ queryKey : ['products' ] });
},
onError : (error ) => {
handleApiError (error, {
customMessages : {
CONFLICT : 'Product name already exists.' ,
},
});
},
});
}
Client-Server Type Sharing
Methods for Type Consistency Method 1: Shared Package (Monorepo)
├── packages/
│ └── shared-types/ # Common types
│ ├── api.types.ts
│ ├── auth.types.ts
│ └── product.types.ts
├── apps/
│ ├── web/ # Frontend
│ └── api/ # Backend
Method 2: Auto-generate Types from API Spec
├── openapi.yaml # OpenAPI spec
└── scripts/
└── generate-types.ts # Type auto-generation script
Method 3: tRPC / GraphQL CodeGen
└── Auto-infer types from schema
Type Definition Example
export interface User {
id : string ;
email : string ;
name : string ;
role : 'user' | 'admin' ;
createdAt : string ;
updatedAt : string ;
}
export interface LoginRequest {
email : string ;
password : string ;
}
export interface LoginResponse {
user : User ;
token : string ;
expiresAt : string ;
}
export interface SignupRequest {
email : string ;
password : string ;
name : string ;
termsAgreed : boolean ;
}
API Integration Patterns
Basic Pattern (fetch) async function getProducts ( ) {
const response = await fetch ('/api/products' );
if (!response.ok ) throw new Error ('Failed to fetch' );
return response.json ();
}
React Query Pattern function useProducts ( ) {
return useQuery ({
queryKey : ['products' ],
queryFn : getProducts,
});
}
SWR Pattern function useProducts ( ) {
return useSWR ('/api/products' , fetcher);
}
State Management Guide Server state (API data) → React Query / SWR
Client state (UI state) → useState / useReducer
Global state (auth, etc.) → Context / Zustand
Form state → React Hook Form
Zero Script QA Application Validate UI behavior with logs:
[UI] Login button clicked
[STATE] isLoading: true
[API] POST /api/auth/login
[RESPONSE] { token: "...", user: {...} }
[STATE] isLoading: false, isLoggedIn: true
[NAVIGATE] → /dashboard
[RESULT] ✅ Login successful
API Integration Checklist
Architecture
Error Handling
Coding Conventions
Template See templates/pipeline/phase-6-ui.template.md
Next Phase Phase 7: SEO/Security → Features are complete, now optimize and strengthen security