feat: restore scan quality, implement standardized naming, and add cask_type integration

This commit is contained in:
2026-01-05 23:33:10 +01:00
parent 21ca704abc
commit 68ac857091
22 changed files with 576 additions and 1020 deletions

View File

@@ -1,18 +1,29 @@
import { z } from 'zod';
const coerceNumber = z.preprocess((val) => {
if (val === null || val === undefined || val === '') return null;
const n = Number(val);
if (isNaN(n)) return null;
// If it looks like a year (e.g. 19xx or 20xx), it's probably not the age
if (n > 1900 && n < 2100) return null;
return n;
}, z.number().min(0).max(200).nullish());
export const BottleMetadataSchema = z.object({
name: z.string().trim().min(1).max(255).nullish(),
distillery: z.string().trim().max(255).nullish(),
bottler: z.string().trim().max(255).nullish(),
series: z.string().trim().max(255).nullish(),
category: z.string().trim().max(100).nullish(),
abv: z.number().min(0).max(100).nullish(),
age: z.number().min(0).max(100).nullish(),
abv: coerceNumber,
age: coerceNumber,
vintage: z.string().trim().max(50).nullish(),
bottleCode: z.string().trim().max(100).nullish(),
whiskybaseId: z.string().trim().max(50).nullish(),
distilled_at: z.string().trim().max(50).nullish(),
bottled_at: z.string().trim().max(50).nullish(),
batch_info: z.string().trim().max(255).nullish(),
cask_type: z.string().trim().max(255).nullish(),
is_whisky: z.boolean().default(true),
confidence: z.number().min(0).max(100).default(100),
purchase_price: z.number().min(0).nullish(),
@@ -42,13 +53,14 @@ export const UpdateBottleSchema = z.object({
name: z.string().trim().min(1).max(255).nullish(),
distillery: z.string().trim().max(255).nullish(),
category: z.string().trim().max(100).nullish(),
abv: z.number().min(0).max(100).nullish(),
age: z.number().min(0).max(100).nullish(),
abv: coerceNumber,
age: coerceNumber,
whiskybase_id: z.string().trim().max(50).nullish(),
purchase_price: z.number().min(0).nullish(),
distilled_at: z.string().trim().max(50).nullish(),
bottled_at: z.string().trim().max(50).nullish(),
batch_info: z.string().trim().max(255).nullish(),
cask_type: z.string().trim().max(255).nullish(),
status: z.enum(['sealed', 'open', 'sampled', 'empty']).nullish(),
});
@@ -81,11 +93,12 @@ export type AdminSettingsData = z.infer<typeof AdminSettingsSchema>;
export const DiscoveryDataSchema = z.object({
name: z.string().trim().min(1).max(255),
distillery: z.string().trim().max(255).nullish(),
abv: z.number().min(0).max(100).nullish(),
age: z.number().min(0).max(100).nullish(),
abv: coerceNumber,
age: coerceNumber,
distilled_at: z.string().trim().max(50).nullish(),
bottled_at: z.string().trim().max(50).nullish(),
batch_info: z.string().trim().max(255).nullish(),
cask_type: z.string().trim().max(255).nullish(),
});
export type DiscoveryData = z.infer<typeof DiscoveryDataSchema>;