generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model Tenant { id String @id @default(uuid()) nombre String rfc String @unique plan Plan @default(starter) databaseName String @unique @map("database_name") cfdiLimit Int @default(100) @map("cfdi_limit") usersLimit Int @default(1) @map("users_limit") active Boolean @default(true) createdAt DateTime @default(now()) @map("created_at") expiresAt DateTime? @map("expires_at") users User[] fielCredential FielCredential? satSyncJobs SatSyncJob[] subscriptions Subscription[] payments Payment[] @@map("tenants") } model User { id String @id @default(uuid()) tenantId String @map("tenant_id") email String @unique passwordHash String @map("password_hash") nombre String role Role @default(visor) active Boolean @default(true) lastLogin DateTime? @map("last_login") createdAt DateTime @default(now()) @map("created_at") tenant Tenant @relation(fields: [tenantId], references: [id]) @@map("users") } model RefreshToken { id String @id @default(uuid()) userId String @map("user_id") token String @unique expiresAt DateTime @map("expires_at") createdAt DateTime @default(now()) @map("created_at") @@map("refresh_tokens") } enum Plan { starter business professional enterprise } enum Role { admin contador visor } // ============================================ // SAT Sync Models // ============================================ model FielCredential { id String @id @default(uuid()) tenantId String @unique @map("tenant_id") rfc String @db.VarChar(13) cerData Bytes @map("cer_data") keyData Bytes @map("key_data") keyPasswordEncrypted Bytes @map("key_password_encrypted") cerIv Bytes @map("cer_iv") cerTag Bytes @map("cer_tag") keyIv Bytes @map("key_iv") keyTag Bytes @map("key_tag") passwordIv Bytes @map("password_iv") passwordTag Bytes @map("password_tag") serialNumber String? @map("serial_number") @db.VarChar(50) validFrom DateTime @map("valid_from") validUntil DateTime @map("valid_until") isActive Boolean @default(true) @map("is_active") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade) @@map("fiel_credentials") } model Subscription { id String @id @default(uuid()) tenantId String @map("tenant_id") plan Plan mpPreapprovalId String? @map("mp_preapproval_id") status String @default("pending") amount Decimal @db.Decimal(10, 2) frequency String @default("monthly") currentPeriodStart DateTime? @map("current_period_start") currentPeriodEnd DateTime? @map("current_period_end") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") tenant Tenant @relation(fields: [tenantId], references: [id]) payments Payment[] @@index([tenantId]) @@index([status]) @@map("subscriptions") } model Payment { id String @id @default(uuid()) tenantId String @map("tenant_id") subscriptionId String? @map("subscription_id") mpPaymentId String? @map("mp_payment_id") amount Decimal @db.Decimal(10, 2) status String @default("pending") paymentMethod String? @map("payment_method") paidAt DateTime? @map("paid_at") createdAt DateTime @default(now()) @map("created_at") tenant Tenant @relation(fields: [tenantId], references: [id]) subscription Subscription? @relation(fields: [subscriptionId], references: [id]) @@index([tenantId]) @@index([subscriptionId]) @@map("payments") } model SatSyncJob { id String @id @default(uuid()) tenantId String @map("tenant_id") type SatSyncType status SatSyncStatus @default(pending) dateFrom DateTime @map("date_from") @db.Date dateTo DateTime @map("date_to") @db.Date cfdiType CfdiSyncType? @map("cfdi_type") satRequestId String? @map("sat_request_id") @db.VarChar(50) satPackageIds String[] @map("sat_package_ids") cfdisFound Int @default(0) @map("cfdis_found") cfdisDownloaded Int @default(0) @map("cfdis_downloaded") cfdisInserted Int @default(0) @map("cfdis_inserted") cfdisUpdated Int @default(0) @map("cfdis_updated") progressPercent Int @default(0) @map("progress_percent") errorMessage String? @map("error_message") startedAt DateTime? @map("started_at") completedAt DateTime? @map("completed_at") createdAt DateTime @default(now()) @map("created_at") retryCount Int @default(0) @map("retry_count") nextRetryAt DateTime? @map("next_retry_at") tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade) @@index([tenantId]) @@index([status]) @@index([status, nextRetryAt]) @@map("sat_sync_jobs") } enum SatSyncType { initial daily } enum SatSyncStatus { pending running completed failed } enum CfdiSyncType { emitidos recibidos }