Initial commit: DrinkTracker full-stack app
Next.js 14 drink collection tracker with AI-powered search, menu scanning, ratings, wishlist, sharing, and CSV backup/restore. Features: - Auth (credentials + OAuth ready) - Drink collection with ratings and reviews - AI search via Claude/OpenAI with search history - Menu photo scanning with AI extraction - Wishlist / Try Later system - Public sharing via slug URLs - CSV backup and restore (merge/replace modes) - Docker Compose for Postgres + MinIO + dev server Security: docker-compose files use env var interpolation instead of hardcoded secrets. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
73
src/lib/validators.ts
Normal file
73
src/lib/validators.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { z } from "zod"
|
||||
|
||||
export const drinkCreateSchema = z.object({
|
||||
name: z.string().min(1, "Name is required").max(200),
|
||||
type: z.enum(["BEER", "WINE", "COCKTAIL", "SPIRIT", "OTHER"]),
|
||||
subType: z.string().max(100).optional(),
|
||||
brewery: z.string().max(200).optional(),
|
||||
region: z.string().max(200).optional(),
|
||||
abv: z.number().min(0).max(100).optional(),
|
||||
description: z.string().max(2000).optional(),
|
||||
imageUrl: z.string().url().optional(),
|
||||
})
|
||||
|
||||
export const drinkUpdateSchema = drinkCreateSchema.partial()
|
||||
|
||||
export const ratingCreateSchema = z.object({
|
||||
drinkId: z.string().min(1),
|
||||
score: z.number().int().min(1).max(5),
|
||||
notes: z.string().max(2000).optional(),
|
||||
wouldReorder: z.boolean().optional(),
|
||||
location: z.string().max(200).optional(),
|
||||
})
|
||||
|
||||
export const ratingUpdateSchema = ratingCreateSchema.omit({ drinkId: true }).partial()
|
||||
|
||||
export const apiKeySchema = z.object({
|
||||
provider: z.enum(["claude", "openai"]),
|
||||
apiKey: z.string().min(1, "API key is required"),
|
||||
label: z.string().max(100).optional(),
|
||||
})
|
||||
|
||||
export const userPreferenceSchema = z.object({
|
||||
preferredStyles: z.array(z.string().max(50)).max(20).optional(),
|
||||
avoidedStyles: z.array(z.string().max(50)).max(20).optional(),
|
||||
minAbv: z.number().min(0).max(100).optional().nullable(),
|
||||
maxAbv: z.number().min(0).max(100).optional().nullable(),
|
||||
defaultProvider: z.enum(["claude", "openai"]).optional().nullable(),
|
||||
})
|
||||
|
||||
export const wishlistCreateSchema = z.object({
|
||||
name: z.string().min(1, "Name is required").max(200),
|
||||
type: z.enum(["BEER", "WINE", "COCKTAIL", "SPIRIT", "OTHER"]),
|
||||
subType: z.string().max(100).optional(),
|
||||
brewery: z.string().max(200).optional(),
|
||||
abv: z.number().min(0).max(100).optional(),
|
||||
description: z.string().max(2000).optional(),
|
||||
notes: z.string().max(2000).optional(),
|
||||
source: z.string().max(50).optional(),
|
||||
})
|
||||
|
||||
export const sharedListCreateSchema = z.object({
|
||||
title: z.string().min(1, "Title is required").max(200),
|
||||
description: z.string().max(2000).optional(),
|
||||
listType: z.enum(["collection", "wishlist", "custom"]).default("collection"),
|
||||
isPublic: z.boolean().default(true),
|
||||
drinkIds: z.array(z.string()).default([]),
|
||||
})
|
||||
|
||||
export const sharedListUpdateSchema = z.object({
|
||||
title: z.string().min(1).max(200).optional(),
|
||||
description: z.string().max(2000).optional().nullable(),
|
||||
isPublic: z.boolean().optional(),
|
||||
})
|
||||
|
||||
export type DrinkCreate = z.infer<typeof drinkCreateSchema>
|
||||
export type DrinkUpdate = z.infer<typeof drinkUpdateSchema>
|
||||
export type RatingCreate = z.infer<typeof ratingCreateSchema>
|
||||
export type RatingUpdate = z.infer<typeof ratingUpdateSchema>
|
||||
export type ApiKeyInput = z.infer<typeof apiKeySchema>
|
||||
export type UserPreferenceInput = z.infer<typeof userPreferenceSchema>
|
||||
export type WishlistCreate = z.infer<typeof wishlistCreateSchema>
|
||||
export type SharedListCreate = z.infer<typeof sharedListCreateSchema>
|
||||
export type SharedListUpdate = z.infer<typeof sharedListUpdateSchema>
|
||||
Reference in New Issue
Block a user