// The tables of the documents module (spec §16). Two, both project-owned. // // `documents_document` is one uploaded file's processing state. `documents_line` holds only what a // person has APPROVED: an extracted line lives as a proposal (kit-proposals) until somebody // decides it, and the proposal's writer inserts the line in the approving transaction. That is how // "nothing is exported without approval" is a property of the schema and not of a filter: the // export reads this table, and nothing but an approval writes to it. import { defineEntity, idSchema, instantSchema } from "@conusai-kit/data" import { z } from "zod" import { DOCUMENT_STATUSES, FAILURE_CODES, PAGE_CLASSES } from "./constants.js" export const documents = defineEntity({ name: "document", table: "documents_document", tenancy: "project", fields: { /** The row of the files module this document was made from: an opaque id, never a foreign key (spec §4.4). */ fileId: idSchema, filename: z.string().min(1).max(255), status: z.enum(DOCUMENT_STATUSES), /** The platform's OCR job id, recorded as soon as the job is accepted so a retry resumes it. */ ocrJobId: z.number().int().nonnegative().nullable(), pageCount: z.number().int().nonnegative().nullable(), /** How many lines the extraction proposed; the proposals themselves are the reviewer's queue. */ proposedCount: z.number().int().nonnegative().nullable(), failureCode: z.enum(FAILURE_CODES).nullable(), /** The pages the extraction left out, with the class that excluded each, so a reviewer sees what was not read. Null until extracted. */ skippedPages: z .array(z.object({ page: z.number().int().min(1), pageClass: z.enum(PAGE_CLASSES) }).strict()) .nullable(), finishedAt: instantSchema.nullable(), }, // One document per file: the job that creates it is retried, and a second row would be a second queue. unique: [["fileId"]], indexes: [["status"]], }) export const lines = defineEntity({ name: "line", table: "documents_line", tenancy: "project", fields: { documentId: idSchema, /** The approved proposal this line came from: its provenance, and the reason a line is written once. */ proposalId: idSchema, label: z.string().min(1).max(200), value: z.string().min(1).max(2_000), /** 1-based page of the source document. */ page: z.number().int().min(1), /** Reading order within the document: the export's order, which a creation time cannot give. */ position: z.number().int().min(0), /** The words the value was read from, verbatim. */ quote: z.string().min(1).max(2_000), /** True when a reviewer changed the label or value before it was approved. */ edited: z.boolean(), approvedBy: z.string().min(1).max(128), }, unique: [["proposalId"]], indexes: [["documentId"]], }) /** Every table this module owns, in the order a migration creates them. */ export const DOCUMENTS_ENTITIES = Object.freeze([documents, lines])