UNPKG

backend-mcp

Version:

Generador automático de backends con Node.js, Express, Prisma y módulos configurables. Servidor MCP compatible con npx para agentes IA. Soporta PostgreSQL, MySQL, MongoDB y SQLite.

579 lines (460 loc) 13.2 kB
# 📦 Módulo database **Versión:** 1.0.0 **Categoría:** infrastructure **Descripción:** Configuración y gestión de base de datos con Prisma ORM ## 📊 Estado del Módulo | Componente | Estado | |------------|--------| | Script de inicialización | ✅ Disponible | | Templates | ✅ Disponible | | Ejemplos | ❌ Faltante | ## 🔗 Dependencias ### Opcionales - `logging` - `monitoring` ## 🤖 Triggers para IA Este módulo se activa automáticamente cuando se detectan las siguientes palabras clave: - **needs_database**: true - **uses_prisma**: true - **requires_orm**: true - **mentions_database**: true ## ✨ Características - prisma-orm - connection-pooling - query-logging - health-checks - migrations - seeding - soft-deletes - audit-trails - transactions - database-statistics ## 📖 Documentación Completa # Database Module Database connection and ORM management module for MCP Backend framework. ## Features - ✅ Multi-database support (PostgreSQL, MySQL) - ✅ Prisma ORM integration - ✅ Connection pooling and management - ✅ Database migrations - ✅ Seed data management - ✅ Query optimization - ✅ Transaction support - ✅ Database backup and restore - ✅ Health monitoring - ✅ Performance metrics ## Installation This module is automatically installed when using the MCP Backend Generator. ## Configuration ### Environment Variables **PostgreSQL:** - `DATABASE_URL` (required) - PostgreSQL connection string - `POSTGRES_HOST` (optional) - Database host - `POSTGRES_PORT` (optional) - Database port (default: 5432) - `POSTGRES_DB` (optional) - Database name - `POSTGRES_USER` (optional) - Database user - `POSTGRES_PASSWORD` (optional) - Database password **MySQL:** - `DATABASE_URL` (required) - MySQL connection string - `MYSQL_HOST` (optional) - Database host - `MYSQL_PORT` (optional) - Database port (default: 3306) - `MYSQL_DATABASE` (optional) - Database name - `MYSQL_USER` (optional) - Database user - `MYSQL_PASSWORD` (optional) - Database password **General:** - `DB_POOL_SIZE` (optional) - Connection pool size (default: 10) - `DB_TIMEOUT` (optional) - Query timeout in ms (default: 30000) - `DB_SSL` (optional) - Enable SSL connection (default: false) - `DB_LOGGING` (optional) - Enable query logging (default: false) ### Configuration File ```typescript // src/config/database.ts export const databaseConfig = { url: process.env.DATABASE_URL, poolSize: parseInt(process.env.DB_POOL_SIZE || '10'), timeout: parseInt(process.env.DB_TIMEOUT || '30000'), ssl: process.env.DB_SSL === 'true', logging: process.env.DB_LOGGING === 'true', retryAttempts: 3, retryDelay: 1000 }; ``` ## Usage ### Database Connection ```typescript import { databaseService } from './services/database'; // Initialize connection await databaseService.connect(); // Get Prisma client const prisma = databaseService.getClient(); // Use Prisma client const users = await prisma.user.findMany(); // Close connection await databaseService.disconnect(); ``` ### Prisma Client Usage ```typescript import { prisma } from './database/client'; // Create const user = await prisma.user.create({ data: { name: 'John Doe', email: 'john@example.com' } }); // Read const users = await prisma.user.findMany({ where: { email: { contains: '@example.com' } }, include: { posts: true } }); // Update const updatedUser = await prisma.user.update({ where: { id: 'user_id' }, data: { name: 'Jane Doe' } }); // Delete await prisma.user.delete({ where: { id: 'user_id' } }); ``` ### Transactions ```typescript import { prisma } from './database/client'; // Interactive transactions const result = await prisma.$transaction(async (tx) => { const user = await tx.user.create({ data: { name: 'John', email: 'john@example.com' } }); const profile = await tx.profile.create({ data: { userId: user.id, bio: 'Hello world' } }); return { user, profile }; }); // Sequential operations const [userCount, postCount] = await prisma.$transaction([ prisma.user.count(), prisma.post.count() ]); ``` ### Raw Queries ```typescript import { prisma } from './database/client'; // Raw query const result = await prisma.$queryRaw` SELECT u.name, COUNT(p.id) as post_count FROM users u LEFT JOIN posts p ON u.id = p.author_id GROUP BY u.id, u.name `; // Execute raw SQL await prisma.$executeRaw` UPDATE users SET last_login = NOW() WHERE id = ${userId} `; ``` ## Database Schema ### PostgreSQL Schema ```sql -- Users table CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), email VARCHAR(255) UNIQUE NOT NULL, name VARCHAR(255) NOT NULL, password_hash VARCHAR(255), role VARCHAR(50) DEFAULT 'user', email_verified BOOLEAN DEFAULT false, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Categories table CREATE TABLE categories ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(255) NOT NULL, description TEXT, parent_id UUID REFERENCES categories(id), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Products table CREATE TABLE products ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(255) NOT NULL, description TEXT, price DECIMAL(10,2) NOT NULL, stock_quantity INTEGER DEFAULT 0, category_id UUID REFERENCES categories(id), created_by UUID REFERENCES users(id), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Inventory movements table CREATE TABLE inventory_movements ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), product_id UUID REFERENCES products(id), movement_type VARCHAR(20) NOT NULL CHECK (movement_type IN ('in', 'out', 'adjustment')), quantity INTEGER NOT NULL, reference_id UUID, notes TEXT, created_by UUID REFERENCES users(id), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` ### Prisma Schema ```prisma // prisma/schema.prisma generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model User { id String @id @default(cuid()) email String @unique name String passwordHash String? @map("password_hash") role String @default("user") emailVerified Boolean @default(false) @map("email_verified") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // Relations createdProducts Product[] @relation("ProductCreator") inventoryMovements InventoryMovement[] @relation("MovementCreator") @@map("users") } model Category { id String @id @default(cuid()) name String description String? parentId String? @map("parent_id") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // Relations parent Category? @relation("CategoryHierarchy", fields: [parentId], references: [id]) children Category[] @relation("CategoryHierarchy") products Product[] @@map("categories") } model Product { id String @id @default(cuid()) name String description String? price Decimal @db.Decimal(10, 2) stockQuantity Int @default(0) @map("stock_quantity") categoryId String? @map("category_id") createdBy String @map("created_by") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // Relations category Category? @relation(fields: [categoryId], references: [id]) creator User @relation("ProductCreator", fields: [createdBy], references: [id]) inventoryMovements InventoryMovement[] @@map("products") } model InventoryMovement { id String @id @default(cuid()) productId String @map("product_id") movementType String @map("movement_type") quantity Int referenceId String? @map("reference_id") notes String? createdBy String @map("created_by") createdAt DateTime @default(now()) @map("created_at") // Relations product Product @relation(fields: [productId], references: [id]) creator User @relation("MovementCreator", fields: [createdBy], references: [id]) @@map("inventory_movements") } ``` ## Migrations ### Running Migrations ```bash # Generate migration npx prisma migrate dev --name init # Apply migrations npx prisma migrate deploy # Reset database npx prisma migrate reset # Generate Prisma client npx prisma generate ``` ### Migration Scripts ```typescript // scripts/database/migrate.ts import { execSync } from 'child_process'; async function runMigrations() { try { console.log('🔄 Running database migrations...'); execSync('npx prisma migrate deploy', { stdio: 'inherit' }); console.log('✅ Migrations completed successfully'); } catch (error) { console.error('❌ Migration failed:', error); process.exit(1); } } runMigrations(); ``` ## Seeding ### Seed Script ```typescript // prisma/seeds/seed.ts import { PrismaClient } from '@prisma/client'; import bcrypt from 'bcrypt'; const prisma = new PrismaClient(); async function main() { console.log('🌱 Seeding database...'); // Create admin user const adminUser = await prisma.user.upsert({ where: { email: 'admin@example.com' }, update: {}, create: { email: 'admin@example.com', name: 'Admin User', passwordHash: await bcrypt.hash('admin123', 12), role: 'admin', emailVerified: true } }); // Create categories const electronics = await prisma.category.upsert({ where: { id: 'electronics' }, update: {}, create: { id: 'electronics', name: 'Electronics', description: 'Electronic devices and accessories' } }); // Create products await prisma.product.createMany({ data: [ { name: 'Laptop', description: 'High-performance laptop', price: 999.99, stockQuantity: 10, categoryId: electronics.id, createdBy: adminUser.id }, { name: 'Mouse', description: 'Wireless mouse', price: 29.99, stockQuantity: 50, categoryId: electronics.id, createdBy: adminUser.id } ] }); console.log('✅ Database seeded successfully'); } main() .catch((e) => { console.error('❌ Seeding failed:', e); process.exit(1); }) .finally(async () => { await prisma.$disconnect(); }); ``` ### Running Seeds ```bash npm run db:seed ``` ## Backup and Restore ### Backup Script ```bash #!/bin/bash # scripts/database/backup.sh DATE=$(date +"%Y%m%d_%H%M%S") BACKUP_FILE="backup_${DATE}.sql" echo "📦 Creating database backup..." pg_dump $DATABASE_URL > "backups/${BACKUP_FILE}" echo "✅ Backup created: ${BACKUP_FILE}" ``` ### Restore Script ```bash #!/bin/bash # scripts/database/restore.sh BACKUP_FILE=$1 if [ -z "$BACKUP_FILE" ]; then echo "❌ Please provide backup file path" exit 1 fi echo "🔄 Restoring database from ${BACKUP_FILE}..." psql $DATABASE_URL < "$BACKUP_FILE" echo "✅ Database restored successfully" ``` ## Health Monitoring ```typescript // src/utils/database/health.ts import { prisma } from '../client'; export async function checkDatabaseHealth() { try { await prisma.$queryRaw`SELECT 1`; return { status: 'healthy', timestamp: new Date().toISOString() }; } catch (error) { return { status: 'unhealthy', error: error.message, timestamp: new Date().toISOString() }; } } export async function getDatabaseMetrics() { const [userCount, productCount, categoryCount] = await Promise.all([ prisma.user.count(), prisma.product.count(), prisma.category.count() ]); return { users: userCount, products: productCount, categories: categoryCount, timestamp: new Date().toISOString() }; } ``` ## Testing ```bash npm test -- database ``` ## Dependencies - @prisma/client - prisma - pg (PostgreSQL) - mysql2 (MySQL) - logging ## Integration - Integrates with all modules requiring database access - Provides connection management for the entire application - Supports multiple database providers ## Performance Optimization - **Connection Pooling**: Configured connection pool for optimal performance - **Query Optimization**: Use indexes and optimize queries - **Caching**: Implement query result caching where appropriate - **Monitoring**: Track query performance and slow queries - **Pagination**: Always paginate large result sets ## Error Handling - `DatabaseConnectionError`: Connection failed - `QueryTimeoutError`: Query exceeded timeout - `TransactionError`: Transaction failed - `MigrationError`: Migration failed - `SeedError`: Seeding failed ## License MIT ## 🔗 Enlaces - [Volver al índice de módulos](./README.md) - [Documentación principal](../README.md) - [Código fuente](../../modules/database/)