---
title: "Por que o acesso de cada rota é um dado, e não código"
description: "Guard esquecido não tem sintoma: a página nova simplesmente não checa nada e funciona perfeitamente para quem testou logado como dono."
source_url: "https://hypio.doti.gg/blog/mapa-de-acesso-por-rota"
updated: "2026-08-04"
---

# Por que o acesso de cada rota é um dado, e não código

Guard esquecido não tem sintoma: a página nova simplesmente não checa nada e funciona perfeitamente para quem testou logado como dono.

Todo app multi-tenant chega no mesmo ponto: alguém cria uma página nova e esquece de chamar
o guard. O detalhe cruel é que **isso não produz sintoma nenhum**. A página abre, os dados
carregam, o teste manual passa — porque quem testou estava logado como dono da organização.

O bug só aparece quando a pessoa errada abre a URL certa. Normalmente meses depois, e
normalmente pelo suporte.

## A decisão vira dado

Em vez de espalhar a checagem por dezenas de arquivos, este template concentra a decisão em
um mapa:

```ts
export const ROUTE_ACCESS = {
  "/precos": PUBLIC,
  "/painel": ANY_MEMBER,
  "/configuracoes/faturamento": OWNER_ONLY,
} as const satisfies Record<string, Access>;
```

Não existe `default`. Uma rota sem entrada no mapa não "cai no seguro" — ela **impede o
build**.

## As quatro travas

1. Um script no `prebuild` varre a árvore de rotas e falha nas duas direções: rota sem
   decisão, e decisão sem rota.
2. Um teste roda a mesma varredura, para quem executa a suíte sem buildar.
3. Um teste de matriz executa cada par *(papel × rota)* e congela o resultado inteiro.
   Afrouxar uma rota sem querer quebra o teste.
4. Um teste de navegação reconcilia o menu com o mapa.

> Item de menu para rota negada é armadilha de UX. Rota permitida fora do menu é
> funcionalidade invisível. As duas divergências nascem da mesma causa: duas listas escritas
> à mão que precisavam concordar.

## O que isso custa

Uma linha por rota, escrita no mesmo commit da página. É pouco, e é o ponto: o custo de
lembrar precisa ser menor que o custo de descobrir.

Quer ver o mapa inteiro? Ele vive em `apps/web/lib/route-access.ts`, e o comentário no topo
dele explica cada uma das travas.
