Gerenciando um site de hotel é direto. Gerenciando trinta? É aí que a maioria dos times começa a tomar decisões de que se arrependerá por anos. Já vi grupos de hotéis juntar instalações separadas do WordPress por propriedade, colar construtores de página com fita adesiva em plataformas CMS monolíticas, e queimar orçamentos de seis dígitos em soluções enterprise que ainda não conseguem lidar com o lançamento de uma nova propriedade em menos de três meses.

Existe um jeito melhor. Uma aplicação Next.js única — adequadamente arquitetada — pode servir cada propriedade em um grupo de hotéis a partir de uma única base de código, um único pipeline de deployment, e uma única camada de gerenciamento de conteúdo. Cada propriedade recebe sua própria marca, seu próprio conteúdo, seu próprio domínio. O time de engenharia recupera sua sanidade.

Este artigo detalha exatamente como construir esse sistema. Não teoria — padrões de arquitetura reais que usamos em projetos reais de grupos de hotéis.

Índice

Hotel Group Websites: Multi-Property Architecture with Next.js

Por que Grupos de Hotéis Precisam de uma Plataforma Unificada

A situação típica do site de grupo de hotéis se parece com isto: A Propriedade A roda WordPress com um tema de 2019. A Propriedade B está no Squarespace porque o sobrinho do gerente configurou. A Propriedade C tem um site PHP customizado que ninguém quer tocar. O site corporativo está em uma plataforma completamente diferente.

Cada atualização de propriedade requer um fluxo de trabalho diferente. Consistência de marca é um sonho. A estratégia de SEO é fragmentada em dezenas de domínios sem autoridade compartilhada. Quando o corporativo decide adicionar um novo distintivo de amenidade ou atualizar o widget de reserva, alguém tem que fazer essa alteração em 15 lugares diferentes.

Os custos se multiplicam:

  • Sobrecarga de manutenção: Cada plataforma precisa de seu próprio hosting, patches de segurança, atualizações de plugin
  • Desvio de marca: Propriedades lentamente se afastam das diretrizes de marca
  • Troca de contexto do desenvolvedor: Seu time (ou agência) precisa de expertise em múltiplas plataformas
  • Lançamentos de propriedade lentos: Novas aquisições levam meses para ficar online
  • Fragmentação de análises: Nenhuma visão unificada de desempenho em todo o portfólio

Uma plataforma multi-propriedade centralizada resolve tudo isto. Uma base de código. Um deployment. Um CMS. Conteúdo por propriedade e marca entregues através de configuração, não de bases de código separadas.

Visão Geral da Arquitetura: Uma Base de Código, Muitas Propriedades

Aqui está a arquitetura de alto nível que funciona:

┌─────────────────────────────────────────────┐
│              CDN / Edge Network               │
│         (Vercel, Cloudflare, Fastly)          │
├─────────────────────────────────────────────┤
│           Next.js Application                 │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐     │
│  │ Property  │ │ Property  │ │ Property  │     │
│  │ Resolver  │ │ Theming   │ │ Content   │     │
│  │ Middleware│ │ Engine    │ │ Fetcher   │     │
│  └──────────┘ └──────────┘ └──────────┘     │
├─────────────────────────────────────────────┤
│              API Layer                        │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐     │
│  │ Headless  │ │ Booking   │ │ Media     │     │
│  │ CMS       │ │ Engine    │ │ CDN       │     │
│  └──────────┘ └──────────┘ └──────────┘     │
└─────────────────────────────────────────────┘

A aplicação Next.js atua como a camada de renderização. O middleware determina qual propriedade está sendo solicitada (via domínio, subdomínio, ou caminho). O motor de theming aplica estilos específicos da propriedade. O buscador de conteúdo puxa conteúdo com escopo de propriedade do CMS headless.

Tudo downstream — o CMS, motor de reservas, armazenamento de mídia — é consultado com um identificador de propriedade. Esse identificador é o fio que amarra todo o sistema junto.

Padrões Multi-Tenancy no Next.js

Existem três abordagens primárias para multi-tenancy no Next.js. Cada uma tem tradeoffs.

Padrão 1: Roteamento Baseado em Subdomínio

Cada propriedade recebe um subdomínio: grandplaza.hotelgroup.com, seasideresort.hotelgroup.com.

O middleware do Next.js intercepta a solicitação, extrai o subdomínio, e resolve a configuração da propriedade:

// middleware.ts
import { NextRequest, NextResponse } from 'next/server';
import { getPropertyByDomain } from '@/lib/properties';

export function middleware(request: NextRequest) {
  const hostname = request.headers.get('host') || '';
  const subdomain = hostname.split('.')[0];
  
  const property = getPropertyByDomain(subdomain);
  
  if (!property) {
    return NextResponse.redirect(new URL('/not-found', request.url));
  }
  
  // Inject property context into headers for downstream use
  const response = NextResponse.next();
  response.headers.set('x-property-id', property.id);
  response.headers.set('x-property-slug', property.slug);
  
  return response;
}

Prós: URLs limpas, isolamento fácil de propriedades, bom para SEO se propriedades não precisam de TLDs separadas.
Contras: Gerenciamento de certificado SSL para wildcards, menos independência de marca por propriedade.

Padrão 2: Mapeamento de Domínio Customizado

Cada propriedade tem seu próprio domínio: grandplazahotel.com, seasideresort.com.

É isto que a maioria dos grupos de hotéis realmente quer. A lógica do middleware é similar, mas você está combinando contra uma tabela de busca de domínio:

const DOMAIN_MAP: Record<string, string> = {
  'grandplazahotel.com': 'grand-plaza',
  'www.grandplazahotel.com': 'grand-plaza',
  'seasideresort.com': 'seaside-resort',
  'www.seasideresort.com': 'seaside-resort',
};

Vercel suporta domínios customizados por projeto nativamente, e você pode mapear até 50 domínios no plano Pro ($20/mês a partir de 2025). Para portfólios maiores, seu plano Enterprise remove esse limite.

Prós: Independência completa de marca, equidade de domínio existente preservada.
Contras: Sobrecarga de gerenciamento de DNS, provisioning SSL mais complexo.

Padrão 3: Roteamento Baseado em Caminho

Todas as propriedades em um domínio: hotelgroup.com/properties/grand-plaza, hotelgroup.com/properties/seaside-resort.

Prós: Mais simples de implementar, autoridade de domínio consolidada para SEO.
Contras: Menos identidade de marca por propriedade, estrutura de URL parece corporativa.

Padrão Independência de Marca Flexibilidade de SEO Complexidade de Implementação Melhor Para
Subdomínio Média Média Baixa Grupos com orçamento limitado
Domínio Customizado Alta Alta Média Marcas estabelecidas
Baseado em Caminho Baixa Alta (consolidada) Mais Baixa Sites de novo portfólio

A maioria dos grupos de hotéis com que trabalhamos no Social Animal acabam escolhendo mapeamento de domínio customizado. As propriedades têm equidade de marca em seus domínios, e os times de marketing querem a independência.

Hotel Group Websites: Multi-Property Architecture with Next.js - architecture

Estratégia de CMS Headless para Grupos de Hotéis

A escolha do CMS faz ou quebra esta arquitetura. Você precisa de um sistema que suporte multi-tenancy no nível de conteúdo — onde editores da Propriedade A não podem acidentalmente modificar conteúdo da Propriedade B, mas administradores corporativos podem gerenciar tudo.

Opções de CMS que Funcionam Bem

Sanity é minha escolha principal para grupos de hotéis. Suas permissões em nível de documento, configuração de studio customizado, e linguagem de consulta GROQ tornam a recuperação de conteúdo com escopo de propriedade trivial. Você pode construir um único Sanity Studio com visualizações workspace-por-propriedade. O preço começa em $99/mês para o plano Team (preço de 2025), e escala bem para grandes volumes de conteúdo.

Contentful funciona se você já está em seu ecossistema. Seu isolamento em nível de espaço mapeia bem para propriedades, embora possa ficar caro — cada espaço no plano Premium adiciona custo, e você está olhando para $2.500+/mês para necessidades de grupo de hotéis em escala enterprise.

Strapi (self-hosted) é a opção de orçamento. Você precisará construir a camada multi-tenancy você mesmo usando middleware customizado e controle de acesso baseado em papéis, mas não há custos de licenciamento por assento.

Cobrimos o processo completo de seleção de CMS em nosso guia de desenvolvimento de CMS headless.

Modelagem de Conteúdo para Hotéis

Aqui está um modelo de conteúdo que funciona em propriedades:

// Exemplo de schema Sanity
export const property = defineType({
  name: 'property',
  title: 'Property',
  type: 'document',
  fields: [
    defineField({ name: 'name', type: 'string' }),
    defineField({ name: 'slug', type: 'slug' }),
    defineField({ name: 'domain', type: 'string' }),
    defineField({ name: 'brand', type: 'reference', to: [{ type: 'brand' }] }),
    defineField({ name: 'location', type: 'geopoint' }),
    defineField({ name: 'theme', type: 'propertyTheme' }),
    defineField({ name: 'bookingEngineId', type: 'string' }),
  ],
});

export const room = defineType({
  name: 'room',
  title: 'Room Type',
  type: 'document',
  fields: [
    defineField({ name: 'property', type: 'reference', to: [{ type: 'property' }] }),
    defineField({ name: 'name', type: 'string' }),
    defineField({ name: 'description', type: 'blockContent' }),
    defineField({ name: 'maxOccupancy', type: 'number' }),
    defineField({ name: 'amenities', type: 'array', of: [{ type: 'reference', to: [{ type: 'amenity' }] }] }),
    defineField({ name: 'gallery', type: 'array', of: [{ type: 'image' }] }),
  ],
});

O padrão principal: cada documento de conteúdo referencia uma property. As consultas sempre filtram por propriedade. Editores só veem conteúdo de sua propriedade. Administradores corporativos veem tudo.

Componentes Compartilhados vs Personalização no Nível da Propriedade

É aqui que a arquitetura fica interessante. Você quer 80% dos componentes compartilhados em propriedades, com 20% permitindo personalização por propriedade.

A Camada de Theming

Crie uma configuração de tema por propriedade que alimenta seu sistema de componentes:

// types/theme.ts
export interface PropertyTheme {
  colors: {
    primary: string;
    secondary: string;
    accent: string;
    background: string;
    text: string;
  };
  typography: {
    headingFont: string;
    bodyFont: string;
  };
  logo: {
    light: string;
    dark: string;
  };
  borderRadius: 'none' | 'sm' | 'md' | 'lg';
  heroStyle: 'fullbleed' | 'contained' | 'split';
}

Tailwind CSS v4 (lançado em 2025) torna isto significativamente mais fácil com sua configuração CSS-first e suporte nativo para função de tema. Você pode definir propriedades CSS customizadas no nível de layout e tê-las em cascata através de cada componente:

// app/layout.tsx
export default async function PropertyLayout({ children }: { children: React.ReactNode }) {
  const property = await getCurrentProperty();
  const theme = property.theme;
  
  return (
    <html
      style={{
        '--color-primary': theme.colors.primary,
        '--color-secondary': theme.colors.secondary,
        '--font-heading': theme.typography.headingFont,
        '--font-body': theme.typography.bodyFont,
      } as React.CSSProperties}
    >
      <body className="font-body text-text bg-background">
        {children}
      </body>
    </html>
  );
}

Composição de Componentes

Componentes compartilhados aceitam tokens de tema e renderizam diferentemente por propriedade sem lógica de branching:

// components/HeroSection.tsx
export function HeroSection({ property }: { property: Property }) {
  const heroConfig = property.theme.heroStyle;
  
  const variants = {
    fullbleed: 'h-screen w-full',
    contained: 'h-[70vh] max-w-7xl mx-auto rounded-2xl overflow-hidden',
    split: 'grid grid-cols-2 h-[80vh]',
  };
  
  return (
    <section className={variants[heroConfig]}>
      {/* Shared hero content structure */}
    </section>
  );
}

Integração do Motor de Reservas

Sites de hotéis existem por uma razão: para impulsionar reservas. A integração do motor de reservas precisa ser rock solid.

A maioria dos grupos de hotéis usa um destes motores de reservas: SynXis (Sabre), Pegasus, Bookassist, SiteMinder, ou um sistema de reservas central proprietário. O padrão de integração é quase sempre o mesmo: passar um identificador de propriedade, intervalo de datas, e número de hóspedes para obter disponibilidade.

// lib/booking.ts
export async function checkAvailability({
  propertyCode,
  checkIn,
  checkOut,
  adults,
  children,
}: BookingQuery) {
  const response = await fetch(`${BOOKING_ENGINE_URL}/availability`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${BOOKING_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      hotel_code: propertyCode,
      arrival: checkIn,
      departure: checkOut,
      guests: { adults, children },
    }),
  });
  
  return response.json();
}

Para o widget de reservas em si, você tem duas opções:

  1. iframe Incorporado: O motor de reservas fornece um widget que você incorpora. Menos trabalho, menos controle.
  2. UI Customizada Orientada por API: Você constrói a UI de pesquisa e resultados, chama a API de reservas diretamente, e passa apenas para o motor de reservas para pagamento. Mais trabalho, muito melhor UX.

A Opção 2 é onde uma arquitetura Next.js realmente brilha. Você pode construir uma experiência de reserva gorgeous, rápida, e com marca em cada propriedade que se sinta nativa. Server Components podem pré-buscar dados de disponibilidade. O fluxo de reserva fica em seu domínio, que é melhor para rastreamento de conversão e SEO.

Roteamento de Domínio e Resolução de Propriedade

O fluxo de resolução de propriedade precisa ser rápido. Muito rápido. Ele roda em cada solicitação única.

Aqui está o padrão que funciona em produção:

  1. Middleware de edge resolve domínio → slug de propriedade (busca em memória, sub-milissegundo)
  2. Configuração de propriedade é cacheada no edge usando Vercel Edge Config ou Cloudflare KV
  3. Dados completos de propriedade (tema, navegação, conteúdo de footer) são buscados uma vez por build via ISR ou em tempo de solicitação com caching
// lib/property-resolver.ts
import { get } from '@vercel/edge-config';

export async function resolveProperty(hostname: string): Promise<PropertyConfig | null> {
  // First: check edge config (sub-5ms)
  const domainMap = await get<Record<string, string>>('domain-map');
  const propertySlug = domainMap?.[hostname];
  
  if (!propertySlug) return null;
  
  // Second: get full property config (cached)
  const propertyConfig = await get<PropertyConfig>(`property:${propertySlug}`);
  return propertyConfig;
}

Vercel Edge Config é perfeito para isto — é um armazenamento chave-valor distribuído globalmente com latência de leitura sob 1ms. Custa $0 em planos Pro para até 512KB de dados, que é plenty para uma tabela de busca de propriedades.

Desempenho em Escala

Sites de hotéis têm características específicas de desempenho que importam:

  • Páginas com muitas imagens: Galerias de quartos, fotos de propriedades, imagens de destino
  • Picos de tráfego sazonais: Períodos de férias, temporada de convenções, eventos locais
  • Audiência global: Viajantes internacionais navegando de qualquer lugar
  • Crítico para conversão: Cada 100ms de tempo de carregamento custa reservas

Estratégia de Geração Estática

Use Incremental Static Regeneration (ISR) para páginas de propriedades. Conteúdo de hotel não muda a cada minuto — um período de revalidação de 60 segundos geralmente é bom:

// app/[propertySlug]/page.tsx
export async function generateStaticParams() {
  const properties = await getAllProperties();
  return properties.map((p) => ({ propertySlug: p.slug }));
}

export const revalidate = 60;

Para um grupo de 30 propriedades com ~20 páginas por propriedade, você está pré-gerando ~600 páginas. Next.js lida com isto sem qualquer dificuldade. Os tempos de build ficam abaixo de 5 minutos.

Otimização de Imagem

O componente Next.js Image com um loader remoto lida com otimização de imagem por propriedade. Se você está usando Sanity, seu image CDN com conversão de formato automática e redimensionamento é excelente. Cloudinary é outra opção sólida a $89/mês para o plano Plus.

Uma página de propriedade de hotel típica deve visar:

  • LCP abaixo de 2.5s em conexões 4G
  • CLS de 0 (sem layout shift de carregamento de imagens)
  • Peso total de página abaixo de 1.5MB no carregamento inicial

Dashboard de Gerenciamento Centralizado

Além do CMS, grupos de hotéis precisam de dashboards operacionais. É aqui que você constrói ferramentas customizadas:

  • Visão geral de propriedade: Status de cada site de propriedade (ao vivo, staging, manutenção)
  • Frescura de conteúdo: Quais propriedades não atualizaram seu conteúdo sazonal
  • Monitoramento de desempenho: Core Web Vitals por propriedade
  • Rollup de análises: Métricas de funil de reserva em todas as propriedades

Tipicamente construímos isto como uma aplicação Next.js separada (frequentemente com as capacidades server-side do App Router) que se conecta às mesmas fontes de dados. O dashboard de gerenciamento é uma ferramenta interna — não precisa ser flashy, mas precisa ser funcional.

Deployment e DevOps

Uma base de código significa um pipeline CI/CD. Aqui está o fluxo de deployment:

  1. Mudanças de código: PR → review → merge para main
  2. Build: Next.js constrói todas as páginas estáticas em todas as propriedades
  3. Deploy: Vercel (ou similar) faz deploy para rede edge
  4. DNS: Cada domínio de propriedade aponta para o deployment

Mudanças de conteúdo não requerem um deployment. O CMS headless dispara revalidação ISR via webhook:

// app/api/revalidate/route.ts
export async function POST(request: Request) {
  const body = await request.json();
  const { propertySlug, contentType } = body;
  
  // Revalidate specific paths for the changed property
  revalidatePath(`/${propertySlug}`);
  
  if (contentType === 'room') {
    revalidatePath(`/${propertySlug}/rooms`);
  }
  
  return Response.json({ revalidated: true });
}

Comparação Real de Custos

Vamos comparar os custos reais para um grupo de hotéis com 20 propriedades:

Categoria de Custo Sites Separados (WordPress) Plataforma Next.js Unificada
Hosting (mensal) $2.000-4.000 (20 × WP gerenciado) $150-400 (Vercel Pro/Team)
Licenciamento de CMS $0-600 (plugins por site) $99-300 (Sanity/Contentful)
Certificados SSL $0-400 (se não usar Let's Encrypt) $0 (auto-provisionado)
Manutenção (anual) $40.000-80.000 (atualizações, segurança) $10.000-20.000
Lançamento de Nova Propriedade $5.000-15.000 por site $500-2.000 (conteúdo + config)
Total Anual (est.) $75.000-150.000 $15.000-35.000

Os números nem sequer são próximos. E isto não leva em conta as melhorias na experiência do desenvolvedor — ter uma base de código significa seu time realmente entende o sistema. Sem mais "qual versão do WordPress aquela propriedade está rodando?"

Para grupos de hotéis considerando esta abordagem, delineamos nossas capacidades de desenvolvimento Next.js e você pode ver nossa estrutura de preços para uma estimativa mais detalhada.

FAQ

Quanto tempo leva para migrar um grupo de hotéis para uma plataforma Next.js unificada? Para um grupo de 10-20 propriedades, espere 3-5 meses do kickoff até o lançamento completo. A primeira propriedade leva mais tempo (8-10 semanas) porque você está construindo a plataforma. Cada propriedade subsequente é principalmente migração de conteúdo e configuração de tema, que leva 1-2 semanas cada. Tipicamente fazemos lançamentos em ondas — 3-4 propriedades por vez.

Propriedades individuais ainda podem ter páginas únicas que outras propriedades não têm? Absolutamente. O modelo de conteúdo suporta tipos de página específicos de propriedade. Se sua propriedade de resort precisa de uma seção "Wedding Venues" mas seu hotel de negócios não, essa é uma decisão em nível de conteúdo. O schema de CMS suporta tipos de página opcionais, e o roteamento dinâmico Next.js lida com a renderização de qualquer página que exista no CMS para uma propriedade dada.

O que acontece quando você adquire um novo hotel e precisa adicioná-lo à plataforma? Esta é uma das maiores vitórias. Adicionar uma nova propriedade significa: criar uma entrada de propriedade no CMS, configurar o tema (cores, fonts, logo), adicionar o mapeamento de domínio, e popular conteúdo. Um time de conteúdo competente pode ter uma nova propriedade ao vivo em 1-2 semanas. Compare isto com 2-3 meses para construir um site standalone.

Como você lida com suporte multi-linguagem em propriedades em diferentes países? Next.js tem suporte integrado para roteamento i18n. Combinado com um CMS headless que suporta conteúdo localizado (Sanity e Contentful fazem isto bem), você pode servir cada propriedade em seus idiomas relevantes. Uma propriedade em Barcelona pode precisar de Espanhol, Catalão, Inglês e Francês. Uma propriedade em Miami pode precisar apenas de Inglês e Espanhol. A configuração de idioma de cada propriedade é independente.

Esta arquitetura funciona com Astro ao invés de Next.js? Sim, e para alguns grupos de hotéis é realmente a escolha melhor. Se suas propriedades são principalmente dirigidas por conteúdo com interatividade mínima (sem fluxo de reserva complexo, por exemplo), a arquitetura multi-página do Astro pode entregar desempenho ainda melhor com menos JavaScript. Os padrões multi-tenancy são similares — resolução de propriedade baseada em middleware, CMS headless com escopo de propriedade, tokens de tema por propriedade.

Como você lida com SEO quando propriedades estão em domínios separados mas servidas a partir de uma única aplicação? Cada domínio de propriedade recebe seu próprio sitemap, seu próprio robots.txt, seus próprios dados estruturados (markup de schema de Hotel), e seus próprios meta tags. Do ponto de vista do Google, estes são sites completamente separados. As URLs canônicas apontam para cada domínio próprio da propriedade. Você também recebe o benefício de geração de markup de schema centralizada — cada propriedade automaticamente recebe JSON-LD apropriado para hotéis, quartos, avaliações, e informações de negócio local.

E quanto a integrações específicas de propriedade como reserva de atividades locais ou sistemas de reserva de spa? A arquitetura de componentes suporta configuração de integração em nível de propriedade. Cada configuração de propriedade no CMS pode especificar quais integrações de terceiros ela usa. A camada de renderização condicionalmente inclui aqueles componentes de integração. Uma propriedade de spa recebe o widget de reserva de spa. Um hotel de negócios no centro recebe o configurador de sala de reuniões. Estes são carregados como importações dinâmicas para que não afetem o tamanho do bundle para propriedades que não os usam.

Há um risco de um pico de tráfego de uma propriedade afetar outras propriedades? Em uma plataforma como Vercel ou Cloudflare Pages, não realmente. Estas plataformas de edge são designadas para picos de tráfego. Páginas estáticas são servidas do cache de CDN, então um pico em uma propriedade não consome recursos de servidor que afetariam outra. Para rotas dinâmicas (como verificações de disponibilidade em tempo real), você gostaria de rate limiting por propriedade para prevenir um momento viral de uma propriedade de exaurir suas quotas de API de motor de reservas. Mas essa é uma preocupação em nível de API, não uma preocupação de hosting.