Guías Avanzadas

Tutoriales detallados para usuarios experimentados

Guías Avanzadas

Explora funcionalidades avanzadas y técnicas para aprovechar al máximo nuestra plataforma.

Configuración de Entornos

Entornos de Desarrollo vs Producción

Configura diferentes entornos para diferentes etapas de tu proyecto.

Configuración de Desarrollo

// config/development.js
module.exports = {
  apiUrl: "https://api-dev.tuapp.com",
  debug: true,
  logLevel: "verbose",
  cache: {
    ttl: 60, // 1 minuto para desarrollo rápido
  },
};

Configuración de Producción

// config/production.js
module.exports = {
  apiUrl: "https://api.tuapp.com",
  debug: false,
  logLevel: "error",
  cache: {
    ttl: 3600, // 1 hora para producción
  },
};

Variables de Entorno

Usa variables de entorno para configuraciones sensibles:

# .env
DATABASE_URL=postgresql://user:pass@localhost:5432/myapp
JWT_SECRET=tu-secreto-super-seguro
WEBHOOK_SECRET=webhook-secret-key
API_KEY=tu-api-key

Automatización Avanzada

Flujos de Trabajo Complejos

Crea automatizaciones sofisticadas con múltiples condiciones.

Flujo de Aprobación Multinivel

# workflow.yml
name: "Aprobación Multinivel"
trigger:
  event: "documento.enviado"

steps:
  - name: "Validación Inicial"
    type: "condition"
    condition: "documento.size < 50MB AND documento.type IN ['pdf', 'docx']"

  - name: "Aprobación Supervisor"
    type: "approval"
    approver: "supervisor"
    timeout: "2d"

  - name: "Aprobación Director"
    type: "approval"
    condition: "documento.amount > 10000"
    approver: "director"
    timeout: "5d"

  - name: "Notificar Resultado"
    type: "notification"
    template: "aprobacion_resultado"

Scripts Personalizados

Ejecuta lógica personalizada en tus automatizaciones:

// scripts/custom-validation.js
function validateDocument(document) {
  // Validaciones personalizadas
  const errors = [];

  if (!document.title || document.title.length < 10) {
    errors.push("El título debe tener al menos 10 caracteres");
  }

  if (!document.tags || document.tags.length === 0) {
    errors.push("El documento debe tener al menos una etiqueta");
  }

  // Validación de contenido usando AI
  if (containsInappropriateContent(document.content)) {
    errors.push("El contenido no cumple con las políticas");
  }

  return {
    valid: errors.length === 0,
    errors: errors,
  };
}

function containsInappropriateContent(content) {
  // Implementa tu lógica de validación
  // Puedes usar APIs de moderación de contenido
  return false;
}

module.exports = { validateDocument };

Optimización de Rendimiento

Caché Inteligente

Implementa estrategias de caché para mejorar el rendimiento:

// cache-strategy.js
class CacheStrategy {
  constructor() {
    this.cache = new Map();
    this.ttl = new Map();
  }

  set(key, value, ttlMs = 3600000) {
    // 1 hora por defecto
    this.cache.set(key, value);
    this.ttl.set(key, Date.now() + ttlMs);

    // Limpieza automática
    setTimeout(() => this.delete(key), ttlMs);
  }

  get(key) {
    if (this.isExpired(key)) {
      this.delete(key);
      return null;
    }
    return this.cache.get(key);
  }

  isExpired(key) {
    const expiry = this.ttl.get(key);
    return expiry && Date.now() > expiry;
  }

  delete(key) {
    this.cache.delete(key);
    this.ttl.delete(key);
  }
}

// Uso
const cache = new CacheStrategy();
cache.set("user:123", userData, 1800000); // 30 minutos

Consultas Optimizadas

Optimiza tus consultas a la API:

// api-optimizer.js
class ApiOptimizer {
  constructor() {
    this.batchSize = 100;
    this.queue = [];
    this.processing = false;
  }

  // Batch multiple requests
  async batchRequest(requests) {
    return new Promise((resolve) => {
      this.queue.push({ requests, resolve });
      this.processBatch();
    });
  }

  async processBatch() {
    if (this.processing || this.queue.length === 0) return;

    this.processing = true;
    const batch = this.queue.splice(0, this.batchSize);

    try {
      const results = await this.executeBatch(batch);
      batch.forEach((item, index) => {
        item.resolve(results[index]);
      });
    } finally {
      this.processing = false;
      if (this.queue.length > 0) {
        setTimeout(() => this.processBatch(), 100);
      }
    }
  }

  async executeBatch(batch) {
    // Ejecuta múltiples requests en paralelo
    const allRequests = batch.flatMap((item) => item.requests);
    return Promise.all(allRequests.map((req) => this.makeRequest(req)));
  }
}

Seguridad Avanzada

Autenticación JWT Personalizada

// auth-middleware.js
const jwt = require("jsonwebtoken");

class AuthMiddleware {
  constructor(secretKey) {
    this.secretKey = secretKey;
  }

  generateToken(user, permissions = []) {
    const payload = {
      userId: user.id,
      email: user.email,
      permissions: permissions,
      iat: Math.floor(Date.now() / 1000),
      exp: Math.floor(Date.now() / 1000) + 24 * 60 * 60, // 24 horas
    };

    return jwt.sign(payload, this.secretKey);
  }

  verifyToken(token) {
    try {
      return jwt.verify(token, this.secretKey);
    } catch (error) {
      throw new Error("Token inválido");
    }
  }

  hasPermission(token, requiredPermission) {
    const decoded = this.verifyToken(token);
    return decoded.permissions.includes(requiredPermission);
  }
}

Validación de Datos Avanzada

// validator.js
class DataValidator {
  static schemas = {
    user: {
      email: { type: "email", required: true },
      password: { type: "string", minLength: 8, required: true },
      age: { type: "number", min: 18, max: 120 },
    },

    project: {
      name: { type: "string", minLength: 3, maxLength: 100, required: true },
      description: { type: "string", maxLength: 1000 },
      budget: { type: "number", min: 0 },
      deadline: { type: "date", future: true },
    },
  };

  static validate(data, schemaName) {
    const schema = this.schemas[schemaName];
    if (!schema) throw new Error(`Schema ${schemaName} no encontrado`);

    const errors = [];

    for (const [field, rules] of Object.entries(schema)) {
      const value = data[field];

      // Campo requerido
      if (rules.required && (value === undefined || value === null)) {
        errors.push(`${field} es requerido`);
        continue;
      }

      if (value !== undefined && value !== null) {
        errors.push(...this.validateField(field, value, rules));
      }
    }

    return {
      valid: errors.length === 0,
      errors: errors,
    };
  }

  static validateField(field, value, rules) {
    const errors = [];

    // Validar tipo
    if (rules.type && !this.validateType(value, rules.type)) {
      errors.push(`${field} debe ser de tipo ${rules.type}`);
    }

    // Validar longitud mínima
    if (rules.minLength && value.length < rules.minLength) {
      errors.push(`${field} debe tener al menos ${rules.minLength} caracteres`);
    }

    // Validar longitud máxima
    if (rules.maxLength && value.length > rules.maxLength) {
      errors.push(
        `${field} no puede tener más de ${rules.maxLength} caracteres`
      );
    }

    // Validar valor mínimo
    if (rules.min && value < rules.min) {
      errors.push(`${field} debe ser mayor o igual a ${rules.min}`);
    }

    // Validar valor máximo
    if (rules.max && value > rules.max) {
      errors.push(`${field} debe ser menor o igual a ${rules.max}`);
    }

    // Validar fecha futura
    if (rules.future && new Date(value) <= new Date()) {
      errors.push(`${field} debe ser una fecha futura`);
    }

    return errors;
  }

  static validateType(value, type) {
    switch (type) {
      case "email":
        return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
      case "string":
        return typeof value === "string";
      case "number":
        return typeof value === "number" && !isNaN(value);
      case "date":
        return !isNaN(Date.parse(value));
      default:
        return true;
    }
  }
}

Monitoreo y Análisis

Métricas Personalizadas

// metrics-collector.js
class MetricsCollector {
  constructor() {
    this.metrics = new Map();
    this.timers = new Map();
  }

  // Incrementar contador
  increment(metric, tags = {}) {
    const key = this.buildKey(metric, tags);
    const current = this.metrics.get(key) || 0;
    this.metrics.set(key, current + 1);
  }

  // Medir tiempo
  startTimer(operation) {
    const id = Date.now() + Math.random();
    this.timers.set(id, Date.now());
    return id;
  }

  endTimer(id, metric, tags = {}) {
    const startTime = this.timers.get(id);
    if (startTime) {
      const duration = Date.now() - startTime;
      this.recordDuration(metric, duration, tags);
      this.timers.delete(id);
    }
  }

  recordDuration(metric, duration, tags = {}) {
    const key = this.buildKey(metric, tags);
    const current = this.metrics.get(key) || [];
    current.push(duration);
    this.metrics.set(key, current);
  }

  buildKey(metric, tags) {
    const tagString = Object.entries(tags)
      .sort()
      .map(([k, v]) => `${k}:${v}`)
      .join(",");
    return `${metric}${tagString ? "|" + tagString : ""}`;
  }

  // Exportar métricas
  export() {
    const result = {};
    for (const [key, value] of this.metrics.entries()) {
      result[key] = Array.isArray(value)
        ? {
            count: value.length,
            avg: value.reduce((a, b) => a + b, 0) / value.length,
            min: Math.min(...value),
            max: Math.max(...value),
          }
        : value;
    }
    return result;
  }
}

// Uso
const metrics = new MetricsCollector();

// En tu aplicación
metrics.increment("api.requests", { endpoint: "/users", method: "GET" });

const timerId = metrics.startTimer("database.query");
// ... ejecutar consulta ...
metrics.endTimer(timerId, "database.query", { table: "users" });

Consejos de Arquitectura

Patrón Repository

// repositories/base-repository.js
class BaseRepository {
  constructor(model) {
    this.model = model;
  }

  async findById(id) {
    return this.model.findByPk(id);
  }

  async findAll(options = {}) {
    return this.model.findAll(options);
  }

  async create(data) {
    return this.model.create(data);
  }

  async update(id, data) {
    const instance = await this.findById(id);
    if (!instance) throw new Error("Registro no encontrado");
    return instance.update(data);
  }

  async delete(id) {
    const instance = await this.findById(id);
    if (!instance) throw new Error("Registro no encontrado");
    return instance.destroy();
  }
}

// repositories/user-repository.js
class UserRepository extends BaseRepository {
  constructor(User) {
    super(User);
  }

  async findByEmail(email) {
    return this.model.findOne({ where: { email } });
  }

  async findActiveUsers() {
    return this.model.findAll({
      where: { status: "active" },
      order: [["createdAt", "DESC"]],
    });
  }
}

Última actualización: Diciembre 2024