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:
527
docs/API.md
Normal file
527
docs/API.md
Normal file
@@ -0,0 +1,527 @@
|
||||
# Documentación de API - Mexus App
|
||||
|
||||
Esta documentación describe todos los endpoints disponibles en la API REST de Mexus App.
|
||||
|
||||
## Base URL
|
||||
|
||||
```
|
||||
Desarrollo: http://localhost:3000/api
|
||||
Producción: https://tu-dominio.com/api
|
||||
```
|
||||
|
||||
## Autenticación
|
||||
|
||||
La API utiliza NextAuth.js para la autenticación. Las peticiones autenticadas requieren una cookie de sesión válida.
|
||||
|
||||
### Headers requeridos
|
||||
|
||||
```
|
||||
Content-Type: application/json
|
||||
Cookie: authjs.session-token=<token>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Endpoints de Autenticación
|
||||
|
||||
### Obtener token CSRF
|
||||
|
||||
```http
|
||||
GET /api/auth/csrf
|
||||
```
|
||||
|
||||
**Respuesta exitosa (200):**
|
||||
```json
|
||||
{
|
||||
"csrfToken": "0ee47c595b90ef7b0356521f5354695cfe22a5797fa30cecba0a279ce28a9719"
|
||||
}
|
||||
```
|
||||
|
||||
### Iniciar sesión
|
||||
|
||||
```http
|
||||
POST /api/auth/callback/credentials
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
```
|
||||
|
||||
**Parámetros:**
|
||||
| Campo | Tipo | Requerido | Descripción |
|
||||
|-------|------|-----------|-------------|
|
||||
| csrfToken | string | Sí | Token CSRF obtenido previamente |
|
||||
| email | string | Sí | Correo electrónico del usuario |
|
||||
| password | string | Sí | Contraseña del usuario |
|
||||
|
||||
**Respuesta exitosa (302):** Redirección a dashboard con cookie de sesión
|
||||
|
||||
### Obtener sesión actual
|
||||
|
||||
```http
|
||||
GET /api/auth/session
|
||||
```
|
||||
|
||||
**Respuesta exitosa (200):**
|
||||
```json
|
||||
{
|
||||
"user": {
|
||||
"id": "cmkk6tf3y00025x5stdh7x2f9",
|
||||
"email": "admin@demo.com",
|
||||
"nombre": "Admin",
|
||||
"apellido": "Demo",
|
||||
"role": "ADMIN",
|
||||
"empresaId": "cmkk6ter000005x5smacuuh5x"
|
||||
},
|
||||
"expires": "2026-01-20T00:25:19.994Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Cerrar sesión
|
||||
|
||||
```http
|
||||
POST /api/auth/signout
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Endpoints de Obras
|
||||
|
||||
### Listar obras
|
||||
|
||||
```http
|
||||
GET /api/obras
|
||||
```
|
||||
|
||||
**Respuesta exitosa (200):**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "cmkk6tf4900085x5semza5bzu",
|
||||
"codigo": "OBR-2024-001",
|
||||
"nombre": "Edificio Residencial Aurora",
|
||||
"descripcion": "Construcción de edificio de 8 niveles",
|
||||
"cliente": "Inmobiliaria del Norte S.A.",
|
||||
"ubicacion": "Col. Centro, Ciudad",
|
||||
"estado": "EN_PROGRESO",
|
||||
"presupuestoTotal": 15000000,
|
||||
"fechaInicio": "2024-01-15T00:00:00.000Z",
|
||||
"fechaFinEstimada": "2025-06-30T00:00:00.000Z",
|
||||
"avanceGeneral": 35,
|
||||
"_count": {
|
||||
"fases": 4,
|
||||
"gastos": 12
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Crear obra
|
||||
|
||||
```http
|
||||
POST /api/obras
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
**Body:**
|
||||
```json
|
||||
{
|
||||
"codigo": "OBR-2024-002",
|
||||
"nombre": "Casa Habitación López",
|
||||
"descripcion": "Construcción de casa de 2 niveles",
|
||||
"cliente": "Juan López García",
|
||||
"ubicacion": "Fracc. Las Palmas #123",
|
||||
"presupuestoTotal": 2500000,
|
||||
"fechaInicio": "2024-03-01",
|
||||
"fechaFinEstimada": "2024-09-30"
|
||||
}
|
||||
```
|
||||
|
||||
**Campos:**
|
||||
| Campo | Tipo | Requerido | Descripción |
|
||||
|-------|------|-----------|-------------|
|
||||
| codigo | string | Sí | Código único de la obra |
|
||||
| nombre | string | Sí | Nombre del proyecto |
|
||||
| descripcion | string | No | Descripción detallada |
|
||||
| cliente | string | Sí | Nombre del cliente |
|
||||
| ubicacion | string | No | Dirección o ubicación |
|
||||
| presupuestoTotal | number | Sí | Presupuesto en MXN |
|
||||
| fechaInicio | date | Sí | Fecha de inicio |
|
||||
| fechaFinEstimada | date | No | Fecha estimada de finalización |
|
||||
|
||||
**Respuesta exitosa (201):**
|
||||
```json
|
||||
{
|
||||
"id": "cmkk7tf4900085x5semza5bzu",
|
||||
"codigo": "OBR-2024-002",
|
||||
"nombre": "Casa Habitación López",
|
||||
"estado": "PLANEACION",
|
||||
"avanceGeneral": 0,
|
||||
"createdAt": "2024-01-20T10:30:00.000Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Obtener obra por ID
|
||||
|
||||
```http
|
||||
GET /api/obras/{id}
|
||||
```
|
||||
|
||||
**Parámetros de URL:**
|
||||
| Parámetro | Tipo | Descripción |
|
||||
|-----------|------|-------------|
|
||||
| id | string | ID de la obra |
|
||||
|
||||
**Respuesta exitosa (200):**
|
||||
```json
|
||||
{
|
||||
"id": "cmkk6tf4900085x5semza5bzu",
|
||||
"codigo": "OBR-2024-001",
|
||||
"nombre": "Edificio Residencial Aurora",
|
||||
"descripcion": "Construcción de edificio de 8 niveles",
|
||||
"estado": "EN_PROGRESO",
|
||||
"presupuestoTotal": 15000000,
|
||||
"avanceGeneral": 35,
|
||||
"fases": [
|
||||
{
|
||||
"id": "fase1",
|
||||
"nombre": "Cimentación",
|
||||
"orden": 1,
|
||||
"avance": 100,
|
||||
"estado": "COMPLETADA"
|
||||
}
|
||||
],
|
||||
"gastos": [
|
||||
{
|
||||
"id": "gasto1",
|
||||
"concepto": "Compra de cemento",
|
||||
"monto": 45000,
|
||||
"estado": "APROBADO"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Actualizar obra
|
||||
|
||||
```http
|
||||
PUT /api/obras/{id}
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
**Body:** (campos opcionales)
|
||||
```json
|
||||
{
|
||||
"nombre": "Edificio Residencial Aurora - Fase 2",
|
||||
"estado": "EN_PROGRESO",
|
||||
"avanceGeneral": 45
|
||||
}
|
||||
```
|
||||
|
||||
**Respuesta exitosa (200):** Objeto obra actualizado
|
||||
|
||||
### Eliminar obra
|
||||
|
||||
```http
|
||||
DELETE /api/obras/{id}
|
||||
```
|
||||
|
||||
**Respuesta exitosa (200):**
|
||||
```json
|
||||
{
|
||||
"message": "Obra eliminada exitosamente"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Endpoints de Gastos
|
||||
|
||||
### Listar gastos
|
||||
|
||||
```http
|
||||
GET /api/gastos
|
||||
```
|
||||
|
||||
**Query Parameters:**
|
||||
| Parámetro | Tipo | Descripción |
|
||||
|-----------|------|-------------|
|
||||
| obraId | string | Filtrar por obra específica |
|
||||
| estado | string | Filtrar por estado (PENDIENTE, APROBADO, RECHAZADO) |
|
||||
|
||||
**Respuesta exitosa (200):**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "cmkk6tf5r000k5x5sxwf04qji",
|
||||
"concepto": "Compra de materiales",
|
||||
"descripcion": "Cemento y varilla para cimentación",
|
||||
"monto": 85000,
|
||||
"categoria": "MATERIALES",
|
||||
"estado": "APROBADO",
|
||||
"fecha": "2024-01-20T00:00:00.000Z",
|
||||
"comprobante": "FAC-12345",
|
||||
"obra": {
|
||||
"id": "obra1",
|
||||
"nombre": "Edificio Aurora"
|
||||
},
|
||||
"usuario": {
|
||||
"nombre": "Juan",
|
||||
"apellido": "Pérez"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Crear gasto
|
||||
|
||||
```http
|
||||
POST /api/gastos
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
**Body:**
|
||||
```json
|
||||
{
|
||||
"concepto": "Pago de mano de obra",
|
||||
"descripcion": "Pago semanal de albañiles",
|
||||
"monto": 25000,
|
||||
"categoria": "MANO_OBRA",
|
||||
"fecha": "2024-01-20",
|
||||
"obraId": "cmkk6tf4900085x5semza5bzu",
|
||||
"comprobante": "REC-001"
|
||||
}
|
||||
```
|
||||
|
||||
**Campos:**
|
||||
| Campo | Tipo | Requerido | Descripción |
|
||||
|-------|------|-----------|-------------|
|
||||
| concepto | string | Sí | Concepto del gasto |
|
||||
| descripcion | string | No | Descripción detallada |
|
||||
| monto | number | Sí | Monto en MXN |
|
||||
| categoria | enum | Sí | MATERIALES, MANO_OBRA, SUBCONTRATO, EQUIPO, TRANSPORTE, ADMINISTRATIVO, OTROS |
|
||||
| fecha | date | Sí | Fecha del gasto |
|
||||
| obraId | string | Sí | ID de la obra asociada |
|
||||
| comprobante | string | No | Número de factura/recibo |
|
||||
|
||||
**Respuesta exitosa (201):** Objeto gasto creado
|
||||
|
||||
### Aprobar gasto
|
||||
|
||||
```http
|
||||
PATCH /api/gastos/{id}/aprobar
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
**Body:**
|
||||
```json
|
||||
{
|
||||
"estado": "APROBADO"
|
||||
}
|
||||
```
|
||||
|
||||
**Valores permitidos para estado:** `APROBADO`, `RECHAZADO`
|
||||
|
||||
**Respuesta exitosa (200):** Objeto gasto actualizado
|
||||
|
||||
### Eliminar gasto
|
||||
|
||||
```http
|
||||
DELETE /api/gastos/{id}
|
||||
```
|
||||
|
||||
**Respuesta exitosa (200):**
|
||||
```json
|
||||
{
|
||||
"message": "Gasto eliminado exitosamente"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Endpoints de Materiales
|
||||
|
||||
### Listar materiales
|
||||
|
||||
```http
|
||||
GET /api/materiales
|
||||
```
|
||||
|
||||
**Respuesta exitosa (200):**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "cmkk6tf6f000x5x5s413dejgf",
|
||||
"codigo": "CEM-001",
|
||||
"nombre": "Cemento Portland",
|
||||
"descripcion": "Cemento gris tipo I",
|
||||
"unidad": "BOLSA",
|
||||
"precioUnitario": 180,
|
||||
"stockMinimo": 100,
|
||||
"stockActual": 250,
|
||||
"ubicacion": "Bodega A",
|
||||
"activo": true
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Crear material
|
||||
|
||||
```http
|
||||
POST /api/materiales
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
**Body:**
|
||||
```json
|
||||
{
|
||||
"codigo": "VAR-002",
|
||||
"nombre": "Varilla corrugada 1/2",
|
||||
"descripcion": "Varilla de acero corrugado",
|
||||
"unidad": "PIEZA",
|
||||
"precioUnitario": 180,
|
||||
"stockMinimo": 200,
|
||||
"ubicacion": "Bodega B"
|
||||
}
|
||||
```
|
||||
|
||||
**Campos:**
|
||||
| Campo | Tipo | Requerido | Descripción |
|
||||
|-------|------|-----------|-------------|
|
||||
| codigo | string | Sí | Código único del material |
|
||||
| nombre | string | Sí | Nombre del material |
|
||||
| descripcion | string | No | Descripción |
|
||||
| unidad | enum | Sí | PIEZA, METRO, METRO_CUADRADO, METRO_CUBICO, KILOGRAMO, LITRO, BOLSA, BULTO, ROLLO, CAJA, UNIDAD |
|
||||
| precioUnitario | number | Sí | Precio por unidad |
|
||||
| stockMinimo | number | No | Stock mínimo para alertas |
|
||||
| ubicacion | string | No | Ubicación en bodega |
|
||||
|
||||
**Respuesta exitosa (201):** Objeto material creado
|
||||
|
||||
### Actualizar material
|
||||
|
||||
```http
|
||||
PUT /api/materiales/{id}
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
**Body:** (campos opcionales)
|
||||
```json
|
||||
{
|
||||
"precioUnitario": 195,
|
||||
"stockMinimo": 150
|
||||
}
|
||||
```
|
||||
|
||||
### Eliminar material
|
||||
|
||||
```http
|
||||
DELETE /api/materiales/{id}
|
||||
```
|
||||
|
||||
### Registrar movimiento de inventario
|
||||
|
||||
```http
|
||||
POST /api/materiales/movimiento
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
**Body:**
|
||||
```json
|
||||
{
|
||||
"materialId": "cmkk6tf6f000x5x5s413dejgf",
|
||||
"tipo": "SALIDA",
|
||||
"cantidad": 50,
|
||||
"motivo": "Envío a obra Edificio Aurora",
|
||||
"obraId": "cmkk6tf4900085x5semza5bzu"
|
||||
}
|
||||
```
|
||||
|
||||
**Campos:**
|
||||
| Campo | Tipo | Requerido | Descripción |
|
||||
|-------|------|-----------|-------------|
|
||||
| materialId | string | Sí | ID del material |
|
||||
| tipo | enum | Sí | ENTRADA, SALIDA, AJUSTE |
|
||||
| cantidad | number | Sí | Cantidad del movimiento |
|
||||
| motivo | string | No | Razón del movimiento |
|
||||
| obraId | string | No | Obra destino (para salidas) |
|
||||
|
||||
**Respuesta exitosa (201):**
|
||||
```json
|
||||
{
|
||||
"id": "mov123",
|
||||
"tipo": "SALIDA",
|
||||
"cantidad": 50,
|
||||
"motivo": "Envío a obra Edificio Aurora",
|
||||
"materialId": "cmkk6tf6f000x5x5s413dejgf",
|
||||
"obraId": "cmkk6tf4900085x5semza5bzu",
|
||||
"createdAt": "2024-01-20T15:30:00.000Z"
|
||||
}
|
||||
```
|
||||
|
||||
**Nota:** El stock del material se actualiza automáticamente según el tipo de movimiento.
|
||||
|
||||
---
|
||||
|
||||
## Códigos de Error
|
||||
|
||||
| Código | Descripción |
|
||||
|--------|-------------|
|
||||
| 400 | Bad Request - Datos inválidos |
|
||||
| 401 | Unauthorized - No autenticado |
|
||||
| 403 | Forbidden - Sin permisos |
|
||||
| 404 | Not Found - Recurso no encontrado |
|
||||
| 500 | Internal Server Error |
|
||||
|
||||
**Formato de error:**
|
||||
```json
|
||||
{
|
||||
"error": "Descripción del error"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Ejemplos con cURL
|
||||
|
||||
### Login y obtener materiales
|
||||
|
||||
```bash
|
||||
# 1. Obtener CSRF token
|
||||
CSRF=$(curl -s -c cookies.txt http://localhost:3000/api/auth/csrf | grep -oP '"csrfToken":"[^"]*"' | cut -d'"' -f4)
|
||||
|
||||
# 2. Login
|
||||
curl -s -b cookies.txt -c cookies.txt \
|
||||
-X POST "http://localhost:3000/api/auth/callback/credentials" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "csrfToken=$CSRF&email=admin@demo.com&password=admin123"
|
||||
|
||||
# 3. Obtener materiales
|
||||
curl -s -b cookies.txt http://localhost:3000/api/materiales
|
||||
```
|
||||
|
||||
### Crear un gasto
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:3000/api/gastos \
|
||||
-b cookies.txt \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"concepto": "Compra de cemento",
|
||||
"monto": 15000,
|
||||
"categoria": "MATERIALES",
|
||||
"fecha": "2024-01-20",
|
||||
"obraId": "cmkk6tf4900085x5semza5bzu"
|
||||
}'
|
||||
```
|
||||
|
||||
### Registrar entrada de material
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:3000/api/materiales/movimiento \
|
||||
-b cookies.txt \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"materialId": "cmkk6tf6f000x5x5s413dejgf",
|
||||
"tipo": "ENTRADA",
|
||||
"cantidad": 100,
|
||||
"motivo": "Compra a proveedor"
|
||||
}'
|
||||
```
|
||||
486
docs/DATABASE.md
Normal file
486
docs/DATABASE.md
Normal file
@@ -0,0 +1,486 @@
|
||||
# Documentación de Base de Datos - Mexus App
|
||||
|
||||
Este documento describe el esquema de base de datos utilizado en Mexus App.
|
||||
|
||||
## Diagrama de Relaciones
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ Empresa │───────│ User │───────│ Gasto │
|
||||
└─────────────┘ └─────────────┘ └─────────────┘
|
||||
│ │
|
||||
│ │
|
||||
▼ ▼
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ Obra │───────│ FaseObra │───────│ TareaObra │
|
||||
└─────────────┘ └─────────────┘ └─────────────┘
|
||||
│
|
||||
├──────────────┬──────────────┬──────────────┐
|
||||
▼ ▼ ▼ ▼
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ Presupuesto │ │ Empleado │ │Subcontratist│ │ Material │
|
||||
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌─────────────┐ ┌─────────────┐
|
||||
│ Partida │ │ Movimiento │
|
||||
│ Presupuesto │ │ Inventario │
|
||||
└─────────────┘ └─────────────┘
|
||||
```
|
||||
|
||||
## Modelos de Datos
|
||||
|
||||
### Empresa
|
||||
|
||||
Representa una empresa en el sistema (multi-tenant).
|
||||
|
||||
| Campo | Tipo | Descripción |
|
||||
|-------|------|-------------|
|
||||
| id | String | ID único (CUID) |
|
||||
| nombre | String | Nombre de la empresa |
|
||||
| rfc | String? | RFC (único) |
|
||||
| direccion | String? | Dirección |
|
||||
| telefono | String? | Teléfono |
|
||||
| email | String? | Email de contacto |
|
||||
| logo | String? | URL del logo |
|
||||
| activo | Boolean | Estado activo (default: true) |
|
||||
| createdAt | DateTime | Fecha de creación |
|
||||
| updatedAt | DateTime | Fecha de actualización |
|
||||
|
||||
**Relaciones:**
|
||||
- `usuarios` → User[] (1:N)
|
||||
- `obras` → Obra[] (1:N)
|
||||
- `materiales` → Material[] (1:N)
|
||||
- `empleados` → Empleado[] (1:N)
|
||||
- `subcontratistas` → Subcontratista[] (1:N)
|
||||
|
||||
---
|
||||
|
||||
### User
|
||||
|
||||
Usuarios del sistema con roles y permisos.
|
||||
|
||||
| Campo | Tipo | Descripción |
|
||||
|-------|------|-------------|
|
||||
| id | String | ID único (CUID) |
|
||||
| email | String | Email (único) |
|
||||
| password | String | Contraseña hasheada |
|
||||
| nombre | String | Nombre |
|
||||
| apellido | String | Apellido |
|
||||
| telefono | String? | Teléfono |
|
||||
| role | Role | Rol del usuario |
|
||||
| activo | Boolean | Estado activo (default: true) |
|
||||
| empresaId | String | ID de la empresa |
|
||||
| createdAt | DateTime | Fecha de creación |
|
||||
| updatedAt | DateTime | Fecha de actualización |
|
||||
|
||||
**Enum Role:**
|
||||
- `ADMIN` - Administrador con acceso total
|
||||
- `GERENTE` - Gerente de proyectos
|
||||
- `SUPERVISOR` - Supervisor de obra
|
||||
- `CONTADOR` - Contador/finanzas
|
||||
- `EMPLEADO` - Empleado general
|
||||
|
||||
**Relaciones:**
|
||||
- `empresa` → Empresa (N:1)
|
||||
- `gastos` → Gasto[] (1:N)
|
||||
- `obrasCreadas` → Obra[] (1:N)
|
||||
|
||||
---
|
||||
|
||||
### Obra
|
||||
|
||||
Proyectos de construcción.
|
||||
|
||||
| Campo | Tipo | Descripción |
|
||||
|-------|------|-------------|
|
||||
| id | String | ID único (CUID) |
|
||||
| codigo | String | Código único de obra |
|
||||
| nombre | String | Nombre del proyecto |
|
||||
| descripcion | String? | Descripción |
|
||||
| cliente | String | Nombre del cliente |
|
||||
| ubicacion | String? | Dirección/ubicación |
|
||||
| estado | EstadoObra | Estado actual |
|
||||
| presupuestoTotal | Float | Presupuesto total MXN |
|
||||
| fechaInicio | DateTime | Fecha de inicio |
|
||||
| fechaFinEstimada | DateTime? | Fecha fin estimada |
|
||||
| fechaFinReal | DateTime? | Fecha fin real |
|
||||
| avanceGeneral | Float | Porcentaje de avance (0-100) |
|
||||
| empresaId | String | ID de la empresa |
|
||||
| creadoPorId | String | ID del usuario creador |
|
||||
| createdAt | DateTime | Fecha de creación |
|
||||
| updatedAt | DateTime | Fecha de actualización |
|
||||
|
||||
**Enum EstadoObra:**
|
||||
- `PLANEACION` - En planeación
|
||||
- `EN_PROGRESO` - En ejecución
|
||||
- `PAUSADA` - Pausada temporalmente
|
||||
- `COMPLETADA` - Finalizada
|
||||
- `CANCELADA` - Cancelada
|
||||
|
||||
**Relaciones:**
|
||||
- `empresa` → Empresa (N:1)
|
||||
- `creadoPor` → User (N:1)
|
||||
- `fases` → FaseObra[] (1:N)
|
||||
- `gastos` → Gasto[] (1:N)
|
||||
- `presupuestos` → Presupuesto[] (1:N)
|
||||
- `empleadosAsignados` → EmpleadoObra[] (1:N)
|
||||
- `subcontratistasAsignados` → SubcontratistaObra[] (1:N)
|
||||
- `movimientosInventario` → MovimientoInventario[] (1:N)
|
||||
|
||||
---
|
||||
|
||||
### FaseObra
|
||||
|
||||
Fases o etapas de una obra.
|
||||
|
||||
| Campo | Tipo | Descripción |
|
||||
|-------|------|-------------|
|
||||
| id | String | ID único (CUID) |
|
||||
| nombre | String | Nombre de la fase |
|
||||
| descripcion | String? | Descripción |
|
||||
| orden | Int | Orden de ejecución |
|
||||
| fechaInicio | DateTime? | Fecha de inicio |
|
||||
| fechaFin | DateTime? | Fecha de fin |
|
||||
| avance | Float | Porcentaje de avance (default: 0) |
|
||||
| estado | EstadoFase | Estado de la fase |
|
||||
| obraId | String | ID de la obra |
|
||||
| createdAt | DateTime | Fecha de creación |
|
||||
| updatedAt | DateTime | Fecha de actualización |
|
||||
|
||||
**Enum EstadoFase:**
|
||||
- `PENDIENTE` - No iniciada
|
||||
- `EN_PROGRESO` - En ejecución
|
||||
- `COMPLETADA` - Finalizada
|
||||
- `CANCELADA` - Cancelada
|
||||
|
||||
**Relaciones:**
|
||||
- `obra` → Obra (N:1)
|
||||
- `tareas` → TareaObra[] (1:N)
|
||||
|
||||
---
|
||||
|
||||
### TareaObra
|
||||
|
||||
Tareas específicas dentro de una fase.
|
||||
|
||||
| Campo | Tipo | Descripción |
|
||||
|-------|------|-------------|
|
||||
| id | String | ID único (CUID) |
|
||||
| nombre | String | Nombre de la tarea |
|
||||
| descripcion | String? | Descripción |
|
||||
| fechaInicio | DateTime? | Fecha de inicio |
|
||||
| fechaFin | DateTime? | Fecha de fin |
|
||||
| estado | EstadoTarea | Estado de la tarea |
|
||||
| faseId | String | ID de la fase |
|
||||
| createdAt | DateTime | Fecha de creación |
|
||||
| updatedAt | DateTime | Fecha de actualización |
|
||||
|
||||
**Enum EstadoTarea:**
|
||||
- `PENDIENTE` - No iniciada
|
||||
- `EN_PROGRESO` - En ejecución
|
||||
- `COMPLETADA` - Finalizada
|
||||
- `BLOQUEADA` - Bloqueada por dependencia
|
||||
|
||||
**Relaciones:**
|
||||
- `fase` → FaseObra (N:1)
|
||||
|
||||
---
|
||||
|
||||
### Presupuesto
|
||||
|
||||
Presupuestos asociados a obras.
|
||||
|
||||
| Campo | Tipo | Descripción |
|
||||
|-------|------|-------------|
|
||||
| id | String | ID único (CUID) |
|
||||
| nombre | String | Nombre del presupuesto |
|
||||
| version | Int | Número de versión (default: 1) |
|
||||
| montoTotal | Float | Monto total calculado |
|
||||
| aprobado | Boolean | Estado de aprobación |
|
||||
| fechaAprobacion | DateTime? | Fecha de aprobación |
|
||||
| obraId | String | ID de la obra |
|
||||
| createdAt | DateTime | Fecha de creación |
|
||||
| updatedAt | DateTime | Fecha de actualización |
|
||||
|
||||
**Relaciones:**
|
||||
- `obra` → Obra (N:1)
|
||||
- `partidas` → PartidaPresupuesto[] (1:N)
|
||||
|
||||
---
|
||||
|
||||
### PartidaPresupuesto
|
||||
|
||||
Líneas de detalle de un presupuesto.
|
||||
|
||||
| Campo | Tipo | Descripción |
|
||||
|-------|------|-------------|
|
||||
| id | String | ID único (CUID) |
|
||||
| concepto | String | Concepto/descripción |
|
||||
| unidad | String | Unidad de medida |
|
||||
| cantidad | Float | Cantidad |
|
||||
| precioUnitario | Float | Precio por unidad |
|
||||
| subtotal | Float | Subtotal calculado |
|
||||
| presupuestoId | String | ID del presupuesto |
|
||||
| createdAt | DateTime | Fecha de creación |
|
||||
| updatedAt | DateTime | Fecha de actualización |
|
||||
|
||||
**Relaciones:**
|
||||
- `presupuesto` → Presupuesto (N:1)
|
||||
|
||||
---
|
||||
|
||||
### Gasto
|
||||
|
||||
Registro de gastos de obra.
|
||||
|
||||
| Campo | Tipo | Descripción |
|
||||
|-------|------|-------------|
|
||||
| id | String | ID único (CUID) |
|
||||
| concepto | String | Concepto del gasto |
|
||||
| descripcion | String? | Descripción detallada |
|
||||
| monto | Float | Monto en MXN |
|
||||
| categoria | CategoriaGasto | Categoría |
|
||||
| fecha | DateTime | Fecha del gasto |
|
||||
| comprobante | String? | Número de comprobante |
|
||||
| estado | EstadoGasto | Estado de aprobación |
|
||||
| obraId | String | ID de la obra |
|
||||
| usuarioId | String | ID del usuario que registra |
|
||||
| createdAt | DateTime | Fecha de creación |
|
||||
| updatedAt | DateTime | Fecha de actualización |
|
||||
|
||||
**Enum CategoriaGasto:**
|
||||
- `MATERIALES` - Compra de materiales
|
||||
- `MANO_OBRA` - Pago de mano de obra
|
||||
- `SUBCONTRATO` - Pagos a subcontratistas
|
||||
- `EQUIPO` - Renta/compra de equipo
|
||||
- `TRANSPORTE` - Fletes y transporte
|
||||
- `ADMINISTRATIVO` - Gastos administrativos
|
||||
- `OTROS` - Otros gastos
|
||||
|
||||
**Enum EstadoGasto:**
|
||||
- `PENDIENTE` - Pendiente de aprobación
|
||||
- `APROBADO` - Aprobado
|
||||
- `RECHAZADO` - Rechazado
|
||||
|
||||
**Relaciones:**
|
||||
- `obra` → Obra (N:1)
|
||||
- `usuario` → User (N:1)
|
||||
|
||||
---
|
||||
|
||||
### Factura
|
||||
|
||||
Facturas emitidas y recibidas.
|
||||
|
||||
| Campo | Tipo | Descripción |
|
||||
|-------|------|-------------|
|
||||
| id | String | ID único (CUID) |
|
||||
| numero | String | Número de factura |
|
||||
| tipo | TipoFactura | Tipo (emitida/recibida) |
|
||||
| cliente | String? | Nombre del cliente |
|
||||
| proveedor | String? | Nombre del proveedor |
|
||||
| subtotal | Float | Subtotal |
|
||||
| iva | Float | IVA |
|
||||
| total | Float | Total |
|
||||
| fechaEmision | DateTime | Fecha de emisión |
|
||||
| fechaVencimiento | DateTime? | Fecha de vencimiento |
|
||||
| estado | EstadoFactura | Estado de pago |
|
||||
| obraId | String | ID de la obra |
|
||||
| createdAt | DateTime | Fecha de creación |
|
||||
| updatedAt | DateTime | Fecha de actualización |
|
||||
|
||||
**Enum TipoFactura:**
|
||||
- `EMITIDA` - Factura a cliente
|
||||
- `RECIBIDA` - Factura de proveedor
|
||||
|
||||
**Enum EstadoFactura:**
|
||||
- `PENDIENTE` - Pendiente de pago
|
||||
- `PAGADA` - Pagada
|
||||
- `VENCIDA` - Vencida
|
||||
- `CANCELADA` - Cancelada
|
||||
|
||||
**Relaciones:**
|
||||
- `obra` → Obra (N:1)
|
||||
|
||||
---
|
||||
|
||||
### Material
|
||||
|
||||
Catálogo de materiales de construcción.
|
||||
|
||||
| Campo | Tipo | Descripción |
|
||||
|-------|------|-------------|
|
||||
| id | String | ID único (CUID) |
|
||||
| codigo | String | Código único |
|
||||
| nombre | String | Nombre del material |
|
||||
| descripcion | String? | Descripción |
|
||||
| unidad | UnidadMedida | Unidad de medida |
|
||||
| precioUnitario | Float | Precio por unidad |
|
||||
| stockMinimo | Float | Stock mínimo para alertas |
|
||||
| stockActual | Float | Stock actual (default: 0) |
|
||||
| ubicacion | String? | Ubicación en bodega |
|
||||
| activo | Boolean | Estado activo (default: true) |
|
||||
| empresaId | String | ID de la empresa |
|
||||
| createdAt | DateTime | Fecha de creación |
|
||||
| updatedAt | DateTime | Fecha de actualización |
|
||||
|
||||
**Enum UnidadMedida:**
|
||||
- `PIEZA` - Pieza
|
||||
- `METRO` - Metro lineal
|
||||
- `METRO_CUADRADO` - Metro cuadrado
|
||||
- `METRO_CUBICO` - Metro cúbico
|
||||
- `KILOGRAMO` - Kilogramo
|
||||
- `LITRO` - Litro
|
||||
- `BOLSA` - Bolsa
|
||||
- `BULTO` - Bulto
|
||||
- `ROLLO` - Rollo
|
||||
- `CAJA` - Caja
|
||||
- `UNIDAD` - Unidad
|
||||
|
||||
**Relaciones:**
|
||||
- `empresa` → Empresa (N:1)
|
||||
- `movimientos` → MovimientoInventario[] (1:N)
|
||||
|
||||
**Índice único:** `@@unique([codigo, empresaId])`
|
||||
|
||||
---
|
||||
|
||||
### MovimientoInventario
|
||||
|
||||
Registro de movimientos de inventario.
|
||||
|
||||
| Campo | Tipo | Descripción |
|
||||
|-------|------|-------------|
|
||||
| id | String | ID único (CUID) |
|
||||
| tipo | TipoMovimiento | Tipo de movimiento |
|
||||
| cantidad | Float | Cantidad |
|
||||
| motivo | String? | Motivo/descripción |
|
||||
| materialId | String | ID del material |
|
||||
| obraId | String? | ID de la obra (opcional) |
|
||||
| createdAt | DateTime | Fecha de creación |
|
||||
|
||||
**Enum TipoMovimiento:**
|
||||
- `ENTRADA` - Entrada de material
|
||||
- `SALIDA` - Salida de material
|
||||
- `AJUSTE` - Ajuste de inventario
|
||||
|
||||
**Relaciones:**
|
||||
- `material` → Material (N:1)
|
||||
- `obra` → Obra (N:1, opcional)
|
||||
|
||||
---
|
||||
|
||||
### Empleado
|
||||
|
||||
Personal de la empresa.
|
||||
|
||||
| Campo | Tipo | Descripción |
|
||||
|-------|------|-------------|
|
||||
| id | String | ID único (CUID) |
|
||||
| codigo | String | Código de empleado |
|
||||
| nombre | String | Nombre |
|
||||
| apellido | String | Apellido |
|
||||
| curp | String? | CURP |
|
||||
| rfc | String? | RFC |
|
||||
| telefono | String? | Teléfono |
|
||||
| email | String? | Email |
|
||||
| puesto | String | Puesto/cargo |
|
||||
| salarioDiario | Float | Salario diario |
|
||||
| fechaIngreso | DateTime | Fecha de ingreso |
|
||||
| activo | Boolean | Estado activo (default: true) |
|
||||
| empresaId | String | ID de la empresa |
|
||||
| createdAt | DateTime | Fecha de creación |
|
||||
| updatedAt | DateTime | Fecha de actualización |
|
||||
|
||||
**Relaciones:**
|
||||
- `empresa` → Empresa (N:1)
|
||||
- `obrasAsignadas` → EmpleadoObra[] (1:N)
|
||||
- `jornadas` → JornadaLaboral[] (1:N)
|
||||
|
||||
---
|
||||
|
||||
### Subcontratista
|
||||
|
||||
Empresas subcontratadas.
|
||||
|
||||
| Campo | Tipo | Descripción |
|
||||
|-------|------|-------------|
|
||||
| id | String | ID único (CUID) |
|
||||
| nombre | String | Nombre/razón social |
|
||||
| rfc | String? | RFC |
|
||||
| contacto | String? | Persona de contacto |
|
||||
| telefono | String? | Teléfono |
|
||||
| email | String? | Email |
|
||||
| especialidad | String | Especialidad/giro |
|
||||
| activo | Boolean | Estado activo (default: true) |
|
||||
| empresaId | String | ID de la empresa |
|
||||
| createdAt | DateTime | Fecha de creación |
|
||||
| updatedAt | DateTime | Fecha de actualización |
|
||||
|
||||
**Relaciones:**
|
||||
- `empresa` → Empresa (N:1)
|
||||
- `obrasAsignadas` → SubcontratistaObra[] (1:N)
|
||||
|
||||
---
|
||||
|
||||
## Tablas de Relación (N:M)
|
||||
|
||||
### EmpleadoObra
|
||||
|
||||
Asignación de empleados a obras.
|
||||
|
||||
| Campo | Tipo | Descripción |
|
||||
|-------|------|-------------|
|
||||
| id | String | ID único (CUID) |
|
||||
| empleadoId | String | ID del empleado |
|
||||
| obraId | String | ID de la obra |
|
||||
| fechaAsignacion | DateTime | Fecha de asignación |
|
||||
| fechaFin | DateTime? | Fecha de fin |
|
||||
| activo | Boolean | Asignación activa |
|
||||
|
||||
### SubcontratistaObra
|
||||
|
||||
Asignación de subcontratistas a obras.
|
||||
|
||||
| Campo | Tipo | Descripción |
|
||||
|-------|------|-------------|
|
||||
| id | String | ID único (CUID) |
|
||||
| subcontratistaId | String | ID del subcontratista |
|
||||
| obraId | String | ID de la obra |
|
||||
| descripcionTrabajo | String | Descripción del trabajo |
|
||||
| montoContrato | Float | Monto del contrato |
|
||||
| fechaInicio | DateTime | Fecha de inicio |
|
||||
| fechaFin | DateTime? | Fecha de fin |
|
||||
| estado | EstadoContrato | Estado del contrato |
|
||||
|
||||
---
|
||||
|
||||
## Comandos de Prisma
|
||||
|
||||
```bash
|
||||
# Generar cliente Prisma
|
||||
npx prisma generate
|
||||
|
||||
# Crear migración
|
||||
npx prisma migrate dev --name descripcion_cambio
|
||||
|
||||
# Aplicar migraciones en producción
|
||||
npx prisma migrate deploy
|
||||
|
||||
# Ver base de datos en navegador
|
||||
npx prisma studio
|
||||
|
||||
# Ejecutar seed
|
||||
npx prisma db seed
|
||||
|
||||
# Resetear base de datos (desarrollo)
|
||||
npx prisma migrate reset
|
||||
```
|
||||
|
||||
## Consideraciones de Seguridad
|
||||
|
||||
1. **Multi-tenant**: Todas las queries filtran por `empresaId` del usuario autenticado
|
||||
2. **Índices**: Se han creado índices en campos frecuentemente consultados
|
||||
3. **Cascade**: Las eliminaciones en cascada están configuradas para mantener integridad
|
||||
4. **Soft delete**: Los registros importantes usan campo `activo` en lugar de eliminación física
|
||||
Reference in New Issue
Block a user