File size: 1,541 Bytes
98fbc6d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import { z } from 'zod';

/**
 * Category API contract — single source of truth for the /api/categories endpoints.
 *
 * Categories are the place-category palette (also the admin "Personalization"
 * surface). Reading is open to any authenticated user; create/update/delete are
 * admin-only. The legacy route (server/src/routes/categories.ts) wraps
 * services/categoryService.ts 1:1.
 *
 * The bespoke 400 ("Category name is required") and 404 ("Category not found")
 * messages are reproduced in the controller so the bodies stay byte-identical.
 */

export const categorySchema = z.object({
  id: z.number(),
  name: z.string(),
  color: z.string(),
  icon: z.string(),
  user_id: z.number().nullable().optional(),
  created_at: z.string().optional(),
});
export type Category = z.infer<typeof categorySchema>;

export const createCategoryRequestSchema = z.object({
  name: z.string().min(1),
  color: z.string().optional(),
  icon: z.string().optional(),
});
export type CreateCategoryRequest = z.infer<typeof createCategoryRequestSchema>;

/** All fields optional — the service COALESCEs each against the stored value. */
export const updateCategoryRequestSchema = z.object({
  name: z.string().optional(),
  color: z.string().optional(),
  icon: z.string().optional(),
});
export type UpdateCategoryRequest = z.infer<typeof updateCategoryRequestSchema>;

export const categoryListResponseSchema = z.object({
  categories: z.array(categorySchema),
});
export type CategoryListResponse = z.infer<typeof categoryListResponseSchema>;