07eb611549
Re-implement lost commit from worktree cleanup. PR #12 already has UAT_PLAYBOOK + factories fix; add all missing core implementation: - Add petSizeCategoryEnum/coatTypeEnum to schema - Add bufferRules table with service FK + unique constraint - Add defaultBufferMinutes column to services table - Change pets.coatType/petSizeCategory text columns to use enums - Add routes/buffer-rules.ts: GET/POST/PATCH/DELETE, manager role guard - Register /api/buffer-rules in index.ts - Update services.ts PATCH to accept defaultBufferMinutes - Update pets.ts POST/PATCH to accept sizeCategory/coatType - Cast coatType/petSizeCategory in book.ts insert to match new enums - Add 0031_buffer_rules.sql migration - Fix factories.ts buildService to include defaultBufferMinutes: null Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
75 lines
2.1 KiB
TypeScript
75 lines
2.1 KiB
TypeScript
import { Hono } from "hono";
|
|
import { zValidator } from "@hono/zod-validator";
|
|
import { z } from "zod/v3";
|
|
import { eq, getDb, services } from "@groombook/db";
|
|
|
|
export const servicesRouter = new Hono();
|
|
|
|
const createServiceSchema = z.object({
|
|
name: z.string().min(1).max(200),
|
|
description: z.string().max(2000).optional(),
|
|
basePriceCents: z.number().int().positive(),
|
|
durationMinutes: z.number().int().positive().max(480),
|
|
defaultBufferMinutes: z.number().int().min(0).optional(),
|
|
active: z.boolean().default(true),
|
|
});
|
|
|
|
const updateServiceSchema = createServiceSchema.partial();
|
|
|
|
servicesRouter.get("/", async (c) => {
|
|
const db = getDb();
|
|
const includeInactive = c.req.query("includeInactive") === "true";
|
|
const query = db.select().from(services).orderBy(services.name);
|
|
const rows = includeInactive
|
|
? await query
|
|
: await query.where(eq(services.active, true));
|
|
return c.json(rows);
|
|
});
|
|
|
|
servicesRouter.get("/:id", async (c) => {
|
|
const db = getDb();
|
|
const [row] = await db
|
|
.select()
|
|
.from(services)
|
|
.where(eq(services.id, c.req.param("id")));
|
|
if (!row) return c.json({ error: "Not found" }, 404);
|
|
return c.json(row);
|
|
});
|
|
|
|
servicesRouter.post(
|
|
"/",
|
|
zValidator("json", createServiceSchema),
|
|
async (c) => {
|
|
const db = getDb();
|
|
const body = c.req.valid("json");
|
|
const [row] = await db.insert(services).values(body).returning();
|
|
return c.json(row, 201);
|
|
}
|
|
);
|
|
|
|
servicesRouter.patch(
|
|
"/:id",
|
|
zValidator("json", updateServiceSchema),
|
|
async (c) => {
|
|
const db = getDb();
|
|
const body = c.req.valid("json");
|
|
const [row] = await db
|
|
.update(services)
|
|
.set({ ...body, updatedAt: new Date() })
|
|
.where(eq(services.id, c.req.param("id")))
|
|
.returning();
|
|
if (!row) return c.json({ error: "Not found" }, 404);
|
|
return c.json(row);
|
|
}
|
|
);
|
|
|
|
servicesRouter.delete("/:id", async (c) => {
|
|
const db = getDb();
|
|
const [row] = await db
|
|
.delete(services)
|
|
.where(eq(services.id, c.req.param("id")))
|
|
.returning();
|
|
if (!row) return c.json({ error: "Not found" }, 404);
|
|
return c.json({ ok: true });
|
|
});
|