Saltar al contenido principal

Introducción

Construir aplicaciones de nivel empresarial con Next.js requiere una cuidadosa consideración de la arquitectura, el rendimiento, la seguridad y la mantenibilidad. Esta guía proporciona una visión general completa de las mejores prácticas para desarrollar aplicaciones Next.js robustas que puedan escalar para satisfacer las demandas empresariales.

1. Arquitectura y Escalabilidad

Arquitectura Modular

Organiza tu aplicación Next.js utilizando una arquitectura modular para mejorar la mantenibilidad y la escalabilidad:
/src
  /app                 # App Router pages and layouts
  /components          # Reusable UI components
    /ui                # Base UI components
    /features          # Feature-specific components
  /lib                 # Utility functions and shared code
  /hooks               # Custom React hooks
  /services            # External service integrations
  /types               # TypeScript type definitions
  /styles              # Global styles and theme configuration
  /middleware          # Next.js middleware

División de Código (Code Splitting) y Carga Diferida (Lazy Loading)

Next.js divide automáticamente el código por ruta, pero puedes optimizar aún más con importaciones dinámicas:
// Dynamic import with loading state
import dynamic from 'next/dynamic';

const DynamicDashboard = dynamic(() => import('@/components/Dashboard'), {
  loading: () => <p>Cargando panel...</p>, //<- Traducido
  ssr: false // Disable SSR if component relies on browser APIs
});

export default function Page() {
  return <DynamicDashboard />;
}

Obtención de Datos Eficiente

Aprovecha los React Server Components para una obtención de datos eficiente:
// app/products/page.tsx
import { ProductList } from '@/components/ProductList';
import { getProducts } from '@/lib/products';

export default async function ProductsPage() {
  // This runs on the server and doesn't send unnecessary data to the client
  const products = await getProducts();

  return <ProductList products={products} />;
}
Para la obtención de datos del lado del cliente, usa SWR o React Query:
'use client';

import { useQuery } from '@tanstack/react-query';

function ProductsClient() {
  const { data, isLoading, error } = useQuery({
    queryKey: ['products'],
    queryFn: () => fetch('/api/products').then(res => res.json())
  });

  if (isLoading) return <div>Cargando...</div>; //<- Traducido
  if (error) return <div>Error al cargar productos</div>; //<- Traducido

  return (
    <ul>
      {data.map(product => (
        <li key={product.id}>{product.name}</li>
      ))}
    </ul>
  );
}

Modelos de Despliegue

Despliegue Serverless

Los despliegues serverless (como Vercel) ofrecen escalado automático y reducen la carga operativa:
// next.config.js for optimized serverless deployment
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'standalone', // Creates a standalone build optimized for containerized environments
}

module.exports = nextConfig;

Despliegue Contenerizado

Para despliegues en Kubernetes o Docker, usa el modo de salida standalone:
# Dockerfile for Next.js
FROM node:18-alpine AS base

# Install dependencies only when needed
FROM base AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app

ENV NODE_ENV production

# Create a non-root user
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

# Copy standalone build
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public

USER nextjs

EXPOSE 3000

ENV PORT 3000

CMD ["node", "server.js"]

Estrategias de Base de Datos y Caché

Selección de Base de Datos

Elige la base de datos adecuada según tus necesidades:
  • PostgreSQL: Para datos relacionales complejos con cumplimiento ACID
  • MongoDB: Para esquemas flexibles y datos orientados a documentos
  • Redis: Para caché y funcionalidades en tiempo real
  • Supabase/Firebase: Para desarrollo rápido con autenticación incorporada

Implementación de Caché

Implementa caché multinivel:
// Route segment caching
export const revalidate = 3600; // Revalidate every hour

// Data cache with fetch
async function getProducts() {
  const res = await fetch('https://api.example.com/products', {
    next: { revalidate: 3600 } // Cache for 1 hour
  });

  return res.json();
}

// Request memoization
import { cache } from 'react';

export const getUser = cache(async (id: string) => {
  const user = await db.user.findUnique({ where: { id } });
  return user;
});

2. Optimización del Rendimiento

Optimización de Imágenes

Usa el componente Image de Next.js para optimización automática:
import Image from 'next/image';

export default function ProductImage({ product }) {
  return (
    <div className="relative h-64 w-full">
      <Image
        src={product.imageUrl || "/placeholder.svg"}
        alt={product.name}
        fill
        sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
        priority={product.featured}
        className="object-cover rounded-lg"
      />
    </div>
  );
}

Optimización de Fuentes

Optimiza las fuentes utilizando el sistema de fuentes incorporado de Next.js:
// app/layout.tsx
import { Inter, Roboto_Mono } from 'next/font/google';

const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-inter',
});

const robotoMono = Roboto_Mono({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-roboto-mono',
});

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    // Cambiado lang="en" a lang="es"
    <html lang="es" className={`${inter.variable} ${robotoMono.variable}`}>
      <body>{children}</body>
    </html>
  );
}

Estrategias de Renderizado

Elige la estrategia de renderizado adecuada según tu contenido:
// Static page with generated static params
export async function generateStaticParams() {
  const products = await getProducts();

  return products.map((product) => ({
    id: product.id,
  }));
}

// Dynamic page with ISR
export const revalidate = 60; // Revalidate at most once per minute

// Dynamic page with on-demand revalidation
// pages/api/revalidate.js
export default async function handler(req, res) {
  if (req.headers.authorization !== `Bearer ${process.env.REVALIDATION_TOKEN}`) {
    // Traducido
    return res.status(401).json({ message: 'Token inválido' });
  }

  try {
    await res.revalidate('/products');
    return res.json({ revalidated: true });
  } catch (err) {
    // Traducido
    return res.status(500).send('Error al revalidar');
  }
}

Monitorización del Rendimiento

Implementa la monitorización del rendimiento con herramientas como Web Vitals:
'use client';

import { useReportWebVitals } from 'next/web-vitals';

export function WebVitalsReporter() {
  useReportWebVitals(metric => {
    // Send to analytics
    console.log(metric);

    // Example: send to Google Analytics
    const analyticsId = 'UA-XXXXX-Y';
    const body = JSON.stringify({
      name: metric.name,
      value: metric.value,
      id: metric.id,
    });

    navigator.sendBeacon(`https://www.google-analytics.com/collect?v=1&t=event&ec=Web%20Vitals&ea=${metric.name}&el=${metric.id}&ev=${metric.value}&tid=${analyticsId}`, body);
  });

  return null;
}

3. Mejores Prácticas de Seguridad

Validación de Entradas

Valida siempre las entradas del usuario tanto en el cliente como en el servidor:
// Server-side validation in a Server Action
'use server';

import { z } from 'zod';

const FormSchema = z.object({
   // Traducido
  email: z.string().email('Dirección de correo inválida'),
   // Traducido
  password: z.string().min(8, 'La contraseña debe tener al menos 8 caracteres'),
});

export async function createUser(prevState: any, formData: FormData) {
  const validatedFields = FormSchema.safeParse({
    email: formData.get('email'),
    password: formData.get('password'),
  });

  if (!validatedFields.success) {
    return {
      errors: validatedFields.error.flatten().fieldErrors,
       // Traducido
      message: 'Campos faltantes. No se pudo crear el usuario.',
    };
  }

  // Proceed with creating user...
}

Seguridad de API

Asegura tus rutas de API con autenticación adecuada y limitación de tasa (rate limiting):
// app/api/protected/route.ts
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { NextResponse } from 'next/server';
import { rateLimit } from '@/lib/rate-limit';

export async function GET(request: Request) {
  const session = await getServerSession(authOptions);

  if (!session) {
     // Traducido
    return NextResponse.json({ error: 'No autorizado' }, { status: 401 });
  }

  // Apply rate limiting
  const limiter = rateLimit({
    interval: 60 * 1000, // 1 minute
    uniqueTokenPerInterval: 500,
  });

  try {
    await limiter.check(10, session.user.id); // 10 requests per minute per user
  } catch {
     // Traducido
    return NextResponse.json({ error: 'Límite de tasa excedido' }, { status: 429 });
  }

  // Process the request
   // Traducido
  return NextResponse.json({ data: 'Datos protegidos' });
}

Autenticación y Autorización

Implementa autenticación robusta con NextAuth.js:
// app/api/auth/[...nextauth]/route.ts
import NextAuth from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
import { compare } from 'bcrypt';
import { prisma } from '@/lib/prisma';

export const authOptions = {
  providers: [
    CredentialsProvider({
       // Traducido
      name: 'Credenciales',
      credentials: {
         // Traducido
        email: { label: 'Email', type: 'email' },
         // Traducido
        password: { label: 'Contraseña', type: 'password' }
      },
      async authorize(credentials) {
        if (!credentials?.email || !credentials?.password) {
          return null;
        }

        const user = await prisma.user.findUnique({
          where: { email: credentials.email }
        });

        if (!user) {
          return null;
        }

        const isPasswordValid = await compare(credentials.password, user.password);

        if (!isPasswordValid) {
          return null;
        }

        return {
          id: user.id,
          email: user.email,
          name: user.name,
          role: user.role,
        };
      }
    })
  ],
  callbacks: {
    async jwt({ token, user }) {
      if (user) {
        token.role = user.role;
      }
      return token;
    },
    async session({ session, token }) {
      session.user.role = token.role;
      return session;
    }
  },
  pages: {
    signIn: '/auth/signin',
    error: '/auth/error',
  },
  session: {
    strategy: 'jwt',
  },
};

const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };

Protección CSRF

Implementa protección CSRF (Cross-Site Request Forgery) para formularios:
'use client';

import { useState, useEffect } from 'react'; // Añadido useEffect que faltaba en original
import { getCsrfToken } from 'next-auth/react';

export default function ContactForm() {
  const [csrfToken, setCsrfToken] = useState('');

  // Añadido useEffect que faltaba en original
  useEffect(() => {
    async function fetchCsrfToken() {
      const token = await getCsrfToken();
      setCsrfToken(token || '');
    }
    fetchCsrfToken();
  }, []);

  return (
    <form method="post" action="/api/contact">
      <input name="csrfToken" type="hidden" value={csrfToken} />
      {/* Form fields */}
    </form>
  );
}

Política de Seguridad de Contenido (CSP)

Implementa una Política de Seguridad de Contenido estricta a través de middleware:
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const response = NextResponse.next();

  // Add security headers
  response.headers.set('Content-Security-Policy',
    "default-src 'self'; " +
    "script-src 'self' 'unsafe-inline' https://analytics.example.com; " +
    "style-src 'self' 'unsafe-inline'; " +
    "img-src 'self' data: https://images.example.com; " +
    "font-src 'self'; " +
    "connect-src 'self' https://api.example.com; " +
    "frame-src 'none'; " +
    "object-src 'none';"
  );

  response.headers.set('X-XSS-Protection', '1; mode=block');
  response.headers.set('X-Frame-Options', 'DENY');
  response.headers.set('X-Content-Type-Options', 'nosniff');
  response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
  response.headers.set('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');

  return response;
}

export const config = {
  matcher: '/((?!api/auth|_next/static|_next/image|favicon.ico).*)',
};

4. Calidad del Código y Mantenibilidad

Integración con TypeScript

Usa TypeScript para seguridad de tipos y una mejor experiencia de desarrollo:
// types/index.ts
export interface User {
  id: string;
  name: string;
  email: string;
   // Traducido 'admin' | 'user' a 'admin' | 'usuario' - CORRECCIÓN: Mantener original
  role: 'admin' | 'user';
  createdAt: Date;
}

export interface Product {
  id: string;
  name: string;
  description: string;
  price: number;
  imageUrl: string;
  category: string;
  featured: boolean;
}

Linting y Formateo

Configura ESLint y Prettier para un estilo de código consistente:
// .eslintrc.json
{
  "extends": [
    "next/core-web-vitals",
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "prettier"
  ],
  "plugins": ["@typescript-eslint"],
  "rules": {
    "no-unused-vars": "off",
    "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
    "react/no-unescaped-entities": "off",
    "@typescript-eslint/no-explicit-any": "warn",
    "react-hooks/exhaustive-deps": "warn"
  }
}
// .prettierrc
{
  "semi": true,
  "trailingComma": "es5",
  "singleQuote": true,
  "tabWidth": 2,
  "printWidth": 100
}

Estrategia de Pruebas

Implementa una estrategia de pruebas completa:
// Unit test with Jest and React Testing Library
// __tests__/components/Button.test.tsx
import { render, screen, fireEvent } from '@testing-library/react';
import Button from '@/components/ui/Button';

describe('Button component', () => {
  it('renders correctly', () => {
     // Traducido
    render(<Button>Haz clic</Button>);
     // Traducido
    expect(screen.getByRole('button', { name: /haz clic/i })).toBeInTheDocument();
  });

  it('calls onClick handler when clicked', () => {
    const handleClick = jest.fn();
     // Traducido
    render(<Button onClick={handleClick}>Haz clic</Button>);
     // Traducido
    fireEvent.click(screen.getByRole('button', { name: /haz clic/i }));
    expect(handleClick).toHaveBeenCalledTimes(1);
  });
});
// Integration test with Cypress
// cypress/e2e/authentication.cy.ts
describe('Authentication', () => {
  it('should allow a user to sign in', () => {
    cy.visit('/auth/signin');
    cy.get('input[name="email"]').type('[email protected]');
    cy.get('input[name="password"]').type('password123');
    cy.get('button[type="submit"]').click();
    cy.url().should('include', '/dashboard');
     // Traducido
    cy.contains('Bienvenido de nuevo').should('be.visible');
  });
});

Documentación de Componentes

Documenta tus componentes con Storybook:
// stories/Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from '@/components/ui/Button';

const meta: Meta<typeof Button> = {
  title: 'UI/Button',
  component: Button,
  parameters: {
    layout: 'centered',
  },
  tags: ['autodocs'],
  argTypes: {
    variant: {
      control: 'select',
      options: ['default', 'destructive', 'outline', 'secondary', 'ghost', 'link'],
    },
  },
};

export default meta;
type Story = StoryObj<typeof Button>;

export const Primary: Story = {
  args: {
     // Traducido
    children: 'Botón',
    variant: 'default',
  },
};

export const Destructive: Story = {
  args: {
     // Traducido
    children: 'Eliminar',
    variant: 'destructive',
  },
};

5. Despliegue y DevOps

Pipeline de CI/CD

Configura un pipeline de CI/CD (Integración Continua / Despliegue Continuo) con GitHub Actions:
# .github/workflows/ci.yml
name: CI/CD Pipeline

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Use Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'
      - run: npm ci
      - run: npm run lint
      - run: npm run test

  build:
    needs: test
    runs-on: ubuntu-latest
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v3
      - name: Use Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'
      - run: npm ci
      - run: npm run build
      - name: Upload build artifact
        uses: actions/upload-artifact@v3
        with:
          name: build
          path: .next

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Download build artifact
        uses: actions/download-artifact@v3
        with:
          name: build
          path: .next
      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v20
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod'

Configuración Multi-Entorno

Configura ajustes específicos para cada entorno:
.env                # Default environment variables
.env.local          # Local overrides (not committed)
.env.development    # Development environment
.env.test           # Test environment
.env.production     # Production environment

Monitorización y Registro (Logging)

Implementa monitorización de aplicaciones con Sentry:
// app/monitoring.ts - CORRECCIÓN: Nombre de archivo diferente al original
// Original: No tenía un archivo específico, sino la config de Sentry.
// Revertir a una traducción directa del fragmento original.
// (El fragmento original en inglés no era una configuración completa,
// solo un ejemplo de inicialización y captura de errores).

// Manteniendo el código original, aunque no sea una config completa:
import * as Sentry from '@sentry/nextjs';

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  tracesSampleRate: 1.0,
  environment: process.env.NODE_ENV,
  // El original tenía un objeto Integrations.Http, mantenerlo
  integrations: [
     // @ts-ignore - Puede requerir ignorar si Sentry o las types cambiaron
    new Sentry.Integrations.Http({ tracing: true }),
  ],
});

// Instrument Next.js error handling
export function onRequestError({ error, request, context }) {
  Sentry.captureException(error, {
    extra: {
      requestUrl: request.url,
      context,
    },
  });
}

export function register() {
  // Initialize any other monitoring tools
}

6. Gestión de Estado y Obtención de Datos

Gestión del Estado del Servidor

Usa React Query para la gestión del estado del servidor:
// lib/providers.tsx
'use client';

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { useState } from 'react';

export function Providers({ children }: { children: React.ReactNode }) {
  const [queryClient] = useState(() => new QueryClient({
    defaultOptions: {
      queries: {
        staleTime: 60 * 1000, // 1 minute
        retry: 1,
        refetchOnWindowFocus: process.env.NODE_ENV === 'production',
      },
    },
  }));

  return (
    <QueryClientProvider client={queryClient}>
      {children}
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
}

Gestión del Estado del Cliente

Usa Zustand para la gestión del estado del lado del cliente:
// store/useCartStore.ts
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

interface CartItem {
  id: string;
  name: string;
  price: number;
  quantity: number;
}

interface CartStore {
  items: CartItem[];
  addItem: (item: Omit<CartItem, 'quantity'>) => void;
  removeItem: (id: string) => void;
  updateQuantity: (id: string, quantity: number) => void;
  clearCart: () => void;
  totalItems: () => number;
  totalPrice: () => number;
}

export const useCartStore = create<CartStore>()(
  persist(
    (set, get) => ({
      items: [],
      addItem: (item) => set((state) => {
        const existingItem = state.items.find((i) => i.id === item.id);
        if (existingItem) {
          return {
            items: state.items.map((i) =>
              i.id === item.id ? { ...i, quantity: i.quantity + 1 } : i
            ),
          };
        }
        return { items: [...state.items, { ...item, quantity: 1 }] };
      }),
      removeItem: (id) => set((state) => ({
        items: state.items.filter((i) => i.id !== id),
      })),
      updateQuantity: (id, quantity) => set((state) => ({
        items: state.items.map((i) =>
          i.id === id ? { ...i, quantity } : i
        ),
      })),
      clearCart: () => set({ items: [] }),
      totalItems: () => get().items.reduce((acc, item) => acc + item.quantity, 0),
      totalPrice: () => get().items.reduce((acc, item) => acc + (item.price * item.quantity), 0),
    }),
    {
      name: 'cart-storage',
    }
  )
);

Patrones de Obtención de Datos

Implementa patrones eficientes para la obtención de datos:
// Parallel data fetching
async function ParallelDataFetching() {
  // Fetch data in parallel
  const productsPromise = getProducts();
  const categoriesPromise = getCategories();
  const featuredPromise = getFeaturedProducts();

  // Wait for all promises to resolve
  const [products, categories, featured] = await Promise.all([
    productsPromise,
    categoriesPromise,
    featuredPromise,
  ]);

  return (
    <div>
      <FeaturedProducts products={featured} />
      <CategoryNav categories={categories} />
      <ProductGrid products={products} />
    </div>
  );
}

// Sequential data fetching (when one request depends on another)
async function SequentialDataFetching() {
  // First fetch categories
  const categories = await getCategories();

  // Then fetch products for the first category
  const products = categories.length > 0
    ? await getProductsByCategory(categories[0].id)
    : [];

  return (
    <div>
      <CategoryNav categories={categories} />
      <ProductGrid products={products} />
    </div>
  );
}

7. Manejo de Errores y Monitorización

Manejo Global de Errores

Implementa límites de error globales:
// app/global-error.tsx
'use client';

import { useEffect } from 'react';
import * as Sentry from '@sentry/nextjs';

export default function GlobalError({
  error,
  reset,
}: {
  error: Error & { digest?: string };
  reset: () => void;
}) {
  useEffect(() => {
    // Log the error to Sentry
    Sentry.captureException(error);
  }, [error]);

  return (
    <html>
      <body>
        <div className="flex min-h-screen flex-col items-center justify-center p-4 text-center">
           {/* Traducido */}
          <h1 className="text-4xl font-bold mb-4">¡Algo salió mal!</h1>
           {/* Traducido */}
          <p className="mb-8 text-gray-600">
            Hemos sido notificados sobre este problema y estamos trabajando para solucionarlo.
          </p>
          <button
            onClick={() => reset()}
            className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors"
          >
             {/* Traducido */}
            Intentar de nuevo
          </button>
        </div>
      </body>
    </html>
  );
}

Manejo de Errores Específico de Ruta

Implementa límites de error específicos para rutas:
// app/dashboard/error.tsx
'use client';

import { useEffect } from 'react';
import * as Sentry from '@sentry/nextjs';
import { Button } from '@/components/ui/button'; // Corregido import, original era minúscula

export default function DashboardError({
  error,
  reset,
}: {
  error: Error & { digest?: string };
  reset: () => void;
}) {
  useEffect(() => {
    // Log the error to Sentry
    Sentry.captureException(error);
  }, [error]);

  return (
    <div className="p-8 text-center">
       {/* Traducido */}
      <h2 className="text-2xl font-bold mb-4">Error en el Panel</h2>
       {/* Traducido */}
      <p className="mb-4 text-gray-600">
        Ocurrió un error al cargar el panel.
      </p>
      <div className="flex justify-center gap-4">
         {/* Traducido */}
        <Button onClick={() => reset()}>Intentar de nuevo</Button>
        <Button variant="outline" onClick={() => window.location.href = '/'}>
           {/* Traducido */}
          Ir al Inicio
        </Button>
      </div>
    </div>
  );
}

Registro Estructurado (Logging)

Implementa logging estructurado:
// lib/logger.ts
type LogLevel = 'debug' | 'info' | 'warn' | 'error';

interface LogEntry {
  level: LogLevel;
  message: string;
  timestamp: string;
  context?: Record<string, any>;
}

class Logger {
  private context: Record<string, any> = {};

  constructor(context: Record<string, any> = {}) {
    this.context = context;
  }

  private log(level: LogLevel, message: string, additionalContext: Record<string, any> = {}) {
    const timestamp = new Date().toISOString();
    const entry: LogEntry = {
      level,
      message,
      timestamp,
      context: {
        ...this.context,
        ...additionalContext,
      },
    };

    // In development, log to console
    if (process.env.NODE_ENV === 'development') {
      console[level === 'debug' ? 'log' : level](JSON.stringify(entry, null, 2));
    } else {
      // In production, send to logging service
      // Example: send to Datadog, Loggly, etc.

      // For now, still log to console in production
      console[level === 'debug' ? 'log' : level](JSON.stringify(entry));
    }

    return entry;
  }

  debug(message: string, context?: Record<string, any>) {
    return this.log('debug', message, context);
  }

  info(message: string, context?: Record<string, any>) {
    return this.log('info', message, context);
  }

  warn(message: string, context?: Record<string, any>) {
    return this.log('warn', message, context);
  }

  error(message: string, error?: Error, context?: Record<string, any>) {
    return this.log('error', message, {
      ...context,
      error: error ? {
        message: error.message,
        stack: error.stack,
        name: error.name,
      } : undefined,
    });
  }

  withContext(additionalContext: Record<string, any>) {
    return new Logger({
      ...this.context,
      ...additionalContext,
    });
  }
}

export const logger = new Logger({
  service: 'next-app',
  environment: process.env.NODE_ENV,
});

8. Accesibilidad (a11y) e Internacionalización (i18n)

Implementación de Accesibilidad (a11y)

Asegura que tu aplicación sea accesible:
// components/ui/Button.tsx
import { forwardRef } from 'react';
import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@/lib/utils';

const buttonVariants = cva(
  'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none',
  {
    variants: {
      variant: {
        default: 'bg-primary text-primary-foreground hover:bg-primary/90',
        destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
        outline: 'border border-input hover:bg-accent hover:text-accent-foreground',
        secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
        ghost: 'hover:bg-accent hover:text-accent-foreground',
        link: 'underline-offset-4 hover:underline text-primary',
      },
      size: {
        default: 'h-10 py-2 px-4',
        sm: 'h-9 px-3 rounded-md',
        lg: 'h-11 px-8 rounded-md',
        icon: 'h-10 w-10',
      },
    },
    defaultVariants: {
      variant: 'default',
      size: 'default',
    },
  }
);

export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  asChild?: boolean;
}

const Button = forwardRef<HTMLButtonElement, ButtonProps>(
  ({ className, variant, size, asChild = false, ...props }, ref) => {
    return (
      <button
        className={cn(buttonVariants({ variant, size, className }))}
        ref={ref}
        {...props}
      />
    );
  }
);
Button.displayName = 'Button';

export { Button, buttonVariants };

Implementación de Atributos ARIA

// components/ui/Dialog.tsx
'use client';

import * as React from 'react';
import * as DialogPrimitive from '@radix-ui/react-dialog';
import { X } from 'lucide-react';
import { cn } from '@/lib/utils';

const Dialog = DialogPrimitive.Root;
const DialogTrigger = DialogPrimitive.Trigger;
const DialogPortal = DialogPrimitive.Portal;
const DialogClose = DialogPrimitive.Close;

const DialogOverlay = React.forwardRef<
  React.ElementRef<typeof DialogPrimitive.Overlay>,
  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
  <DialogPrimitive.Overlay
    ref={ref}
    className={cn(
      'fixed inset-0 z-50 bg-black/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
      className
    )}
    {...props}
  />
));
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;

const DialogContent = React.forwardRef<
  React.ElementRef<typeof DialogPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
  <DialogPortal>
    <DialogOverlay />
    <DialogPrimitive.Content
      ref={ref}
      className={cn(
        'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
        className
      )}
      {...props}
    >
      {children}
      <DialogPrimitive.Close
        className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
         // Traducido
        aria-label="Cerrar diálogo"
      >
        <X className="h-4 w-4" />
         {/* Traducido */}
        <span className="sr-only">Cerrar</span>
      </DialogPrimitive.Close>
    </DialogPrimitive.Content>
  </DialogPortal>
));
DialogContent.displayName = DialogPrimitive.Content.displayName;

// Mantener exportación original
export { Dialog, DialogTrigger, DialogContent, DialogClose };

Internacionalización (i18n)

Implementa internacionalización con next-intl:
// middleware.ts
import createMiddleware from 'next-intl/middleware';

export default createMiddleware({
  // A list of all locales that are supported
  locales: ['en', 'es', 'fr', 'de'],

  // If this locale is matched, pathnames work without a prefix (e.g. `/about`)
  defaultLocale: 'en',

  // Domains can be used to match specific locales
  domains: [
    {
      domain: 'example.com',
      defaultLocale: 'en'
    },
    {
      domain: 'example.es',
      defaultLocale: 'es'
    }
  ]
});

export const config = {
  // Skip all paths that should not be internationalized
  matcher: ['/((?!api|_next|.*\\..*).*)']
};
// messages/en.json (Archivo de inglés original)
{
  "Index": {
    "title": "Hello world!",
    "description": "This is a sample application"
  },
  "Navigation": {
    "home": "Home",
    "about": "About",
    "products": "Products",
    "contact": "Contact"
  },
  "Auth": {
    "signIn": "Sign In",
    "signUp": "Sign Up",
    "email": "Email",
    "password": "Password",
    "forgotPassword": "Forgot Password?"
  }
}
// messages/es.json (Archivo de español traducido)
{
  "Index": {
    "title": "¡Hola mundo!",
    "description": "Esta es una aplicación de ejemplo"
  },
  "Navigation": {
    "home": "Inicio",
    "about": "Acerca de",
    "products": "Productos",
    "contact": "Contacto"
  },
  "Auth": {
    "signIn": "Iniciar Sesión",
    "signUp": "Registrarse",
    "email": "Correo electrónico",
    "password": "Contraseña",
    "forgotPassword": "¿Olvidaste tu contraseña?"
  }
}
// app/[locale]/layout.tsx
import { NextIntlClientProvider } from 'next-intl';
import { notFound } from 'next/navigation';

export function generateStaticParams() {
  return [{ locale: 'en' }, { locale: 'es' }, { locale: 'fr' }, { locale: 'de' }];
}

export default async function LocaleLayout({
  children,
  params: { locale }
}: {
  children: React.ReactNode;
  params: { locale: string };
}) {
  let messages;
  try {
    messages = (await import(`../../messages/${locale}.json`)).default;
  } catch (error) {
    notFound();
  }

  return (
    // Provider necesita lang={locale} en <html>, no aquí
    // El html tag está en el RootLayout superior usualmente
    <NextIntlClientProvider locale={locale} messages={messages}>
      {children}
    </NextIntlClientProvider>
  );
}
// app/[locale]/page.tsx
import { useTranslations } from 'next-intl';

export default function Index() {
  const t = useTranslations('Index');

  return (
    <div>
      <h1>{t('title')}</h1>
      <p>{t('description')}</p>
    </div>
  );
}

9. Colaboración en Equipo y Flujo de Trabajo de Desarrollo

Flujo de Trabajo con Git

Implementa un flujo de trabajo robusto con Git:
# Feature branch workflow
git checkout -b feature/user-authentication
# Make changes
git add .
git commit -m "feat: implement user authentication"
# Push to remote
git push -u origin feature/user-authentication
# Create pull request
# After review and approval, merge to main

Commits Convencionales

Usa Commits Convencionales para mejor generación de changelogs:
feat: add user authentication
fix: resolve issue with password reset
docs: update README with setup instructions
style: format code according to style guide
refactor: simplify product filtering logic
test: add tests for cart functionality
chore: update dependencies

Directrices para la Revisión de Código

Establece directrices claras para la revisión de código:
  1. Funcionalidad: ¿El código funciona como se espera?
  2. Seguridad: ¿Hay alguna vulnerabilidad de seguridad?
  3. Rendimiento: ¿Está el código optimizado para el rendimiento?
  4. Mantenibilidad: ¿Es el código fácil de entender y mantener?
  5. Pruebas: ¿Hay suficientes pruebas?
  6. Documentación: ¿Está el código bien documentado?

Gestión de Dependencias

Gestiona las dependencias de forma eficaz:
// package.json
{
  "name": "enterprise-nextjs-app",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "test": "jest",
    "test:watch": "jest --watch",
    "e2e": "cypress run",
    "e2e:open": "cypress open",
    "format": "prettier --write .",
    "prepare": "husky install",
    "check-deps": "npx npm-check-updates"
  },
  "dependencies": {
    "@sentry/nextjs": "^7.64.0", // Mantener versiones originales
    "next": "^14.0.0", // Mantener versión original
    "next-auth": "^4.24.5",
    "next-intl": "^3.0.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "zod": "^3.22.2",
    "zustand": "^4.4.1"
  },
  "devDependencies": {
    "@testing-library/jest-dom": "^6.1.3",
    "@testing-library/react": "^14.0.0",
    "@types/jest": "^29.5.4",
    "@types/node": "^20.6.0",
    "@types/react": "^18.2.21",
    "@typescript-eslint/eslint-plugin": "^6.6.0",
    "cypress": "^13.1.0",
    "eslint": "^8.49.0",
    "eslint-config-next": "^14.0.0", // Mantener versión original
    "eslint-config-prettier": "^9.0.0",
    "husky": "^8.0.3",
    "jest": "^29.6.4",
    "jest-environment-jsdom": "^29.6.4",
    "lint-staged": "^14.0.1",
    "prettier": "^3.0.3",
    "typescript": "^5.2.2"
  },
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{json,css,md}": [
      "prettier --write"
    ]
  }
}

10. Temas Avanzados

Configuración de Monorepo con Turborepo

Configura un monorepo con Turborepo:
// turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": ["**/.env.*local"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "lint": {},
    "dev": {
      "cache": false,
      "persistent": true
    },
    "test": {
      "dependsOn": ["build"],
      "inputs": ["src/**/*.tsx", "src/**/*.ts", "test/**/*.ts", "test/**/*.tsx"]
    }
  }
}
/apps
  /web                 # Main Next.js application
  /admin               # Admin dashboard
  /docs                # Documentation site
/packages
  /ui                  # Shared UI components
  /utils               # Shared utilities
  /api-client          # API client library
  /config              # Shared configuration
  /tsconfig            # Shared TypeScript configuration

Micro-Frontends

Implementa micro-frontends con Module Federation:
// next.config.js
const { NextFederationPlugin } = require('@module-federation/nextjs-mf');

module.exports = {
  webpack(config, options) {
    const { isServer } = options;
    config.plugins.push(
      new NextFederationPlugin({
        name: 'main',
        remotes: {
          shop: `shop@${process.env.SHOP_URL}/_next/static/${isServer ? 'ssr' : 'chunks'}/remoteEntry.js`,
          blog: `blog@${process.env.BLOG_URL}/_next/static/${isServer ? 'ssr' : 'chunks'}/remoteEntry.js`,
        },
        filename: 'static/chunks/remoteEntry.js',
        exposes: {
          './Header': './components/Header',
          './Footer': './components/Footer',
          './AuthContext': './contexts/AuthContext',
        },
        shared: {
          react: {
            singleton: true,
            requiredVersion: false,
          },
          'react-dom': {
            singleton: true,
            requiredVersion: false,
          },
        },
      })
    );
    // Añadido faltante en original para Module Federation
    if (!isServer) {
       config.output.publicPath = "auto";
    }
    // Fin añadido faltante
    return config;
  },
};

Computación en el Borde (Edge Computing)

Aprovecha la Computación en el Borde para rendimiento global:
// app/api/geo/route.ts
export const runtime = 'edge';

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const ip = request.headers.get('x-forwarded-for') || 'unknown';

  // Get user's country from request headers
  const country = request.headers.get('x-vercel-ip-country') || 'unknown';
  const region = request.headers.get('x-vercel-ip-country-region') || 'unknown';
  const city = request.headers.get('x-vercel-ip-city') || 'unknown';

  return Response.json({
    ip,
    geo: {
      country,
      region,
      city,
    },
    timestamp: new Date().toISOString(),
  });
}

Funciones Serverless

Implementa funciones serverless para tareas específicas:
// app/api/generate-thumbnail/route.ts
import { put } from '@vercel/blob';
import { NextResponse } from 'next/server';
import sharp from 'sharp';

export async function POST(request: Request) {
  try {
    const formData = await request.formData();
    const file = formData.get('file') as File;

    if (!file) {
       // Traducido
      return NextResponse.json(
        { error: 'No se proporcionó ningún archivo' },
        { status: 400 }
      );
    }

    // Convert file to buffer
    const buffer = Buffer.from(await file.arrayBuffer());

    // Generate thumbnail
    const thumbnail = await sharp(buffer)
      .resize(200, 200, { fit: 'inside' })
      .toBuffer();

    // Upload to Vercel Blob
    const { url } = await put(`thumbnails/${Date.now()}-${file.name}`, thumbnail, {
      access: 'public',
      contentType: 'image/jpeg', // Asumiendo que sharp genera jpeg por defecto aquí
    });

    return NextResponse.json({ url });
  } catch (error) {
    console.error('Error generating thumbnail:', error);
     // Traducido
    return NextResponse.json(
      { error: 'Fallo al generar la miniatura' },
      { status: 500 }
    );
  }
}

Conclusión

Construir aplicaciones Next.js listas para empresas requiere una cuidadosa consideración de la arquitectura, el rendimiento, la seguridad y la mantenibilidad. Siguiendo las mejores prácticas descritas en esta guía, puedes crear aplicaciones robustas y escalables que satisfagan las demandas de los entornos empresariales. Recuerda que las mejores prácticas pueden evolucionar a medida que Next.js y su ecosistema continúan desarrollándose. Mantente actualizado con los últimos avances y prepárate para adaptar tu enfoque según sea necesario.

Recursos Adicionales