Skip to main content
add-frontend-feature Step-by-step guide to add a new feature to the React frontend. Covers TypeScript types, API endpoints, query hooks, mutation hooks, components, routes, and dialogs. Use when creating new UI features connected to backend APIs.
跳到安装 Skills Marketplace 发现并探索由社区构建的 Agent Skills
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/agusmdev/fullstack-ai-template --skill add-frontend-feature命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
下载 Zip 下载中... 同仓库更多 Skills Codebase health scanner and technical debt tracker. Use when the user asks about code quality, technical debt, dead code, large files, god classes, duplicate functions, code smells, naming issues, import cycles, or coupling problems. Also use when asked for a health score, what to fix next, or to create a cleanup plan. Supports 29 languages.
Configure Alembic for async SQLAlchemy migrations with PostgreSQL
Create FastAPI application factory with lifespan, middleware, pagination, and router configuration
name add-frontend-feature description Step-by-step guide to add a new feature to the React frontend. Covers TypeScript types, API endpoints, query hooks, mutation hooks, components, routes, and dialogs. Use when creating new UI features connected to backend APIs.
Add Frontend Feature
Sequential guide for adding a new feature module to the React frontend. The items feature is the canonical reference.
Step 1: Types (types/your-entity.ts)
export interface YourEntity {
id : string
name : string
description : string | null
created_at : string
updated_at : string
}
export interface YourEntityCreate {
name : string
description ?: string
}
export interface YourEntityUpdate {
name ?: string
description ?: string
}
Step 2: API Endpoints (lib/api-endpoints.ts)
export const API = {
YOUR_ENTITIES : {
LIST : '/api/v1/your-entities' ,
CREATE : '/api/v1/your-entities' ,
DETAIL : (id : string ) => `/api/v1/your-entities/${id} ` ,
UPDATE : (id : string ) => `/api/v1/your-entities/${id} ` ,
DELETE : (id : string ) => `/api/v1/your-entities/${id} ` ,
},
} as const
Step 3: Query Keys (lib/query-keys.ts) export const queryKeys = {
yourEntities : {
all : ['your-entities' ] as const ,
list : () => [...queryKeys.yourEntities .all , 'list' ] as const ,
detail : (id : string ) => [...queryKeys.yourEntities .all , 'detail' , id] as const ,
},
}
Step 4: Zod Schema (lib/schemas/your-entity.ts) import { z } from 'zod'
export const yourEntitySchema = z.object ({
name : z.string ().min (1 , 'Name is required' ).max (255 ),
description : z.string ().max (5000 ).optional (),
})
export type YourEntityFormData = z.infer <typeof yourEntitySchema>
Step 5: Query Hook (hooks/queries/useYourEntitiesQuery.ts) import { queryOptions } from '@tanstack/react-query'
import { api } from '@/lib/api-client'
import { API } from '@/lib/api-endpoints'
import { queryKeys } from '@/lib/query-keys'
import type { YourEntity } from '@/types/your-entity'
export const yourEntitiesQueryOptions = ( ) =>
queryOptions ({
queryKey : queryKeys.yourEntities .list (),
queryFn : () => api.get <YourEntity []>(API .YOUR_ENTITIES .LIST ),
staleTime : 1000 * 60 * 5 ,
})
export const yourEntityDetailQueryOptions = (id : string ) =>
queryOptions ({
queryKey : queryKeys.yourEntities .detail (id),
queryFn : () => api.get <YourEntity >(API .YOUR_ENTITIES .DETAIL (id)),
staleTime : 1000 * 60 * 5 ,
})
Step 6: Mutation Hooks (hooks/mutations/useYourEntityMutations.ts) import { useMutation, useQueryClient } from '@tanstack/react-query'
import { api } from '@/lib/api-client'
import { API } from '@/lib/api-endpoints'
import { queryKeys } from '@/lib/query-keys'
import type { YourEntityCreate , YourEntityUpdate } from '@/types/your-entity'
export function useCreateYourEntity ( ) {
const queryClient = useQueryClient ()
return useMutation ({
mutationFn : (data : YourEntityCreate ) =>
api.post (API .YOUR_ENTITIES .CREATE , data),
onSuccess : () => {
queryClient.invalidateQueries ({ queryKey : queryKeys.yourEntities .all })
},
})
}
export function useUpdateYourEntity ( ) {
const queryClient = useQueryClient ()
return useMutation ({
mutationFn : ({ id, data }: { id: string ; data: YourEntityUpdate } ) =>
api.patch (API .YOUR_ENTITIES .UPDATE (id), data),
onSuccess : () => {
queryClient.invalidateQueries ({ queryKey : queryKeys.yourEntities .all })
},
})
}
export function useDeleteYourEntity ( ) {
const queryClient = useQueryClient ()
return useMutation ({
mutationFn : (id : string ) => api.delete (API .YOUR_ENTITIES .DELETE (id)),
onSuccess : () => {
queryClient.invalidateQueries ({ queryKey : queryKeys.yourEntities .all })
},
})
}
Step 7: Components
List Component (components/your-entities/YourEntitiesList.tsx) import { useQuery } from '@tanstack/react-query'
import { yourEntitiesQueryOptions } from '@/hooks/queries/useYourEntitiesQuery'
export function YourEntitiesList ( ) {
const { data, isLoading, error } = useQuery (yourEntitiesQueryOptions ())
if (isLoading) return <div > Loading...</div >
if (error) return <div > Error: {error.message}</div >
return (
<div >
{data?.map((entity) => (
<div key ={entity.id} > {entity.name}</div >
))}
</div >
)
}
Form Dialog (components/your-entities/dialogs/YourEntityFormDialog.tsx) import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { yourEntitySchema, type YourEntityFormData } from '@/lib/schemas/your-entity'
import { useCreateYourEntity } from '@/hooks/mutations/useYourEntityMutations'
import { toast } from 'sonner'
export function CreateYourEntityDialog ( ) {
const createMutation = useCreateYourEntity ()
const form = useForm<YourEntityFormData >({
resolver : zodResolver (yourEntitySchema),
defaultValues : { name : '' , description : '' },
})
async function onSubmit (data : YourEntityFormData ) {
try {
await createMutation.mutateAsync (data)
toast.success ('Created successfully' )
} catch (error) {
toast.error ('Failed to create' )
}
}
return (
)
}
Step 8: Route (routes/your-entities.tsx) import { createFileRoute } from '@tanstack/react-router'
import { YourEntitiesList } from '@/components/your-entities/YourEntitiesList'
export const Route = createFileRoute ('/your-entities' )({
component : YourEntitiesPage ,
})
function YourEntitiesPage ( ) {
return (
<div className ="container mx-auto py-6" >
<h1 className ="text-2xl font-bold mb-6" > Your Entities</h1 >
<YourEntitiesList />
</div >
)
}
After creating the route file, run bun run dev to auto-generate the route tree.
Step 9: Navigation Add a link in components/common/Navigation.tsx:
<Link to="/your-entities" >Your Entities </Link >
Folder Structure Result src/
├── types/your-entity.ts
├── lib/
│ ├── api-endpoints.ts (updated)
│ ├── query-keys.ts (updated)
│ └── schemas/your-entity.ts
├── hooks/
│ ├── queries/useYourEntitiesQuery.ts
│ └── mutations/useYourEntityMutations.ts
├── components/
│ └── your-entities/
│ ├── YourEntitiesList.tsx
│ └── dialogs/
│ └── YourEntityFormDialog.tsx
└── routes/
└── your-entities.tsx
Checklist