feat: add pagination support to admin categories endpoint

- Add page/limit query parameters with Zod validation (max 50)
- Update listCategories service to return paginated results
- Response format includes pagination metadata (total, page, limit)
- Matches existing pattern from questions/feedback endpoints

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Wang Zhuoxuan 2026-04-11 12:56:40 +08:00
parent 2dd5f18822
commit 6e65993f89
4 changed files with 74 additions and 5 deletions

7
.claude/settings.json Normal file
View File

@ -0,0 +1,7 @@
{
"enabledPlugins": {
"typescript-lsp@claude-plugins-official": true,
"claude-md-management@claude-plugins-official": true,
"glm-plan-usage@zai-coding-plugins": false
}
}

View File

@ -0,0 +1,15 @@
{
"permissions": {
"allow": [
"mcp__plugin_ecc_context7__resolve-library-id",
"mcp__plugin_ecc_context7__query-docs",
"Bash(bun install:*)",
"Bash(bun add:*)",
"Bash(bunx tsc:*)",
"Bash(git status:*)",
"Bash(git add:*)",
"Bash(git commit:*)",
"Bash(bun run:*)"
]
}
}

View File

@ -18,10 +18,32 @@ const updateCategorySchema = z.object({
status: z.enum(['active', 'inactive']).optional(),
});
const listCategoriesQuerySchema = z.object({
page: z.coerce.number().int().positive().optional().default(1),
limit: z.coerce.number().int().positive().max(50).optional().default(20),
});
export async function adminCategoriesRoutes(app: FastifyInstance): Promise<void> {
app.get('/', async () => {
const data = await categoryService.listCategories();
return { success: true, data, error: null };
app.get('/', async (request) => {
const parsed = listCategoriesQuerySchema.safeParse(request.query);
if (!parsed.success) {
return {
success: false,
data: null,
error: {
code: 'VALIDATION_ERROR',
message: parsed.error.issues[0]?.message ?? 'Invalid query parameters'
}
};
}
const result = await categoryService.listCategories(parsed.data);
return {
success: true,
data: result.items,
pagination: result.pagination,
error: null
};
});
app.post('/', async (request) => {

View File

@ -2,8 +2,33 @@ import { db } from '../../db/client.js';
import { categories, questions } from '../../db/schema.js';
import { eq, and, sql } from 'drizzle-orm';
export async function listCategories() {
return db.select().from(categories).orderBy(categories.sortOrder);
interface ListOptions {
page?: number;
limit?: number;
}
export async function listCategories({ page = 1, limit = 20 }: ListOptions = {}) {
const offset = (page - 1) * limit;
// Get total count
const [countResult] = await db
.select({ total: sql<number>`COUNT(*)` })
.from(categories);
const total = Number(countResult?.total ?? 0);
// Get paginated items
const items = await db
.select()
.from(categories)
.orderBy(categories.sortOrder)
.limit(limit)
.offset(offset);
return {
items,
pagination: { total, page, limit }
};
}
export async function createCategory(data: { id: string; name: string; slug: string; parentId?: string; sortOrder?: number }) {