feat(server): implement ship REST endpoints with Zod validation

Adds GET/POST/PATCH/DELETE /api/ships with constraint validation (current <= max),
enum checks for maneuver_class, and cascade delete for weapons.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Bas van Rossem
2026-02-19 16:17:16 +01:00
parent 4b4d105009
commit 5f179229d6
5 changed files with 236 additions and 4 deletions

View File

@@ -0,0 +1,49 @@
import { z } from 'zod';
const maneuverClasses = ['A', 'B', 'C', 'D', 'E', 'F', 'S'] as const;
export const createShipSchema = z.object({
name: z.string().min(1).max(100).default('Unnamed Ship'),
hull_current: z.number().int().min(0).default(0),
hull_max: z.number().int().min(0).default(0),
armor_current: z.number().int().min(0).default(0),
armor_max: z.number().int().min(0).default(0),
ac: z.number().int().min(0).default(10),
con_save: z.number().int().nullable().default(null),
speed: z.number().int().min(0).nullable().default(null),
maneuver_class: z.enum(maneuverClasses).nullable().default(null),
size_category: z.string().max(50).nullable().default(null),
notes: z.string().nullable().default(null),
});
export const updateShipSchema = z
.object({
name: z.string().min(1).max(100),
hull_current: z.number().int().min(0),
hull_max: z.number().int().min(0),
armor_current: z.number().int().min(0),
armor_max: z.number().int().min(0),
ac: z.number().int().min(0),
con_save: z.number().int().nullable(),
speed: z.number().int().min(0).nullable(),
maneuver_class: z.enum(maneuverClasses).nullable(),
size_category: z.string().max(50).nullable(),
notes: z.string().nullable(),
})
.partial()
.refine(
(data) => {
// Ensure current <= max when both are provided
if (data.hull_current !== undefined && data.hull_max !== undefined) {
return data.hull_current <= data.hull_max;
}
if (data.armor_current !== undefined && data.armor_max !== undefined) {
return data.armor_current <= data.armor_max;
}
return true;
},
{ message: 'Current values must not exceed max values' },
);
export type CreateShipInput = z.infer<typeof createShipSchema>;
export type UpdateShipInput = z.infer<typeof updateShipSchema>;