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.
164 lines
8.9 KiB
JavaScript
164 lines
8.9 KiB
JavaScript
// This script is responsible for synchronizing employee data from the local
|
|
// Prisma database to an external database. It is designed to be run as a scheduled task.
|
|
|
|
// --- External Database Configuration (PLACEHOLDERS - User MUST Configure via environment variables) ---
|
|
// IMPORTANT: These variables define the connection to your external database.
|
|
// You MUST configure these, ideally through environment variables, for the script to work.
|
|
// The script provides a template for different database types, but you'll need to:
|
|
// 1. Install the appropriate database client library (e.g., `npm install pg` or `npm install mysql2`).
|
|
// 2. Implement the actual database connection and query logic in the designated section.
|
|
|
|
const EXTERNAL_DB_TYPE = process.env.EXTERNAL_DB_TYPE || 'your_db_type_here'; // e.g., 'postgres', 'mysql'. User must set this.
|
|
const EXTERNAL_DB_HOST = process.env.EXTERNAL_DB_HOST || 'YOUR_EXTERNAL_DB_HOST'; // User must set this.
|
|
const EXTERNAL_DB_PORT = process.env.EXTERNAL_DB_PORT || 5432; // Adjust default port if needed. User must set this.
|
|
const EXTERNAL_DB_USER = process.env.EXTERNAL_DB_USER || 'YOUR_EXTERNAL_DB_USER'; // User must set this.
|
|
const EXTERNAL_DB_PASSWORD = process.env.EXTERNAL_DB_PASSWORD || 'YOUR_EXTERNAL_DB_PASSWORD'; // User must set this.
|
|
const EXTERNAL_DB_NAME = process.env.EXTERNAL_DB_NAME || 'YOUR_EXTERNAL_DB_NAME'; // User must set this.
|
|
const EXTERNAL_DB_EMPLEADOS_TABLE = process.env.EXTERNAL_DB_EMPLEADOS_TABLE || 'empleados_externos'; // User must set this.
|
|
// --- End of External Database Configuration ---
|
|
|
|
// 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...');
|
|
try {
|
|
// 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 || !localEmpleados.length) {
|
|
console.log('[SyncEmpleados] No employees found from API. Nothing to sync.');
|
|
return;
|
|
}
|
|
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
|
|
// and install the required database client library (e.g., 'pg' for PostgreSQL, 'mysql2' for MySQL).
|
|
// The following are conceptual examples.
|
|
|
|
// Example for PostgreSQL using 'pg' library (user would need to install it: npm install pg)
|
|
/*
|
|
if (EXTERNAL_DB_TYPE === 'postgres') {
|
|
// const { Client } = require('pg'); // User would uncomment and install
|
|
// const externalDbClient = new Client({
|
|
// host: EXTERNAL_DB_HOST,
|
|
// port: EXTERNAL_DB_PORT,
|
|
// user: EXTERNAL_DB_USER,
|
|
// password: EXTERNAL_DB_PASSWORD,
|
|
// database: EXTERNAL_DB_NAME,
|
|
// });
|
|
// await externalDbClient.connect();
|
|
// console.log('[SyncEmpleados] Connected to external PostgreSQL database.');
|
|
|
|
// ... (sync logic using externalDbClient) ...
|
|
|
|
// await externalDbClient.end();
|
|
// console.log('[SyncEmpleados] Disconnected from external PostgreSQL database.');
|
|
} else if (EXTERNAL_DB_TYPE === 'mysql') {
|
|
// const mysql = require('mysql2/promise'); // User would uncomment and install
|
|
// const connection = await mysql.createConnection({
|
|
// host: EXTERNAL_DB_HOST,
|
|
// user: EXTERNAL_DB_USER,
|
|
// password: EXTERNAL_DB_PASSWORD,
|
|
// database: EXTERNAL_DB_NAME,
|
|
// port: EXTERNAL_DB_PORT,
|
|
// });
|
|
// console.log('[SyncEmpleados] Connected to external MySQL database.');
|
|
|
|
// ... (sync logic using connection) ...
|
|
|
|
// await connection.end();
|
|
// console.log('[SyncEmpleados] Disconnected from external MySQL database.');
|
|
} else {
|
|
console.error(`[SyncEmpleados] Unsupported EXTERNAL_DB_TYPE: ${EXTERNAL_DB_TYPE}. User needs to implement connection logic.`);
|
|
// For now, we will just log the data that would be synced
|
|
}
|
|
*/
|
|
// --- End of External DB Connection Logic ---
|
|
|
|
console.log('[SyncEmpleados] --- Data to be Synced (Conceptual) ---');
|
|
for (const emp of localEmpleados) {
|
|
console.log(`[SyncEmpleados] Processing employee: ID=${emp.id}, Cedula=${emp.cedula}, Name=${emp.name}`);
|
|
|
|
// Conceptual Upsert Logic: The following section outlines where you would implement the upsert (update or insert) operation.
|
|
// You'll need to use your chosen external database client to first check if an employee
|
|
// with a matching unique identifier (e.g., emp.cedula) exists in the ${EXTERNAL_DB_EMPLEADOS_TABLE}.
|
|
// If it exists, execute an UPDATE statement. If not, execute an INSERT statement.
|
|
// Ensure you map fields from 'emp' (local employee) to the corresponding columns in your external table.
|
|
|
|
// Example of data to be inserted/updated:
|
|
const externalData = {
|
|
// Assuming external table has these columns. User must map accordingly.
|
|
// Ensure data types are compatible between local and external databases.
|
|
cedula: emp.cedula, // Primary key for matching in the external table (assumed)
|
|
nombre: emp.name,
|
|
telefono: emp.telefono,
|
|
ubicacion: emp.ubicacion,
|
|
// local_id: emp.id, // Optional: store local ID for reference
|
|
// ... map other fields ...
|
|
};
|
|
console.log(`[SyncEmpleados] Data for external table: ${JSON.stringify(externalData)}`);
|
|
}
|
|
console.log('[SyncEmpleados] --- End of Data to be Synced ---');
|
|
|
|
} catch (error) {
|
|
// Catch any errors that occur during the synchronization process.
|
|
console.error('[SyncEmpleados] Error during synchronization:', error);
|
|
} finally {
|
|
// No Prisma client to disconnect as we are using API.
|
|
}
|
|
console.log('[SyncEmpleados] Synchronization process finished.');
|
|
}
|
|
|
|
export { syncEmpleadosToExternalDB };
|
|
|
|
// --- Testing Considerations ---
|
|
// 1. **Configuration is Key:** This script requires the `EXTERNAL_DB_...` variables to be correctly
|
|
// configured with your actual external database credentials and details before any meaningful
|
|
// end-to-end testing can be performed.
|
|
//
|
|
// 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 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 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 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,
|
|
// run the sync script, and then query the external test database to assert that
|
|
// the data was synchronized correctly. This provides more comprehensive testing
|
|
// but requires more setup.
|
|
//
|
|
// 4. **Logging:** Pay close attention to the console output. The script includes logging for various
|
|
// stages, which will be crucial for diagnosing issues during testing and operation.
|
|
// --- End of Testing Considerations ---
|
|
|
|
// Optional: For direct execution of this script, e.g., `node worker/sync-empleados.js`
|
|
if (require.main === module) {
|
|
console.log('[SyncEmpleados] Running synchronization script directly.');
|
|
syncEmpleadosToExternalDB()
|
|
.then(() => console.log('[SyncEmpleados] Direct execution completed.'))
|
|
.catch(err => console.error('[SyncEmpleados] Direct execution failed:', err));
|
|
}
|