generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model KeyValueStore { id String @id @default(uuid()) namespace String key String value Json createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([namespace, key]) @@index([namespace]) } // ─── GIS: eTerra ParcelSync ──────────────────────────────────────── model GisFeature { id String @id @default(uuid()) layerId String // e.g. TERENURI_ACTIVE, CLADIRI_ACTIVE siruta String objectId Int // eTerra OBJECTID (unique per layer); negative for no-geometry parcels (= -immovablePk) inspireId String? cadastralRef String? // NATIONAL_CADASTRAL_REFERENCE areaValue Float? isActive Boolean @default(true) attributes Json // all raw eTerra attributes geometry Json? // GeoJSON geometry (Polygon/MultiPolygon) geometrySource String? // null = normal GIS sync, "NO_GEOMETRY" = eTerra immovable without GIS geometry // NOTE: native PostGIS column 'geom' is managed via SQL trigger (see prisma/postgis-setup.sql) // Prisma doesn't need to know about it — trigger auto-populates from geometry JSON enrichment Json? // magic data: CF, owners, address, categories, etc. enrichedAt DateTime? // when enrichment was last fetched syncRunId String? projectId String? // link to project tag createdAt DateTime @default(now()) updatedAt DateTime @updatedAt syncRun GisSyncRun? @relation(fields: [syncRunId], references: [id], onDelete: SetNull) @@unique([layerId, objectId]) @@index([siruta]) @@index([cadastralRef]) @@index([layerId, siruta]) @@index([projectId]) @@index([geometrySource]) } model GisSyncRun { id String @id @default(uuid()) siruta String uatName String? layerId String status String @default("pending") // pending | running | done | error totalRemote Int @default(0) totalLocal Int @default(0) newFeatures Int @default(0) removedFeatures Int @default(0) startedAt DateTime @default(now()) completedAt DateTime? errorMessage String? features GisFeature[] @@index([siruta]) @@index([layerId]) @@index([siruta, layerId]) } model GisUat { siruta String @id name String county String? workspacePk Int? geometry Json? /// EsriGeometry { rings: number[][][] } in EPSG:3844 areaValue Float? /// Area in sqm from LIMITE_UAT AREA_VALUE field lastUpdatedDtm String? /// LAST_UPDATED_DTM from eTerra — for incremental sync updatedAt DateTime @updatedAt @@index([name]) @@index([county]) } // ─── Registratura: Atomic Sequences + Audit ──────────────────────── model RegistrySequence { id String @id @default(uuid()) company String // B, U, S, G (single-letter prefix) year Int type String // SEQ (shared across directions) lastSeq Int @default(0) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([company, year, type]) @@index([company, year]) } model RegistryAudit { id String @id @default(uuid()) entryId String entryNumber String action String // created, updated, reserved_created, reserved_claimed, late_registration, closed, deleted actor String actorName String? company String detail Json? createdAt DateTime @default(now()) @@index([entryId]) @@index([company, createdAt]) } // ─── ANCPI ePay: CF Extract Orders ────────────────────────────────── model CfExtract { id String @id @default(uuid()) orderId String? // ePay orderId (shared across batch items) basketRowId Int? // ePay cart item ID nrCadastral String // cadastral number nrCF String? // CF number if different siruta String? // UAT SIRUTA code judetIndex Int // ePay county index (0-41) judetName String // county display name uatId Int // ePay UAT numeric ID uatName String // UAT display name prodId Int @default(14200) solicitantId String @default("14452") status String @default("pending") // pending|queued|cart|searching|ordering|polling|downloading|completed|failed|cancelled epayStatus String? // raw ePay status idDocument Int? // ePay document ID documentName String? // ePay filename documentDate DateTime? // when ANCPI generated minioPath String? // MinIO object key minioIndex Int? // file version index creditsUsed Int @default(1) immovableId String? // eTerra immovable ID immovableType String? // T/C/A measuredArea String? legalArea String? address String? gisFeatureId String? // link to GisFeature version Int @default(1) // increments on re-order expiresAt DateTime? // 30 days after documentDate supersededById String? // newer version id requestedBy String? errorMessage String? pollAttempts Int @default(0) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt completedAt DateTime? @@index([nrCadastral]) @@index([status]) @@index([orderId]) @@index([gisFeatureId]) @@index([createdAt]) @@index([nrCadastral, version]) }