generated from john/python-template
5.2 KiB
5.2 KiB
TypeScript Zod schemas
Here are the TypeScript Zod schemas matching your V2 PostgreSQL database definition.
These schemas cover:
- Database Entities: Pure runtime validators representing rows fetched directly from PostgreSQL.
- AI Payload Extensions: The structured document output stored inside job.ai_metadata.
- Insert/Create Schemas: Utility types derived with .omit() for creating new records where auto-generated columns (id, created_at, updated_at, etc.) are handled by PostgreSQL defaults.
import { z } from "zod";
// ==========================================
// 1. ATOMIC & REUSABLE SCHEMAS
// ==========================================
export const UUIDSchema = z.string().uuid();
export const ISODateTimeSchema = z.coerce.date();
export const BoundingBoxSchema = z.object({
ymin: z.number().min(0).max(1000),
xmin: z.number().min(0).max(1000),
ymax: z.number().min(0).max(1000),
xmax: z.number().min(0).max(1000),
});
export const BlockTypeSchema = z.enum([
"heading",
"paragraph",
"table",
"margin_note",
"signature",
"footnote",
"header",
]);
// ==========================================
// 2. PAGE-LEVEL AI METADATA SCHEMA (job_source.ai_metadata)
// ==========================================
export const TranscribedBlockSchema = z.object({
text: z.string(),
confidence: z.number().min(0).max(1),
blockType: BlockTypeSchema,
boundingBox: BoundingBoxSchema.optional(),
});
export const PageAIMetadataSchema = z.object({
detectedLanguage: z.string().optional(),
overallConfidence: z.number().min(0).max(1),
blocks: z.array(TranscribedBlockSchema),
inputTokens: z.number().optional(),
outputTokens: z.number().optional(),
extractedEntities: z.record(z.string(), z.unknown()).optional(),
});
export type PageAIMetadata = z.infer<typeof PageAIMetadataSchema>;
// ==========================================
// 3. TABLE ENTITY SCHEMAS
// ==========================================
// --- PERSON TABLE ---
export const PersonSchema = z.object({
id: UUIDSchema,
fullName: z.string().min(1),
displayName: z.string().nullable().optional(),
maidenName: z.string().nullable().optional(),
birthDate: z.string().nullable().optional(),
birthDateRaw: z.string().nullable().optional(),
birthPlace: z.string().nullable().optional(),
deathDate: z.string().nullable().optional(),
deathDateRaw: z.string().nullable().optional(),
deathPlace: z.string().nullable().optional(),
biography: z.string().nullable().optional(),
portraitPath: z.string().nullable().optional(),
metadata: z.record(z.string(), z.unknown()).default({}),
createdAt: ISODateTimeSchema,
updatedAt: ISODateTimeSchema,
});
// --- DOCUMENT TABLE ---
export const DocumentSchema = z.object({
id: UUIDSchema,
name: z.string().min(1),
documentType: z.string().nullable().optional(),
documentDate: z.string().nullable().optional(),
documentDateRaw: z.string().nullable().optional(),
locationCreated: z.string().nullable().optional(),
notes: z.string().nullable().optional(),
archiveIdentifier: z.string().nullable().optional(),
createdAt: ISODateTimeSchema,
updatedAt: ISODateTimeSchema,
});
// --- DOCUMENT_PERSON JUNCTION ---
export const PersonRoleSchema = z.enum(["author", "recipient"]);
export const DocumentPersonSchema = z.object({
id: UUIDSchema,
documentId: UUIDSchema,
personId: UUIDSchema,
role: PersonRoleSchema,
createdAt: ISODateTimeSchema,
});
// --- JOB TABLE ---
export const JobStatusSchema = z.enum([
"queued",
"processing",
"completed",
"partial_success",
"failed",
]);
export const JobSchema = z.object({
id: UUIDSchema,
documentId: UUIDSchema,
status: JobStatusSchema.default("queued"),
retryCount: z.number().int().nonnegative().default(0),
provider: z.string(),
model: z.string(),
promptName: z.string().nullable().optional(),
dateCreated: ISODateTimeSchema,
dateUpdated: ISODateTimeSchema,
});
// --- SOURCE TABLE ---
export const SourceSchema = z.object({
id: UUIDSchema,
documentId: UUIDSchema,
pageNumber: z.number().int().positive().default(1),
uploadName: z.string(),
filename: z.string(),
filePath: z.string(),
rawTranscription: z.string().nullable().optional(),
revisedText: z.string().nullable().optional(),
dateUploaded: ISODateTimeSchema,
dateRevised: ISODateTimeSchema.nullable().optional(),
});
// --- JOB_SOURCE JUNCTION (Page Execution Output) ---
export const JobSourceStatusSchema = z.enum([
"pending",
"transcribed",
"failed",
]);
export const JobSourceSchema = z.object({
id: UUIDSchema,
jobId: UUIDSchema,
sourceId: UUIDSchema,
status: JobSourceStatusSchema.default("pending"),
rawTranscription: z.string().nullable().optional(),
aiMetadata: PageAIMetadataSchema.nullable().optional(),
rawApiResponse: z.record(z.string(), z.unknown()).nullable().optional(),
errorDetail: z.string().nullable().optional(),
executedAt: ISODateTimeSchema,
});
export type Person = z.infer<typeof PersonSchema>;
export type Document = z.infer<typeof DocumentSchema>;
export type DocumentPerson = z.infer<typeof DocumentPersonSchema>;
export type Job = z.infer<typeof JobSchema>;
export type Source = z.infer<typeof SourceSchema>;
export type JobSource = z.infer<typeof JobSourceSchema>;