- Complete design document with architecture, data models, and API specs - Database schema (Prisma) for multi-tenant PostgreSQL - README with project overview and plans - Support for 4 visual themes (Light, Vibrant, Corporate, Dark) - Comprehensive module specifications: - Dashboard with KPIs - CFDI management - IVA/ISR tax control - Bank reconciliation - Fiscal calendar - User management with roles Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
278 lines
7.5 KiB
Plaintext
278 lines
7.5 KiB
Plaintext
// 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
|
|
}
|