diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..3d82207 --- /dev/null +++ b/.claude/settings.json @@ -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 + } +} diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..62e2c93 --- /dev/null +++ b/.claude/settings.local.json @@ -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:*)" + ] + } +} diff --git a/src/routes/admin/categories.ts b/src/routes/admin/categories.ts index 5d52c41..5a51c00 100644 --- a/src/routes/admin/categories.ts +++ b/src/routes/admin/categories.ts @@ -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 { - 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) => { diff --git a/src/services/admin/category-service.ts b/src/services/admin/category-service.ts index e730f6f..c8cc4db 100644 --- a/src/services/admin/category-service.ts +++ b/src/services/admin/category-service.ts @@ -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`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 }) {