@skailan/tenant-manager
v1.0.0
Published
Gestión optimizada de multitenancy para Skailan
Maintainers
Readme
@skailan/tenant-manager
Gestión optimizada de multitenancy para Skailan. Esta librería proporciona una solución robusta para manejar múltiples tenants en aplicaciones Node.js con Express.
🚀 Instalación
npm install @skailan/tenant-manager📖 Uso Básico
Configuración Inicial
import { TenantManager, createTenantResolver } from "@skailan/tenant-manager";
const tenantManager = new TenantManager({
database: {
type: "postgresql",
host: "localhost",
port: 5432,
username: "postgres",
password: "password",
database: "skailan",
},
cache: {
type: "redis",
host: "localhost",
port: 6379,
ttl: 300000, // 5 minutos
},
isolation: "database-per-tenant",
autoScaling: true,
});Middleware Express
import express from "express";
import { createTenantResolver } from "@skailan/tenant-manager";
const app = express();
// Crear middleware de resolución de tenants
const tenantResolver = createTenantResolver(tenantManager);
// Usar middleware
app.use(tenantResolver);
// Ahora todas las requests tienen acceso a req.tenant
app.get("/api/data", (req, res) => {
console.log("Tenant ID:", req.tenant?.id);
console.log("Tenant Name:", req.tenant?.name);
res.json({
tenant: req.tenant,
data: "Your data here",
});
});Uso Manual
import { TenantManager } from "@skailan/tenant-manager";
const tenantManager = new TenantManager(config);
// Resolver tenant manualmente
const tenant = await tenantManager.resolveTenant("empresa1.skailan.com");
console.log(tenant.id); // 'empresa1'
console.log(tenant.name); // 'Empresa1'
// Obtener base de datos del tenant
const db = await tenantManager.getTenantDatabase(tenant.id);🔧 Configuración
Opciones de Base de Datos
{
database: {
type: 'postgresql' | 'mysql',
host: string,
port: number,
username: string,
password: string,
database: string,
ssl?: boolean
}
}Opciones de Cache
{
cache: {
type: 'redis' | 'memory',
host?: string, // Solo para Redis
port?: number, // Solo para Redis
password?: string, // Solo para Redis
ttl?: number // Tiempo de vida en ms
}
}Opciones de Aislamiento
database-per-tenant: Cada tenant tiene su propia base de datosschema-per-tenant: Cada tenant usa un schema diferente en la misma base de datos
🛠️ API
TenantManager
resolveTenant(host: string): Promise<Tenant>
Resuelve un tenant basado en el hostname.
getTenantDatabase(tenantId: string): Promise<PrismaClient>
Obtiene la conexión de base de datos para un tenant específico.
createTenant(tenantData: Partial<Tenant>): Promise<Tenant>
Crea un nuevo tenant.
invalidateTenantCache(host: string): Promise<void>
Invalida el cache para un host específico.
getStats(): Promise<Stats>
Obtiene estadísticas del cache y conexiones.
Middlewares
createTenantResolver(tenantManager: TenantManager)
Crea un middleware Express que resuelve automáticamente el tenant.
requireTenant(req: Request, res: Response, next: NextFunction)
Middleware que requiere que exista un tenant en la request.
getTenantDatabase(tenantManager: TenantManager)
Middleware que obtiene la base de datos del tenant.
📊 Ejemplos de Uso
Ejemplo Completo
import express from "express";
import {
TenantManager,
createTenantResolver,
requireTenant,
getTenantDatabase,
} from "@skailan/tenant-manager";
const app = express();
// Configurar TenantManager
const tenantManager = new TenantManager({
database: {
type: "postgresql",
host: process.env.DB_HOST || "localhost",
port: parseInt(process.env.DB_PORT || "5432"),
username: process.env.DB_USER || "postgres",
password: process.env.DB_PASSWORD || "",
database: process.env.DB_NAME || "skailan",
},
cache: {
type: "redis",
host: process.env.REDIS_HOST || "localhost",
port: parseInt(process.env.REDIS_PORT || "6379"),
ttl: 300000,
},
isolation: "database-per-tenant",
autoScaling: true,
});
// Middlewares
app.use(express.json());
app.use(createTenantResolver(tenantManager));
// Rutas que requieren tenant
app.get("/api/contacts", requireTenant, async (req, res) => {
const db = await tenantManager.getTenantDatabase(req.tenant!.id);
const contacts = await db.contact.findMany({
where: { tenantId: req.tenant!.id },
});
res.json(contacts);
});
// Ruta con middleware de base de datos
app.get(
"/api/users",
requireTenant,
getTenantDatabase(tenantManager),
async (req, res) => {
const users = await req.tenantDatabase!.user.findMany();
res.json(users);
}
);
app.listen(3000, () => {
console.log("🚀 Server running on port 3000");
});Ejemplo con Configuración por Defecto
import { createTenantManager } from "@skailan/tenant-manager";
// Usar configuración por defecto
const tenantManager = createTenantManager();
// O personalizar solo algunas opciones
const tenantManager = createTenantManager({
database: {
host: "my-db-host.com",
password: "my-password",
},
cache: {
type: "redis",
host: "my-redis-host.com",
},
});🧪 Testing
# Ejecutar tests
npm test
# Ejecutar tests en modo watch
npm run test:watch
# Ver coverage
npm test -- --coverage📈 Performance
- Cache Hit Rate: > 95% con Redis
- Latencia de Resolución: < 10ms con cache
- Conexiones de BD: Pooling automático por tenant
- Memory Usage: Optimizado con lazy loading
🔒 Seguridad
- Aislamiento completo entre tenants
- Validación de hostnames
- Timeout en conexiones de base de datos
- Rate limiting por tenant (configurable)
🤝 Contribuir
- Fork el proyecto
- Crear una rama para tu feature (
git checkout -b feature/amazing-feature) - Commit tus cambios (
git commit -m 'Add amazing feature') - Push a la rama (
git push origin feature/amazing-feature) - Abrir un Pull Request
📄 Licencia
MIT License - ver LICENSE para detalles.
🆘 Soporte
Para soporte técnico, contacta al equipo de Skailan o abre un issue en el repositorio.
