feat: Initial commit - Mexus App

Sistema de Gestión de Obras de Construcción completo con:
- Dashboard con KPIs y gráficos
- Módulo de obras con fases y tareas
- Control financiero (gastos, presupuestos)
- Gestión de recursos (personal, subcontratistas)
- Inventario de materiales con alertas de stock
- Reportes con exportación CSV
- Autenticación con roles (NextAuth.js v5)
- API REST completa
- Documentación de API y base de datos
- Configuración Docker para despliegue

Stack: Next.js 14+, TypeScript, Tailwind CSS, Prisma, PostgreSQL

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Mexus
2026-01-19 01:10:55 +00:00
commit 86bfbd2039
82 changed files with 18845 additions and 0 deletions

315
prisma/seed.ts Normal file
View File

@@ -0,0 +1,315 @@
import { PrismaClient, Role, EstadoObra, CategoriaGasto } from "@prisma/client";
import bcrypt from "bcryptjs";
const prisma = new PrismaClient();
async function main() {
console.log("Seeding database...");
// Create empresa
const empresa = await prisma.empresa.create({
data: {
nombre: "Constructora Demo S.A. de C.V.",
rfc: "CDM123456ABC",
direccion: "Av. Principal #123, Ciudad de Mexico",
telefono: "55 1234 5678",
email: "contacto@constructorademo.com",
},
});
console.log("Created empresa:", empresa.nombre);
// Create admin user
const hashedPassword = await bcrypt.hash("admin123", 12);
const adminUser = await prisma.user.create({
data: {
email: "admin@demo.com",
password: hashedPassword,
nombre: "Admin",
apellido: "Demo",
role: Role.ADMIN,
empresaId: empresa.id,
},
});
console.log("Created admin user:", adminUser.email);
// Create supervisor user
const supervisorUser = await prisma.user.create({
data: {
email: "supervisor@demo.com",
password: hashedPassword,
nombre: "Juan",
apellido: "Supervisor",
role: Role.SUPERVISOR,
empresaId: empresa.id,
},
});
// Create cliente
const cliente = await prisma.cliente.create({
data: {
nombre: "Cliente Residencial SA",
rfc: "CRS987654XYZ",
direccion: "Calle Ejemplo #456",
telefono: "55 9876 5432",
email: "cliente@ejemplo.com",
empresaId: empresa.id,
},
});
console.log("Created cliente:", cliente.nombre);
// Create obra
const obra = await prisma.obra.create({
data: {
nombre: "Torre Residencial Norte",
descripcion: "Proyecto de torre residencial de 20 pisos con amenidades",
direccion: "Av. Reforma #500, CDMX",
estado: EstadoObra.EN_PROGRESO,
fechaInicio: new Date("2024-01-15"),
fechaFinPrevista: new Date("2025-06-30"),
porcentajeAvance: 35,
presupuestoTotal: 15000000,
gastoTotal: 5250000,
empresaId: empresa.id,
clienteId: cliente.id,
supervisorId: supervisorUser.id,
},
});
console.log("Created obra:", obra.nombre);
// Create fases
const fases = await Promise.all([
prisma.faseObra.create({
data: {
nombre: "Cimentacion",
descripcion: "Excavacion y cimentacion profunda",
orden: 1,
porcentajeAvance: 100,
obraId: obra.id,
},
}),
prisma.faseObra.create({
data: {
nombre: "Estructura",
descripcion: "Construccion de estructura de concreto",
orden: 2,
porcentajeAvance: 60,
obraId: obra.id,
},
}),
prisma.faseObra.create({
data: {
nombre: "Instalaciones",
descripcion: "Instalaciones electricas, hidraulicas y sanitarias",
orden: 3,
porcentajeAvance: 10,
obraId: obra.id,
},
}),
]);
console.log("Created", fases.length, "fases");
// Create presupuesto
const presupuesto = await prisma.presupuesto.create({
data: {
nombre: "Presupuesto Principal 2024",
descripcion: "Presupuesto inicial aprobado",
total: 15000000,
aprobado: true,
obraId: obra.id,
},
});
// Create partidas
await Promise.all([
prisma.partidaPresupuesto.create({
data: {
codigo: "CIM-001",
descripcion: "Excavacion y cimentacion",
unidad: "METRO_CUBICO",
cantidad: 500,
precioUnitario: 2500,
total: 1250000,
categoria: CategoriaGasto.MANO_DE_OBRA,
presupuestoId: presupuesto.id,
},
}),
prisma.partidaPresupuesto.create({
data: {
codigo: "EST-001",
descripcion: "Concreto estructural",
unidad: "METRO_CUBICO",
cantidad: 2000,
precioUnitario: 3500,
total: 7000000,
categoria: CategoriaGasto.MATERIALES,
presupuestoId: presupuesto.id,
},
}),
]);
// Create gastos
const gastos = await Promise.all([
prisma.gasto.create({
data: {
concepto: "Compra de cemento",
descripcion: "500 toneladas de cemento Portland",
monto: 1500000,
fecha: new Date("2024-02-01"),
categoria: CategoriaGasto.MATERIALES,
estado: "APROBADO",
obraId: obra.id,
creadoPorId: adminUser.id,
aprobadoPorId: adminUser.id,
fechaAprobacion: new Date("2024-02-02"),
},
}),
prisma.gasto.create({
data: {
concepto: "Renta de maquinaria",
descripcion: "Excavadora y retroexcavadora",
monto: 750000,
fecha: new Date("2024-02-15"),
categoria: CategoriaGasto.EQUIPOS,
estado: "APROBADO",
obraId: obra.id,
creadoPorId: supervisorUser.id,
aprobadoPorId: adminUser.id,
fechaAprobacion: new Date("2024-02-16"),
},
}),
prisma.gasto.create({
data: {
concepto: "Nomina trabajadores",
descripcion: "Pago quincenal",
monto: 500000,
fecha: new Date("2024-03-01"),
categoria: CategoriaGasto.MANO_DE_OBRA,
estado: "PAGADO",
obraId: obra.id,
creadoPorId: adminUser.id,
aprobadoPorId: adminUser.id,
fechaAprobacion: new Date("2024-03-01"),
},
}),
prisma.gasto.create({
data: {
concepto: "Compra de acero",
descripcion: "Varilla corrugada",
monto: 2000000,
fecha: new Date("2024-03-15"),
categoria: CategoriaGasto.MATERIALES,
estado: "PENDIENTE",
obraId: obra.id,
creadoPorId: supervisorUser.id,
},
}),
]);
console.log("Created", gastos.length, "gastos");
// Create materiales
const materiales = await Promise.all([
prisma.material.create({
data: {
codigo: "CEM-001",
nombre: "Cemento Portland",
descripcion: "Cemento gris tipo I",
unidad: "BOLSA",
precioUnitario: 180,
stockMinimo: 100,
stockActual: 250,
ubicacion: "Bodega A",
empresaId: empresa.id,
},
}),
prisma.material.create({
data: {
codigo: "VAR-001",
nombre: "Varilla corrugada 3/8",
descripcion: "Varilla de acero corrugado",
unidad: "PIEZA",
precioUnitario: 120,
stockMinimo: 500,
stockActual: 1200,
ubicacion: "Bodega B",
empresaId: empresa.id,
},
}),
prisma.material.create({
data: {
codigo: "GRA-001",
nombre: "Grava 3/4",
descripcion: "Grava triturada",
unidad: "METRO_CUBICO",
precioUnitario: 450,
stockMinimo: 50,
stockActual: 30,
ubicacion: "Patio",
empresaId: empresa.id,
},
}),
]);
console.log("Created", materiales.length, "materiales");
// Create empleados
const empleados = await Promise.all([
prisma.empleado.create({
data: {
nombre: "Pedro",
apellido: "Martinez",
documento: "PEMA850101ABC",
telefono: "55 1111 2222",
puesto: "Maestro de Obra",
salarioBase: 25000,
fechaIngreso: new Date("2023-01-15"),
empresaId: empresa.id,
},
}),
prisma.empleado.create({
data: {
nombre: "Maria",
apellido: "Garcia",
documento: "MAGA900520XYZ",
telefono: "55 3333 4444",
puesto: "Ingeniero Residente",
salarioBase: 35000,
fechaIngreso: new Date("2023-03-01"),
empresaId: empresa.id,
},
}),
]);
console.log("Created", empleados.length, "empleados");
// Create subcontratistas
await prisma.subcontratista.create({
data: {
nombre: "Instalaciones Electromecanicas SA",
rfc: "IEL123456ABC",
especialidad: "Instalaciones Electricas",
telefono: "55 5555 6666",
email: "contacto@ielsa.com",
empresaId: empresa.id,
},
});
console.log("Seed completed successfully!");
console.log("\nCredenciales de acceso:");
console.log("Email: admin@demo.com");
console.log("Password: admin123");
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});