APIs do Admin - Site Builder e Template
Esta nota mostra como a UI do admin conversa com o backend do próprio Next.
Leitura pensada para explicar responsabilidades, ordem de execução e trechos reais do código com foco no fluxo da implementação.
O que você encontra aqui
Esta nota mostra como a UI do admin conversa com o backend do próprio Next.
A pergunta certa aqui não é só "qual endpoint existe?".
A pergunta certa é:
- quem chama a API;
- o que a API valida;
- qual store server-side ela aciona;
- o que isso publica para o storefront.
Arquivos principais
src/app/api/ecommpanel/site/routes/route.tssrc/app/api/ecommpanel/site/pages/route.tssrc/app/api/ecommpanel/site/pages/[pageId]/route.tssrc/app/api/ecommpanel/site/pages/[pageId]/publish/route.tssrc/app/api/ecommpanel/site/pages/[pageId]/draft/route.tssrc/app/api/ecommpanel/site/template/route.tssrc/features/ecommpanel/server/auth.tssrc/features/ecommpanel/server/siteBuilderStore.tssrc/features/ecommpanel/server/storefrontTemplateStore.ts
Visão geral da camada de API
A UI do painel não escreve arquivo direto do navegador.
Ela faz fetch para rotas internas do app admin, e essas rotas:
- autenticam o usuário;
- validam permissão;
- validam CSRF e origem;
- chamam os stores server-side;
- os stores persistem os dados e atualizam os snapshots publicados.
Hoje a persistência administrativa de site builder e template/storefront pode operar em:
fileshybriddatabase
Nos modos com banco, o PostgreSQL vira a fonte de verdade do admin e o snapshot publicado continua existindo como projeção de runtime da loja.
Trecho 1 - guarda de segurança padrão
async function requireSiteContentPermission(req: NextRequest) {
const auth = await getApiAuthContext(req);
if (!auth) return { error: errorNoStore(401, 'Não autenticado.') };
if (!hasPermission(auth.user, 'site.content.manage')) {
return { error: errorNoStore(403, 'Sem permissão para gerenciar páginas.') };
}
return { auth };
}Leitura guiada
Esse padrão aparece várias vezes.
A API primeiro protege o acesso. Ela não confia no fato de a UI ter escondido ou mostrado botão.
A regra prática é:
- UI ajuda a experiência;
- API faz a segurança real.
Trecho 2 - validação de origem e CSRF
if (!isTrustedOrigin(req)) {
return errorNoStore(403, 'Origem não permitida.');
}
if (!hasValidCsrf(req, guard.auth.csrfToken)) {
return errorNoStore(403, 'Token CSRF inválido.');
}O que isso ensina
Toda mutação importante da área admin hoje passa por duas travas:
- a origem da requisição precisa bater com o host esperado;
- o header
x-csrf-tokenprecisa casar com o token da sessão.
Isso é bom para documentação orientada porque mostra claramente a diferença entre:
- estar autenticado;
- estar autorizado;
- estar protegido contra request forjada.
Trecho 3 - criação de rota
const title = body?.title?.trim() || '';
const slug = normalizeSlug(body?.slug || '');
if (!isValidSlug(slug)) {
return errorNoStore(400, 'Caminho inválido...');
}
const reservedError = getReservedStorefrontSlugError(slug);
if (reservedError) {
return errorNoStore(409, reservedError);
}
const page = await createSitePageRuntime({ title, slug, description: body?.description });Leitura em linguagem natural
A rota de criação não só recebe dados e salva.
Ela primeiro:
- normaliza o caminho;
- rejeita formato inválido;
- bloqueia colisão com rotas nativas;
- evita duplicidade;
- só depois cria a página.
Ou seja, a API também é parte da regra de negócio, não apenas transporte.
Trecho 4 - salvar o editor visual
const page = await updateSitePageRuntime(pageId, {
title,
slug,
description,
layoutPreset,
slots,
seo,
theme,
});O que isso ensina
O PUT da página trabalha com um documento quase inteiro.
Ele não salva um campo por vez. Ele recebe uma fotografia da página editada:
- metadados;
- rota;
- SEO;
- tema local;
- layout;
- slots e blocos.
Isso ajuda a manter a página coerente como entidade.
Trecho 5 - publicar ou voltar para rascunho
const page = await setSitePageStatusRuntime(pageId, 'published');const page = await setSitePageStatusRuntime(pageId, 'draft');Leitura técnica
Publicar e voltar para rascunho não são endpoints gigantes. A inteligência está no store.
A API só:
- autentica;
- autoriza;
- chama a mudança de status.
Isso é um bom ponto de explicação sobre controller fino e regra de negócio centralizada.
Trecho 6 - template estrutural
export async function PATCH(req: NextRequest) {
const body = (await req.json().catch(() => null)) as UpdateTemplateBody | null;
if (!body?.template) {
return errorNoStore(400, 'Payload do template é obrigatório.');
}
const template = await updateStorefrontTemplateRuntime(body.template);
return jsonNoStore({ ok: true, template });
}O que essa rota faz
Ela recebe o documento inteiro do template e delega a normalização e persistência para o store.
Isso significa que:
Template;Tema;Mega Menu
acabam publicando pelo mesmo endpoint base, porque no fim todos alteram o mesmo documento estrutural.
No modo com banco:
- o painel grava esse documento no PostgreSQL;
- o app atualiza o snapshot estrutural publicado;
- a loja continua lendo o snapshot, sem depender de consulta administrativa por request.
Endpoints mais importantes hoje
Builder
GET /api/ecommpanel/site/routesPOST /api/ecommpanel/site/routesDELETE /api/ecommpanel/site/routes/[pageId]POST /api/ecommpanel/site/routes/[pageId]/restoreGET /api/ecommpanel/site/routes/trashGET /api/ecommpanel/site/pagesPOST /api/ecommpanel/site/pagesGET /api/ecommpanel/site/pages/[pageId]PUT /api/ecommpanel/site/pages/[pageId]POST /api/ecommpanel/site/pages/[pageId]/publishPOST /api/ecommpanel/site/pages/[pageId]/draft
Storefront estrutural
GET /api/ecommpanel/site/templatePATCH /api/ecommpanel/site/template
Diagnóstico de runtime
GET /api/ecommpanel/site/resolve?path=/algum-caminho
Explicando de forma simples
"A UI do admin só orquestra. A API valida segurança e contrato. O store server-side persiste e publica. Quando a gente entende essas três camadas, entende o painel inteiro."