// Horux360 - Database Schema // PostgreSQL with Multi-tenant (schema per tenant) generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } // ============================================ // PUBLIC SCHEMA - Shared across all tenants // ============================================ model Tenant { id String @id @default(uuid()) nombre String rfc String @unique plan Plan @default(starter) schemaName String @unique @map("schema_name") cfdiLimit Int @map("cfdi_limit") usersLimit Int @map("users_limit") active Boolean @default(true) createdAt DateTime @default(now()) @map("created_at") expiresAt DateTime? @map("expires_at") users User[] @@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") } enum Plan { starter business professional enterprise } enum Role { admin contador visor } // ============================================ // TENANT SCHEMA - Isolated per tenant // These models exist in each tenant's schema // ============================================ // Note: The following models are defined for documentation // They will be created dynamically in each tenant schema model Cuenta { id Int @id @default(autoincrement()) codigo String nombre String tipo TipoCuenta padreId Int? @map("padre_id") active Boolean @default(true) padre Cuenta? @relation("CuentaHijos", fields: [padreId], references: [id]) hijos Cuenta[] @relation("CuentaHijos") @@map("cuentas") } enum TipoCuenta { activo pasivo capital ingreso egreso } model Cfdi { id String @id @default(uuid()) uuidFiscal String @unique @map("uuid_fiscal") tipo TipoCfdi serie String? folio String? fechaEmision DateTime @map("fecha_emision") fechaTimbrado DateTime @map("fecha_timbrado") rfcEmisor String @map("rfc_emisor") nombreEmisor String @map("nombre_emisor") rfcReceptor String @map("rfc_receptor") nombreReceptor String @map("nombre_receptor") subtotal Decimal @db.Decimal(18, 2) descuento Decimal @default(0) @db.Decimal(18, 2) iva Decimal @default(0) @db.Decimal(18, 2) isrRetenido Decimal @default(0) @map("isr_retenido") @db.Decimal(18, 2) ivaRetenido Decimal @default(0) @map("iva_retenido") @db.Decimal(18, 2) total Decimal @db.Decimal(18, 2) moneda String @default("MXN") tipoCambio Decimal @default(1) @map("tipo_cambio") @db.Decimal(10, 4) metodoPago String? @map("metodo_pago") formaPago String? @map("forma_pago") usoCfdi String? @map("uso_cfdi") estado EstadoCfdi @default(vigente) xmlUrl String? @map("xml_url") pdfUrl String? @map("pdf_url") createdAt DateTime @default(now()) @map("created_at") conceptos CfdiConcepto[] movimientos MovimientoBancario[] @@map("cfdis") } enum TipoCfdi { ingreso egreso traslado pago nomina } enum EstadoCfdi { vigente cancelado } model CfdiConcepto { id Int @id @default(autoincrement()) cfdiId String @map("cfdi_id") claveProducto String @map("clave_producto") descripcion String cantidad Decimal @db.Decimal(10, 2) unidad String valorUnitario Decimal @map("valor_unitario") @db.Decimal(18, 2) importe Decimal @db.Decimal(18, 2) descuento Decimal @default(0) @db.Decimal(18, 2) objetoImpuesto String? @map("objeto_impuesto") cfdi Cfdi @relation(fields: [cfdiId], references: [id]) @@map("cfdi_conceptos") } model IvaMensual { id Int @id @default(autoincrement()) año Int mes Int ivaTrasladado Decimal @map("iva_trasladado") @db.Decimal(18, 2) ivaAcreditable Decimal @map("iva_acreditable") @db.Decimal(18, 2) ivaRetenido Decimal @default(0) @map("iva_retenido") @db.Decimal(18, 2) resultado Decimal @db.Decimal(18, 2) acumulado Decimal @db.Decimal(18, 2) estado EstadoDeclaracion @default(pendiente) fechaDeclaracion DateTime? @map("fecha_declaracion") @@unique([año, mes]) @@map("iva_mensual") } model IsrMensual { id Int @id @default(autoincrement()) año Int mes Int ingresosAcumulados Decimal @map("ingresos_acumulados") @db.Decimal(18, 2) deducciones Decimal @db.Decimal(18, 2) baseGravable Decimal @map("base_gravable") @db.Decimal(18, 2) isrCausado Decimal @map("isr_causado") @db.Decimal(18, 2) isrRetenido Decimal @map("isr_retenido") @db.Decimal(18, 2) isrAPagar Decimal @map("isr_a_pagar") @db.Decimal(18, 2) estado EstadoDeclaracion @default(pendiente) fechaDeclaracion DateTime? @map("fecha_declaracion") @@unique([año, mes]) @@map("isr_mensual") } enum EstadoDeclaracion { pendiente declarado acreditado } model MovimientoBancario { id Int @id @default(autoincrement()) banco String cuenta String fecha DateTime referencia String? descripcion String tipo TipoMovimiento monto Decimal @db.Decimal(18, 2) saldo Decimal @db.Decimal(18, 2) cfdiId String? @map("cfdi_id") estadoConciliacion EstadoConciliacion @default(pendiente) @map("estado_conciliacion") notas String? cfdi Cfdi? @relation(fields: [cfdiId], references: [id]) @@map("movimientos_bancarios") } enum TipoMovimiento { cargo abono } enum EstadoConciliacion { pendiente conciliado error } model Alerta { id Int @id @default(autoincrement()) tipo TipoAlerta titulo String mensaje String prioridad Prioridad @default(media) fechaVencimiento DateTime? @map("fecha_vencimiento") leida Boolean @default(false) resuelta Boolean @default(false) createdAt DateTime @default(now()) @map("created_at") @@map("alertas") } enum TipoAlerta { vencimiento discrepancia iva_favor declaracion } enum Prioridad { alta media baja } model CalendarioFiscal { id Int @id @default(autoincrement()) titulo String descripcion String? tipo TipoObligacion fechaLimite DateTime @map("fecha_limite") recurrencia Recurrencia @default(unica) completado Boolean @default(false) notas String? @@map("calendario_fiscal") } enum TipoObligacion { declaracion pago obligacion } enum Recurrencia { mensual bimestral anual unica }