Refactor: Centralize Prisma schema and restrict DB access
This commit refactors the project to use a shared Prisma schema and restricts direct database access to the API service. Key changes: - Created a new shared package `core/prisma` containing the Prisma schema, generated client, and types. - Configured the monorepo to use NPM workspaces, including `core/prisma` and all services. - Updated all services (`api`, `ui`, `mcp`, `agent`, and the background processing service) to depend on `@empresa/prisma-schema`. - The API service now imports `PrismaClient` from `@empresa/prisma-schema/client`. - Other services import only types from `@empresa/prisma-schema`. - Removed redundant Prisma configurations from `api` and the background processing service. - Updated the background processing service's `sync-empleados.js` to fetch data via an API call instead of direct database access. - Updated TypeScript configurations (`tsconfig.base.json` and service-specific ones) to support the new structure and path aliases. - Updated `README.md` to reflect the new architecture and added convenience scripts for Prisma operations. This change promotes a single source of truth for data models, reduces code duplication, and improves the overall architecture by centralizing database operations within the API service.
This commit is contained in:
224
README.md
224
README.md
@@ -12,125 +12,219 @@
|
||||
|
||||
## 📂 Estructura del proyecto
|
||||
|
||||
El proyecto ahora está organizado como un monorepo utilizando workspaces (npm/yarn/pnpm).
|
||||
|
||||
```
|
||||
planilla/
|
||||
├─ .gitea/workflows/build.yml # CI/CD: build + push + deploy
|
||||
├─ api/ # servicio API
|
||||
├─ agent/ # Servicio Agent (Node.js)
|
||||
│ ├─ Dockerfile
|
||||
│ └─ package.json
|
||||
├─ api/ # Servicio API (Node.js + Express)
|
||||
│ ├─ Dockerfile
|
||||
│ ├─ jsconfig.json
|
||||
│ ├─ package.json
|
||||
│ └─ server.js
|
||||
├─ ui/ # frontend Vue 3
|
||||
├─ core/
|
||||
│ └─ prisma/ # Paquete compartido para el schema y cliente Prisma
|
||||
│ ├─ package.json
|
||||
│ ├─ tsconfig.json
|
||||
│ ├─ schema.prisma
|
||||
│ ├─ index.ts # Exporta tipos de Prisma
|
||||
│ └─ client.ts # Exporta PrismaClient
|
||||
├─ mcp/ # Servicio MCP (Node.js)
|
||||
│ ├─ Dockerfile
|
||||
│ └─ package.json
|
||||
├─ ui/ # Frontend Vue 3 + Vite
|
||||
│ ├─ Dockerfile
|
||||
│ ├─ tsconfig.json
|
||||
│ ├─ package.json
|
||||
│ ├─ index.html
|
||||
│ ├─ src/
|
||||
│ └─ vite.config.js
|
||||
├─ Dockerfile # imagen raíz (si aplica)
|
||||
├─ docker-compose.yml # orquestación de todos los servicios
|
||||
└─ README.md # este documento
|
||||
├─ worker/ # Servicio Worker (Node.js)
|
||||
│ ├─ Dockerfile
|
||||
│ ├─ jsconfig.json
|
||||
│ └─ package.json
|
||||
├─ package.json # package.json raíz para workspaces
|
||||
├─ tsconfig.base.json # Configuración base de TypeScript para todo el monorepo
|
||||
├─ docker-compose.yml # Orquestación de todos los servicios
|
||||
└─ README.md # Este documento
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Workspaces and Shared Packages
|
||||
|
||||
Este monorepo utiliza workspaces para gestionar múltiples paquetes/servicios. La configuración de workspaces se encuentra en el `package.json` raíz.
|
||||
|
||||
### `@empresa/prisma-schema` (`core/prisma`)
|
||||
|
||||
Este es un paquete compartido que centraliza la definición del schema de Prisma y la configuración del cliente.
|
||||
|
||||
* **Schema**: `core/prisma/schema.prisma`
|
||||
* **Generación del Cliente**: El cliente Prisma se genera dentro de este paquete.
|
||||
* **Consumo de Tipos**: Otros servicios (UI, workers, etc.) deben importar los tipos generados por Prisma desde `@empresa/prisma-schema`.
|
||||
```typescript
|
||||
import type { Employee, OtherModel } from '@empresa/prisma-schema';
|
||||
```
|
||||
* **Consumo del Cliente Prisma (`PrismaClient`)**: La instancia de `PrismaClient` solo debe ser utilizada por el servicio `api`. Se importa de la siguiente manera:
|
||||
```javascript
|
||||
// En api/server.js o similar
|
||||
import { PrismaClient } from '@empresa/prisma-schema/client';
|
||||
const prisma = new PrismaClient();
|
||||
```
|
||||
Otros servicios **no deben** importar ni instanciar `PrismaClient` directamente. Deben interactuar con la base de datos a través de la API.
|
||||
|
||||
### TypeScript Configuration
|
||||
|
||||
* Un `tsconfig.base.json` en la raíz define configuraciones comunes de TypeScript, incluyendo alias de path para `@empresa/prisma-schema`.
|
||||
* Cada servicio/paquete que utiliza TypeScript tiene su propio `tsconfig.json` (o `jsconfig.json` para proyectos JavaScript) que extiende la configuración base.
|
||||
* El paquete `core/prisma` compila su salida (cliente Prisma y tipos) a su directorio `dist/`.
|
||||
|
||||
---
|
||||
|
||||
## 📝 Requisitos
|
||||
|
||||
* **Docker** (v20+)
|
||||
* **Docker Compose** (v2+)
|
||||
* **Node.js** (v18+) y **npm** para desarrollo local
|
||||
* **Node.js** (v18+) y **npm** (o yarn/pnpm) para desarrollo local y gestión de workspaces.
|
||||
* **Acceso a red** `app-net` y `principal` en Docker
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Variables de entorno
|
||||
|
||||
Si querés cambiar credenciales, editá directamente en `docker-compose.yml` o usá un `.env`:
|
||||
Las variables de entorno relevantes para cada servicio se pueden encontrar en sus respectivos Dockerfiles o en `docker-compose.yml`. La variable `DATABASE_URL` para la conexión a PostgreSQL es utilizada por el paquete `core/prisma` (y por ende, por la `api` que lo consume) y debe estar configurada para que la `api` funcione correctamente.
|
||||
|
||||
```dotenv
|
||||
# Ejemplo de variables en .env o docker-compose.yml
|
||||
COMPOSE_PROJECT_NAME=planilla
|
||||
POSTGRES_USER=usuario
|
||||
POSTGRES_PASSWORD=clave
|
||||
POSTGRES_DB=midb
|
||||
DATABASE_URL="postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Levantando los servicios
|
||||
|
||||
1. **Clonar repo**
|
||||
|
||||
```bash
|
||||
```
|
||||
|
||||
git clone [https://gitea.interno.com/nucleo000/planilla.git](https://gitea.interno.com/nucleo000/planilla.git)
|
||||
cd planilla
|
||||
|
||||
````
|
||||
2. **Construir y levantar**
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
````
|
||||
|
||||
3. **Ver logs**
|
||||
|
||||
```bash
|
||||
```
|
||||
|
||||
docker compose logs -f api ui
|
||||
|
||||
````
|
||||
4. **Detener todo**
|
||||
```bash
|
||||
docker compose down --remove-orphans
|
||||
````
|
||||
1. **Clonar repo**
|
||||
```bash
|
||||
git clone [https://gitea.interno.com/nucleo000/planilla.git](https://gitea.interno.com/nucleo000/planilla.git)
|
||||
cd planilla
|
||||
```
|
||||
2. **Instalar dependencias de workspaces** (desde la raíz del monorepo)
|
||||
```bash
|
||||
npm install # o yarn install / pnpm install
|
||||
```
|
||||
3. **Generar cliente Prisma** (necesario después de instalar o si cambias el schema)
|
||||
Desde la raíz del monorepo:
|
||||
```bash
|
||||
npm run db:generate --workspace=@empresa/prisma-schema # o yarn workspace @empresa/prisma-schema db:generate
|
||||
```
|
||||
O directamente desde el paquete:
|
||||
```bash
|
||||
cd core/prisma
|
||||
npm run db:generate
|
||||
cd ../..
|
||||
```
|
||||
4. **Construir y levantar contenedores Docker**
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
5. **Ver logs**
|
||||
```bash
|
||||
docker compose logs -f api ui worker # Agrega otros servicios según sea necesario
|
||||
```
|
||||
6. **Detener todo**
|
||||
```bash
|
||||
docker compose down --remove-orphans
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📡 Acceso a la aplicación
|
||||
|
||||
* La **UI** no expone puertos en el host. En Nginx Proxy Manager (red `principal`):
|
||||
* La **UI** (`ui` service) no expone puertos en el host. En Nginx Proxy Manager (red `principal`):
|
||||
* **Domino**: `planilla.midominio.com` (o el que configures)
|
||||
* **Scheme**: http
|
||||
* **Forward Hostname**: `planilla-ui` (o el nombre de contenedor que uses en `docker-compose.yml`)
|
||||
* **Forward Port**: `80` (o el puerto que exponga el contenedor de la UI, si es diferente)
|
||||
Posteriormente, puedes habilitar SSL Let’s Encrypt desde la pestaña **SSL** en Nginx Proxy Manager.
|
||||
|
||||
* **Domino**: `planilla.midominio.com`
|
||||
* **Scheme**: http
|
||||
* **Forward Hostname**: `planilla-ui` (o `ui` si así lo nombraste)
|
||||
* **Forward Port**: `80`
|
||||
|
||||
Después podés habilitar SSL Let’s Encrypt desde la pestaña **SSL**.
|
||||
|
||||
* La **API** corre internamente en `planilla-api:4000` y no se expone externamente. Vu hace proxy la UI o clientes internos.
|
||||
* La **API** (`api` service) corre internamente, por defecto en el puerto `4000`, y no se expone directamente al exterior. La UI u otros servicios internos pueden accederla por su nombre de servicio y puerto (e.g., `http://api:4000`).
|
||||
|
||||
---
|
||||
|
||||
## 🗄️ Detalles de cada servicio
|
||||
|
||||
### Base de datos (db)
|
||||
### Base de datos (`db`)
|
||||
|
||||
* Imagen: `postgres:15`
|
||||
* Volumen persistente: `db_data`
|
||||
* Credenciales en `docker-compose.yml`.
|
||||
* Imagen: `postgres:15`
|
||||
* Volumen persistente: `db_data`
|
||||
* Credenciales y configuración en `docker-compose.yml` y/o archivo `.env`.
|
||||
* El schema es gestionado por Prisma en `core/prisma/schema.prisma`. Las migraciones se aplican a través de los comandos de Prisma CLI.
|
||||
|
||||
### API (api)
|
||||
### API (`api`)
|
||||
|
||||
* **Framework**: Express
|
||||
* **DB**: `pg` (Pool)
|
||||
* **Endpoints**:
|
||||
* **Framework**: Express
|
||||
* Utiliza el cliente Prisma desde `@empresa/prisma-schema/client` para interactuar con la base de datos.
|
||||
* Las definiciones de tipos (ej. para cuerpos de request/response) pueden ser importadas desde `@empresa/prisma-schema`.
|
||||
* Arranca en el puerto **4000** internamente (configurable).
|
||||
* Código principal en `api/server.js`.
|
||||
|
||||
* `GET /api/items` → devuelve `items` desde Postgres.
|
||||
* Arranca en puerto **4000** internamente.
|
||||
* Código principal en `api/server.js`.
|
||||
### UI (`ui`)
|
||||
|
||||
> Aviso: si ves `SyntaxError` al usar `import`, asegurate de tener en `api/package.json`:
|
||||
>
|
||||
> ```json
|
||||
> {
|
||||
> "type": "module"
|
||||
> }
|
||||
> ```
|
||||
* **Framework**: Vue 3 + Vite
|
||||
* Importa tipos de datos (ej. `Employee`) desde `@empresa/prisma-schema` para type-safety en el frontend.
|
||||
* Consume datos de la API (`api` service).
|
||||
* Arranca en el puerto **80** internamente (configurable a través de `vite.config.js` y `Dockerfile`).
|
||||
* Código fuente en `ui/src/`.
|
||||
|
||||
### UI (ui)
|
||||
### Worker (`worker`)
|
||||
|
||||
* **Framework**: Vue 3 + Vite
|
||||
* **Build**: produce carpeta `dist/` y se sirve con Nginx
|
||||
* Arranca en puerto **80** internamente.
|
||||
* Código fuente en `ui/src/`, configuración en `vite.config.js`.
|
||||
* Servicio Node.js para tareas en segundo plano o programadas.
|
||||
* Puede importar tipos desde `@empresa/prisma-schema`.
|
||||
* Debe interactuar con la base de datos **a través de la API**, no directamente.
|
||||
|
||||
### Agent (`agent`) y MCP (`mcp`)
|
||||
|
||||
* Otros servicios Node.js.
|
||||
* Pueden importar tipos desde `@empresa/prisma-schema` si necesitan interactuar con estructuras de datos alineadas con la base de datos.
|
||||
* Deben interactuar con la base de datos **a través de la API**.
|
||||
|
||||
---
|
||||
|
||||
## Prisma Migrations
|
||||
|
||||
Las migraciones de la base de datos se gestionan con Prisma CLI desde el paquete `core/prisma`.
|
||||
|
||||
1. **Modificar el schema**: Edita `core/prisma/schema.prisma`.
|
||||
2. **Crear una nueva migración**:
|
||||
Desde la raíz del monorepo:
|
||||
```bash
|
||||
npm run prisma:migrate:dev --workspace=@empresa/prisma-schema -- --name tu-nombre-de-migracion
|
||||
```
|
||||
O directamente desde el paquete `core/prisma`:
|
||||
```bash
|
||||
cd core/prisma
|
||||
npx prisma migrate dev --name tu-nombre-de-migracion
|
||||
cd ../..
|
||||
```
|
||||
Esto generará los archivos SQL de migración en `core/prisma/migrations/`.
|
||||
3. **Aplicar migraciones** (generalmente manejado por el `entrypoint.sh` de la API o un script de despliegue):
|
||||
Desde la raíz:
|
||||
```bash
|
||||
npm run prisma:deploy --workspace=@empresa/prisma-schema
|
||||
```
|
||||
O desde `core/prisma`:
|
||||
```bash
|
||||
npx prisma migrate deploy
|
||||
```
|
||||
4. **Generar cliente Prisma** (después de cambios en el schema o migraciones):
|
||||
Esto se hace con el comando `db:generate` ya mencionado en la sección de levantamiento.
|
||||
|
||||
---
|
||||
|
||||
|
||||
14
agent/jsconfig.json
Normal file
14
agent/jsconfig.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"checkJs": false,
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "node",
|
||||
"target": "esnext", // Or appropriate target for your Node.js version
|
||||
"module": "esnext", // Since package.json has "type": "module"
|
||||
// Paths are inherited from tsconfig.base.json
|
||||
"baseUrl": "." // baseUrl is still needed if there are other local paths
|
||||
},
|
||||
"include": ["**/*.js"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
"@open-wa/wa-automate": "^4.34.3",
|
||||
"mime-types": "^2.1.35",
|
||||
"@modelcontextprotocol/sdk": "^1.0.0",
|
||||
"@philschmid/weather-mcp": "^1.0.0"
|
||||
"@philschmid/weather-mcp": "^1.0.0",
|
||||
"@empresa/prisma-schema": "1.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
14
api/jsconfig.json
Normal file
14
api/jsconfig.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"checkJs": false,
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "node",
|
||||
"target": "esnext", // Or appropriate target for your Node.js version
|
||||
"module": "esnext", // Since package.json has "type": "module"
|
||||
// Paths are inherited from tsconfig.base.json
|
||||
"baseUrl": "." // baseUrl is still needed if there are other local paths
|
||||
},
|
||||
"include": ["**/*.js"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -7,13 +7,11 @@
|
||||
"start": "node server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "^6.8.2",
|
||||
"@empresa/prisma-schema": "1.0.0",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.18.2",
|
||||
"node-cron": "^4.0.5",
|
||||
"pg": "^8.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prisma": "^6.8.2"
|
||||
}
|
||||
"devDependencies": {}
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "Cliente" (
|
||||
"id" BIGSERIAL NOT NULL,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT (now() AT TIME ZONE 'utc'),
|
||||
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT (now() AT TIME ZONE 'utc'),
|
||||
"name" TEXT NOT NULL,
|
||||
"cedula" BIGINT NOT NULL,
|
||||
"ubicacion" TEXT NOT NULL DEFAULT '.',
|
||||
"grupo_estudio" TEXT,
|
||||
"empleado" BOOLEAN NOT NULL DEFAULT false,
|
||||
"avatar_url" TEXT,
|
||||
"telefono" TEXT,
|
||||
"idciat" TEXT,
|
||||
|
||||
CONSTRAINT "Cliente_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Planilla" (
|
||||
"id" BIGSERIAL NOT NULL,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT (now() AT TIME ZONE 'utc'),
|
||||
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT (now() AT TIME ZONE 'utc'),
|
||||
"fecha_desde" TIMESTAMP(3) NOT NULL,
|
||||
"fecha_hasta" TIMESTAMP(3) NOT NULL,
|
||||
"titulo" TEXT NOT NULL,
|
||||
"total" DECIMAL(65,30),
|
||||
"estado" TEXT NOT NULL DEFAULT 'pagado',
|
||||
"fecha_anulado" TIMESTAMP(3),
|
||||
"empleado_id" BIGINT NOT NULL,
|
||||
"creador_id" UUID,
|
||||
"anulador_id" UUID,
|
||||
|
||||
CONSTRAINT "Planilla_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "TareaRealizada" (
|
||||
"id" BIGSERIAL NOT NULL,
|
||||
"empleado_id" BIGINT NOT NULL,
|
||||
"planilla_id" BIGINT,
|
||||
"titulo" TEXT NOT NULL,
|
||||
"precio" DOUBLE PRECISION,
|
||||
"estado" TEXT NOT NULL DEFAULT 'pendiente',
|
||||
"observacion" TEXT,
|
||||
"fecha" TIMESTAMP(3) NOT NULL,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT (now() AT TIME ZONE 'utc'),
|
||||
"tipo" TEXT NOT NULL DEFAULT '',
|
||||
"fecha_anulado" TIMESTAMP(3),
|
||||
"creador_id" UUID NOT NULL,
|
||||
"anulador_id" UUID,
|
||||
|
||||
CONSTRAINT "TareaRealizada_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Asistencia" (
|
||||
"id" BIGSERIAL NOT NULL,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT (now() AT TIME ZONE 'utc'),
|
||||
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT (now() AT TIME ZONE 'utc'),
|
||||
"entrada" TIMESTAMP(3) DEFAULT (now() AT TIME ZONE 'utc'),
|
||||
"salida" TIMESTAMP(3),
|
||||
"historial" JSONB,
|
||||
"observacion" TEXT,
|
||||
"estado" TEXT DEFAULT 'pendiente',
|
||||
"fecha_anulado" TIMESTAMP(3),
|
||||
"empleado_id" BIGINT NOT NULL,
|
||||
"creador_id" UUID NOT NULL,
|
||||
"modificado_id" UUID,
|
||||
"anulador_id" UUID,
|
||||
|
||||
CONSTRAINT "Asistencia_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Cliente_cedula_key" ON "Cliente"("cedula");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Planilla" ADD CONSTRAINT "Planilla_empleado_id_fkey" FOREIGN KEY ("empleado_id") REFERENCES "Cliente"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TareaRealizada" ADD CONSTRAINT "TareaRealizada_empleado_id_fkey" FOREIGN KEY ("empleado_id") REFERENCES "Cliente"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Asistencia" ADD CONSTRAINT "Asistencia_empleado_id_fkey" FOREIGN KEY ("empleado_id") REFERENCES "Cliente"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -1,18 +0,0 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Asistencia" ALTER COLUMN "created_at" SET DEFAULT (now() AT TIME ZONE 'utc'),
|
||||
ALTER COLUMN "updated_at" SET DEFAULT (now() AT TIME ZONE 'utc'),
|
||||
ALTER COLUMN "entrada" SET DEFAULT (now() AT TIME ZONE 'utc');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Cliente" ALTER COLUMN "created_at" SET DEFAULT (now() AT TIME ZONE 'utc'),
|
||||
ALTER COLUMN "updated_at" SET DEFAULT (now() AT TIME ZONE 'utc');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Planilla" ALTER COLUMN "created_at" SET DEFAULT (now() AT TIME ZONE 'utc'),
|
||||
ALTER COLUMN "updated_at" SET DEFAULT (now() AT TIME ZONE 'utc');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "TareaRealizada" ALTER COLUMN "created_at" SET DEFAULT (now() AT TIME ZONE 'utc');
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TareaRealizada" ADD CONSTRAINT "TareaRealizada_planilla_id_fkey" FOREIGN KEY ("planilla_id") REFERENCES "Planilla"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -1,3 +0,0 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (e.g., Git)
|
||||
provider = "postgresql"
|
||||
@@ -1,6 +1,5 @@
|
||||
import express from 'express';
|
||||
import { PrismaClient } from './prisma/generated/client/index.js';
|
||||
import { Decimal } from '@prisma/client/runtime/library.js';
|
||||
import { PrismaClient } from '@empresa/prisma-schema/client';
|
||||
import cors from 'cors';
|
||||
|
||||
// Import new routers
|
||||
@@ -16,7 +15,6 @@ import planillasRouter from './routes/planillas/planillas.js';
|
||||
// Resto del código
|
||||
|
||||
BigInt.prototype.toJSON = function () { return this.toString(); };
|
||||
Decimal.prototype.toJSON = function () { return this.toString(); };
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
export const app = express();
|
||||
|
||||
2
core/prisma/client.ts
Normal file
2
core/prisma/client.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
// This file exports the PrismaClient instance for use in Node.js environments (specifically the API).
|
||||
export { PrismaClient } from './generated/client';
|
||||
7
core/prisma/index.ts
Normal file
7
core/prisma/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
// This file serves as the entry point for the @empresa/prisma-schema package.
|
||||
// It re-exports only the generated types by default.
|
||||
// For PrismaClient instance, import from '@empresa/prisma-schema/client'.
|
||||
|
||||
export * from './generated/client/index-browser'; // Exports types for browser/non-Node.js environments
|
||||
// If you need all types including Node.js specific ones (less common for shared types):
|
||||
// export * from './generated/client';
|
||||
27
core/prisma/package.json
Normal file
27
core/prisma/package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "@empresa/prisma-schema",
|
||||
"version": "1.0.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
},
|
||||
"./client": {
|
||||
"types": "./dist/client.d.ts",
|
||||
"default": "./dist/client.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"db:generate": "prisma generate",
|
||||
"prisma:migrate:dev": "prisma migrate dev",
|
||||
"prisma:deploy": "prisma migrate deploy"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prisma": "^5.10.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "^5.10.2"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
output = "generated/client"
|
||||
output = "./generated/client"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
26
core/prisma/tsconfig.json
Normal file
26
core/prisma/tsconfig.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"target": "es2017",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"outDir": "dist",
|
||||
"declaration": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"declarationDir": "dist",
|
||||
// Overriding base to be specific for this package
|
||||
"baseUrl": ".",
|
||||
"paths": {} // Clear paths from base, not needed here
|
||||
},
|
||||
"include": ["./schema.prisma", "./generated/client", "index.ts", "client.ts"],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist",
|
||||
".next",
|
||||
".turbo",
|
||||
"coverage",
|
||||
"build",
|
||||
"prisma/seed.ts"
|
||||
]
|
||||
}
|
||||
14
mcp/jsconfig.json
Normal file
14
mcp/jsconfig.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"checkJs": false,
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "node",
|
||||
"target": "esnext", // Or appropriate target for your Node.js version
|
||||
"module": "esnext", // Since package.json has "type": "module"
|
||||
// Paths are inherited from tsconfig.base.json
|
||||
"baseUrl": "." // baseUrl is still needed if there are other local paths
|
||||
},
|
||||
"include": ["**/*.js"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
"start": "node index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.0.0"
|
||||
"@modelcontextprotocol/sdk": "^1.0.0",
|
||||
"@empresa/prisma-schema": "1.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
18
package.json
Normal file
18
package.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "empresa-monorepo",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"agent",
|
||||
"api",
|
||||
"core/prisma",
|
||||
"mcp",
|
||||
"ui",
|
||||
"worker"
|
||||
],
|
||||
"scripts": {
|
||||
"db:generate": "npm run db:generate --workspace=@empresa/prisma-schema",
|
||||
"prisma:migrate:dev": "npm run prisma:migrate:dev --workspace=@empresa/prisma-schema",
|
||||
"prisma:deploy": "npm run prisma:deploy --workspace=@empresa/prisma-schema"
|
||||
}
|
||||
}
|
||||
14
tsconfig.base.json
Normal file
14
tsconfig.base.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@empresa/prisma-schema": ["core/prisma/index.ts"], // Points to the main entry for types
|
||||
"@empresa/prisma-schema/client": ["core/prisma/client.ts"] // Points to the client entry
|
||||
},
|
||||
// Common options
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,8 @@
|
||||
"axios": "^1.9.0",
|
||||
"pinia": "^3.0.2",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.5.1"
|
||||
"vue-router": "^4.5.1",
|
||||
"@empresa/prisma-schema": "1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.2.2",
|
||||
|
||||
@@ -43,20 +43,7 @@
|
||||
<script setup lang="ts">
|
||||
import { PropType } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
// Define the structure of the employee object based on the Prisma schema
|
||||
interface Employee {
|
||||
id: string | number // Changed from BigInt to string | number for easier handling in frontend
|
||||
name: string
|
||||
cedula: number // Changed from BigInt
|
||||
avatar_url?: string
|
||||
telefono?: string
|
||||
ubicacion: string
|
||||
idciat?: string
|
||||
grupo_estudio?: string
|
||||
// created_at and updated_at are usually not displayed directly in a summary card
|
||||
// empleado: boolean // This is implicit as it's an employee card
|
||||
}
|
||||
import type { Employee } from '@empresa/prisma-schema'
|
||||
|
||||
const props = defineProps({
|
||||
employee: {
|
||||
|
||||
23
ui/tsconfig.json
Normal file
23
ui/tsconfig.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"jsx": "preserve",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true, // Vite handles emission
|
||||
// Add Vue-specific options if not in base
|
||||
"allowJs": true, // If you have JS files too
|
||||
// Vite projects often use this for path aliases like @/
|
||||
// The base already has baseUrl: "."
|
||||
// Paths for @empresa/prisma-schema are inherited from tsconfig.base.json
|
||||
"paths": {
|
||||
"@/*": ["src/*"] // Local alias for UI project
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }] // Common for Vite projects
|
||||
}
|
||||
12
ui/tsconfig.node.json
Normal file
12
ui/tsconfig.node.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"target": "esnext",
|
||||
// Specific overrides for Node context if needed
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.js"] // Or .ts if you use TypeScript for Vite config
|
||||
}
|
||||
14
worker/jsconfig.json
Normal file
14
worker/jsconfig.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"checkJs": false,
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "node",
|
||||
"target": "esnext", // Or appropriate target for your Node.js version
|
||||
"module": "esnext", // Since package.json has "type": "module"
|
||||
// Paths are inherited from tsconfig.base.json
|
||||
"baseUrl": "." // baseUrl is still needed if there are other local paths
|
||||
},
|
||||
"include": ["**/*.js"],
|
||||
"exclude": ["node_modules", "prisma"] // Excluding worker/prisma as it's not used anymore
|
||||
}
|
||||
@@ -7,10 +7,9 @@
|
||||
"start": "node server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "^6.7.0",
|
||||
"@empresa/prisma-schema": "1.0.0",
|
||||
"express": "^4.18.2",
|
||||
"node-cron": "^4.0.5",
|
||||
"pg": "^8.8.0",
|
||||
"prisma": "^6.7.0"
|
||||
"pg": "^8.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
// This is your Prisma schema file,
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
|
||||
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
output = "../generated/prisma"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
@@ -17,33 +17,31 @@ const EXTERNAL_DB_NAME = process.env.EXTERNAL_DB_NAME || 'YOUR_EXTERNAL_DB_NAME'
|
||||
const EXTERNAL_DB_EMPLEADOS_TABLE = process.env.EXTERNAL_DB_EMPLEADOS_TABLE || 'empleados_externos'; // User must set this.
|
||||
// --- End of External Database Configuration ---
|
||||
|
||||
import { PrismaClient } from '../api/prisma/generated/client';
|
||||
const prisma = new PrismaClient();
|
||||
// Import types from the shared Prisma package.
|
||||
// We are not importing PrismaClient here as the worker will fetch data from the API.
|
||||
import type { Cliente } from '@empresa/prisma-schema'; // Assuming Cliente is the relevant type for employees
|
||||
|
||||
// Define a type for the employee data we expect from the API.
|
||||
// This might be identical to Cliente or a subset, depending on the API endpoint.
|
||||
type EmployeeDataFromAPI = Pick<Cliente, 'id' | 'name' | 'cedula' | 'ubicacion' | 'telefono'>;
|
||||
|
||||
async function syncEmpleadosToExternalDB() {
|
||||
console.log('[SyncEmpleados] Starting synchronization process...');
|
||||
// Core logic for synchronization, wrapped in try/catch/finally to ensure
|
||||
// resources like the Prisma client are properly managed (e.g., disconnected).
|
||||
try {
|
||||
// Fetch all 'Cliente' records from the local Prisma database that are marked as 'empleado'.
|
||||
const localEmpleados = await prisma.cliente.findMany({
|
||||
where: { empleado: true }, // Filters for clients who are also employees
|
||||
select: {
|
||||
id: true, // Local ID, might be useful for logging/tracing
|
||||
name: true,
|
||||
cedula: true,
|
||||
ubicacion: true,
|
||||
telefono: true,
|
||||
// avatar_url: true, // Add other relevant fields
|
||||
// idciat: true, // Add other relevant fields
|
||||
},
|
||||
});
|
||||
// TODO: Fetch employee data from the API (e.g., GET /api/empleados)
|
||||
// This is a placeholder for the API call logic.
|
||||
console.log('[SyncEmpleados] Fetching employee data from API...');
|
||||
const response = await fetch('http://localhost:4000/api/empleados'); // Replace with your actual API endpoint
|
||||
if (!response.ok) {
|
||||
throw new Error(`API request failed with status ${response.status}`);
|
||||
}
|
||||
const localEmpleados: EmployeeDataFromAPI[] = await response.json();
|
||||
|
||||
if (!localEmpleados.length) {
|
||||
console.log('[SyncEmpleados] No employees found in local database. Nothing to sync.');
|
||||
if (!localEmpleados || !localEmpleados.length) {
|
||||
console.log('[SyncEmpleados] No employees found from API. Nothing to sync.');
|
||||
return;
|
||||
}
|
||||
console.log(`[SyncEmpleados] Found ${localEmpleados.length} employees to sync.`);
|
||||
console.log(`[SyncEmpleados] Found ${localEmpleados.length} employees from API to sync.`);
|
||||
|
||||
// --- External DB Connection Logic (User to implement based on EXTERNAL_DB_TYPE) ---
|
||||
// User must implement the actual database connection logic here based on EXTERNAL_DB_TYPE
|
||||
@@ -119,9 +117,7 @@ async function syncEmpleadosToExternalDB() {
|
||||
// Catch any errors that occur during the synchronization process.
|
||||
console.error('[SyncEmpleados] Error during synchronization:', error);
|
||||
} finally {
|
||||
// Ensure the Prisma client is always disconnected, even if an error occurs.
|
||||
await prisma.$disconnect();
|
||||
console.log('[SyncEmpleados] Prisma client disconnected.');
|
||||
// No Prisma client to disconnect as we are using API.
|
||||
}
|
||||
console.log('[SyncEmpleados] Synchronization process finished.');
|
||||
}
|
||||
@@ -136,19 +132,17 @@ export { syncEmpleadosToExternalDB };
|
||||
// 2. **Manual Testing:**
|
||||
// * Once configured, you can test the script by running it directly: `node worker/sync-empleados.js`
|
||||
// * Observe the console logs for any errors or successful completion messages.
|
||||
// * Verify that data from your local 'Cliente' table (where empleado=true) appears correctly
|
||||
// in your designated external database table (`EXTERNAL_DB_EMPLEADOS_TABLE`).
|
||||
// * Check that subsequent runs correctly update existing records and insert new ones.
|
||||
// * The cron job in `worker/cron-worker.js` is scheduled to run this script daily at midnight.
|
||||
// * Verify that data fetched from the API appears correctly (or is logged as intended for now)
|
||||
// if you have implemented the external DB sync part.
|
||||
// * The cron job in `worker/cron-worker.js` is scheduled to run this script.
|
||||
// You can monitor logs after this time to see its execution.
|
||||
//
|
||||
// 3. **Automated Testing (Recommendations for future development):**
|
||||
// * **Unit Tests:**
|
||||
// - Mock the Prisma client (`../api/prisma/generated/client`) to return predefined employee data
|
||||
// and spy on its methods.
|
||||
// - Mock the API call (`fetch`) to return predefined employee data.
|
||||
// - Mock the external database client (e.g., `pg`, `mysql2`) to simulate connection,
|
||||
// query execution (select, insert, update), and disconnections. This allows testing
|
||||
// the sync logic without actual database dependencies.
|
||||
// the sync logic without actual API or database dependencies.
|
||||
// * **Integration Tests:**
|
||||
// - If possible, set up a dedicated test instance of your external database.
|
||||
// - Write tests that populate the local Prisma test database with sample employee data,
|
||||
|
||||
Reference in New Issue
Block a user