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
Markdown
# 📦 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/)