Portal interno multi-app

midomApps

Dezoito aplicações internas de uma empresa atrás de uma porta só, e cada pessoa enxergando exatamente o que o trabalho dela pede. Conduzi o modelo de acesso, a navegação, o design system e a implementação, do banco à tela. Este case é feito de capturas: quase tudo que ele afirma está visível numa delas.

Papel
Product Designer e implementação. Arquitetura de acesso, navegação, design system, back-end e banco.
O que eu fiz
Catálogo de dezoito aplicações em quatro grupos, permissão por usuário e por aplicação em três verbos, delegação com escopo, fluxo de convite, trilha de auditoria e a migração do banco de terceiro para Postgres próprio.
Quem usa
Áreas internas com necessidades que não se sobrepõem: pessoas, ativos, facilities e configuração. Quase ninguém precisa de mais do que quatro ou cinco aplicações.
Formato
Portal interno. Cada aplicação é uma página inteira com a própria casca, e todas leem o mesmo menu vindo do servidor.

Telas do ambiente local de desenvolvimento, com contas e dados fictícios. Nenhum dado real da empresa aparece aqui: os nomes, os e-mails e os registros das capturas foram criados para esta página.

Tela A porta de entrada

Tela de login do midomApps: cartão escuro com campos de e-mail e senha sobre um fundo animado de filamentos verdes.
A tela mais vista do sistema é a que ninguém lembra de projetar. Aqui ela é a porta única do portal: não há cadastro próprio e não há “continuar como convidado”. Quem entra foi convidado por alguém de dentro, e o convite já sai com o que a pessoa vai poder abrir. O sistema tem uma superfície sem login — um quiosque de registro de refeição —, e ela é exceção declarada num arquivo de rotas só dela, não esquecimento.

01 O contexto e quem era afetado

Dezoito aplicações, e ninguém usa dezoito.

Carteira de linhas telefônicas, colaboradores CLT e PJ, desligamento, vagas, patrimônio, equipamentos, salas de reunião, cardápio, plano alimentar, facilities. Cada uma nasceu sozinha, para resolver o problema de uma área. Juntas, viraram o portal.

O que um portal interno faz de errado quase sempre é a mesma coisa: ele mostra tudo para todo mundo e confia que a pessoa saiba o que não é dela. O custo aparece nos dois lados. Quem é de RH abre o sistema e encontra dezesseis coisas que não usa. E o patrimônio da empresa, a lista de colaboradores, o histórico de desligamento ficam a um clique de qualquer conta.

Tela O catálogo inteiro, na conta de quem administra

Portal do midomApps na conta de uma administradora: dezoito cartões de aplicação, cada um com as pílulas Ver, Editar e Excluir, e a barra lateral agrupando tudo em Pessoas, Ativos, Outros e Configurações.
Dezoito aplicações em quatro grupos: Pessoas, Ativos, Outros e Configurações. As três pílulas de cada cartão não são decoração — elas dizem o que esta conta pode fazer naquela aplicação. Aqui são as três em todas, porque a conta é de administração. Guarde esta tela: a próxima seção mostra ela de novo, em outra conta.

02 O que eu descobri

Papel não resolve, e o problema é de eixo.

A saída óbvia é criar papéis: administrador, gestor, usuário. Ela quebra na primeira semana de uso real, e quebra porque duas pessoas da mesma área precisam de coisas diferentes.

Descoberta 01. A unidade de acesso não é o papel, é o par pessoa × aplicação. Quem cuida de contratação precisa de Vagas e Colaboradores, mas não de Desligamento. Quem cuida de saída precisa de Desligamento e Colaboradores, mas não de Vagas. Os dois são “RH”. Um papel chamado RH ou dá demais para os dois, ou de menos para os dois, e o jeito de consertar isso com papéis é criar um papel por pessoa, que é o mesmo que não ter papel nenhum.

Descoberta 02. Ver, editar e excluir são perguntas separadas. Recepção precisa ver a lista de equipamentos o dia inteiro e nunca precisa apagar um item dela. Tratar acesso como interruptor liga e desliga junto a leitura e a destruição, e então a escolha vira “nego a informação que a pessoa precisa” ou “dou o botão de apagar para quem só ia consultar”.

O acesso é lista de liberação, nunca lista de bloqueio: aplicação sem registro no mapa da pessoa simplesmente não existe para ela.

Descoberta 03, e é a que decidiu a arquitetura. A diferença entre as duas listas só aparece no dia em que uma aplicação nova entra no sistema: com lista de bloqueio, ela nasce aberta para todo mundo e alguém precisa lembrar de fechar; com lista de liberação, ela nasce invisível e alguém precisa decidir abrir. O erro de esquecer muda de lado, e esse é o assunto inteiro.

Tela A mesma tela do portal, numa conta de RH

Portal do midomApps na conta de um usuário de RH: cinco cartões — Usuários, Colaboradores, Colaboradores PJ, Vagas e Desligamento — com pílulas de ação diferentes em cada um, e a barra lateral com dois grupos apenas.
A mesma URL, o mesmo produto, outra conta. Cinco cartões em vez de dezoito, e a barra lateral com dois grupos em vez de quatro. Repare nas pílulas, uma a uma: Colaboradores tem Ver, Editar e Excluir; Colaboradores PJ, Vagas e Desligamento têm Ver e Editar; Usuários tem só Ver. Não existe cinza, não existe cadeado e não existe página de “peça acesso ao seu gestor” — o que a conta não alcança não aparece. O vazio embaixo dos cartões é parte da prova: não há porta escondida.

03 O modelo de acesso

Três verbos no banco, quatro níveis na tela.

No banco cada linha de permissão é uma pessoa, uma aplicação e três booleanos: can_view, can_edit, can_delete. Oito combinações existem no papel. Só quatro fazem sentido para quem administra, e são essas quatro que a tela oferece.

O que a tela oferece O que vai para o banco, e por quê
Desligado nenhuma linha. Não é uma linha com tudo falso: é ausência, que é o que faz a lista ser de liberação.
Viewer só ver. É onde toda concessão começa, inclusive quando quem concede queria dar mais.
Editor ver e editar. O nível de quem opera o dia a dia da área.
Full ver, editar e excluir. Excluir é o único verbo que destrói registro, e por isso é o que separa Editor de Full.
“Editar sem ver” não é oferecido. É combinação válida no banco e sem sentido no mundo: editar o que não se enxerga. Deixar a tela oferecer isso seria criar um estado que só existe para dar defeito.

A interação segue a frequência da decisão, e não o número de campos. Ligar e desligar uma aplicação é a decisão comum, então é um interruptor. Escolher entre Viewer, Editor e Full é a decisão rara, então é uma pílula que cicla nos três ao ser clicada, e que fica apagada enquanto a aplicação está desligada. Dezoito linhas com três caixas de seleção cada dariam cinquenta e quatro alvos numa coluna só, e a pessoa que administra teria de ler a matriz inteira para responder “o Rafael mexe em Colaboradores?”.

Tela Quem é a pessoa e o que ela alcança, lado a lado

Modal de edição de usuário em duas colunas: à esquerda nome, e-mail, alternador de SuperAdmin, nova senha e usuário ativo; à direita a lista das dezoito aplicações com interruptor e nível, com Colaboradores em Full e Colaboradores PJ, Vagas e Desligamento em Editor.
Duas colunas, e a divisão é proposital: à esquerda quem a pessoa é, à direita o que ela alcança. As duas respostas moram na mesma janela porque quem concede precisa das duas ao mesmo tempo, e “Acesso a todos os apps” no alto é o atalho honesto para o caso em que a resposta é mesmo “tudo”. O alternador roxo de SuperAdmin fica do lado esquerdo, e não na lista: ele não é a décima nona aplicação, é outra categoria de resposta.

Tela A lista de quem tem conta

Tela de Usuários com sete contas: contadores de total, ativos, superadmins e inativos, e uma tabela com tipo, número de aplicações, último acesso e status de cada conta.
A coluna Aplicações é a que faz esta tela valer: ela responde “quanto acesso esta pessoa tem” sem abrir ninguém — 4 apps, 1 app, ou Acesso total em destaque quando é o caso. Último acesso está ao lado de propósito: conta com muito acesso e nenhum uso é o que se revisa primeiro. E o convite pendente aparece na linha da pessoa, não numa tela separada, porque quem foi convidado e não entrou ainda é problema de hoje, não relatório.

04 Delegação

Trazer gente para dentro sem virar administrador.

O pedido que quebra qualquer modelo de permissão bem-comportado é este: quem cuida de Vagas precisa convidar as pessoas que vão acompanhar as vagas. Não é pedido de acesso — é pedido para dar acesso.

As duas respostas fáceis são ruins. Dar a aplicação de Usuários inteira transforma quem cuida de Vagas em administrador do portal, com poder sobre patrimônio e desligamento. Negar joga toda contratação numa fila de chamado que atrasa a única coisa urgente ali, que é a pessoa entrar hoje.

A saída foi um terceiro estado, e ele não é um papel novo: é derivado. Quem pode editar Vagas ganha uma fatia da aplicação de Usuários, calculada na hora a partir da permissão que a pessoa já tem. Nessa fatia dá para convidar alguém — e o convite sai travado em Vagas, no nível Viewer —, e dá para reenviar convite que a própria pessoa mandou. Nada além disso: não edita quem já existe, não muda permissão de ninguém, não vê o resto da lista.

Tela A mesma aplicação de Usuários, na conta de quem cuida de Vagas

Modal de novo usuário na conta de um gestor de Vagas: a coluna de permissões traz uma linha só, Vagas em nível Viewer, e a frase Você só pode conceder acesso ao app Vagas, em modo visualização.
A coluna que tinha dezoito linhas aqui tem uma, e ela não é editável. O limite está dito três vezes na mesma janela, em três lugares em que a pessoa olha em momentos diferentes: no subtítulo do topo, na linha travada em Viewer, e na frase embaixo dela. Repetição aqui não é ruído — é a diferença entre a pessoa entender a regra antes de tentar e descobrir por um erro depois de preencher o formulário. Atrás do modal, os contadores em zero: a fatia também não deixa ver a lista dos outros.

E a tela não é a barreira. O mesmo escopo é recalculado no servidor a cada requisição, e um convite que chegue pedindo qualquer outra aplicação é recusado ali, mesmo tendo saído de uma janela que não oferecia esse botão. O navegador é da pessoa; o que vale é o servidor perguntar de novo.

05 Decisões de design

Três decisões, e a origem de cada uma.

5.1

O menu sai de uma fonte só

Barra lateral, gaveta e barra de baixo leem a mesma lista, que vem do servidor já filtrada pelo que a conta alcança. Nenhuma das três tem catálogo próprio.

O defeito que isso evita é chato e clássico: a aplicação nova entra em dois dos três menus e some no terceiro, e o relato que chega é “no meu celular não tem”. Pior: com catálogo escrito na tela, esconder um item vira decisão de cada página, e basta uma esquecer para o item aparecer para quem não deveria vê-lo.

Vem da descoberta 03

5.2

O celular não recebe o portal encolhido

Quem confere um equipamento na recepção, quem recebe um patrimônio na doca e quem consulta o cardápio antes do almoço faz isso de pé, com uma mão. O portal é desenhado a partir de 375px, com alvo de toque de 44 por 44 em tudo que se clica.

A barra de baixo carrega três aplicações e “Mais”, e as três saem da mesma lista do servidor. A gaveta traz o catálogo inteiro e, no alto dela, quem está logado — porque num portal em que o acesso muda de pessoa para pessoa, “quem sou eu agora” é informação de navegação, não de perfil.

Vem da descoberta 01

Telas O portal e a gaveta, no celular

Portal do midomApps no celular: cartões de aplicação em duas colunas e a barra inferior com Linhas, Usuários, Logs e Mais.
O portal. Os cartões perdem as pílulas de ação: no celular a pergunta é “onde eu vou”, e o que a conta pode fazer se resolve dentro da aplicação.
Gaveta de navegação aberta no celular, com nome e e-mail de quem está logado no topo, a lista completa de aplicações e o botão Sair no rodapé.
A gaveta. Nome e e-mail no alto, catálogo no meio, sair embaixo em vermelho — a única ação destrutiva da navegação, longe do polegar em repouso.
5.3

Um sistema visual, e nenhuma cor escrita à mão

Dezoito aplicações escritas em momentos diferentes viram dezoito produtos se cada uma decidir a própria cor, o próprio espaçamento e o próprio botão. Aqui elas consomem um arquivo só de tokens, e valor de cor escrito dentro de uma tela é proibido por convenção do projeto, não por gosto.

O que isso compra é concreto: a etiqueta de status significa a mesma coisa nas dezoito, verde é ativo e vermelho é destrutivo em todas, e quem aprendeu a ler uma tabela aqui já sabe ler as outras dezessete. É o único jeito de um portal interno não cobrar um treinamento por aplicação.

Vem da descoberta 01

06 Como saiu do papel

Uma origem só, e o banco trazido para casa.

Fastify com Postgres 18 na API, HTML, CSS e JavaScript sem framework no front, e o mesmo processo servindo as duas coisas na mesma origem — o que elimina CORS do sistema inteiro. Sessão em cookie httpOnly com o estado no servidor, senha em bcrypt, e nada de credencial em armazenamento do navegador, onde qualquer script da página alcança.

O banco nem sempre foi próprio. O sistema rodava sobre um banco de terceiro, com automações fora, e o código guardava identificadores opacos daquele serviço no lugar dos nomes das tabelas. Trazer para um Postgres local trocou os identificadores por nomes reais, e a diferença aparece no erro: tabela que não existe agora falha dizendo o nome, em vez de devolver um “não encontrado” silencioso que parecia lista vazia.

A migração deixou uma marca visível, e ela fica. O front tem cerca de duzentos usos da chave primária no formato do serviço antigo, com maiúscula. O Postgres, deixado à vontade, dobraria o nome para minúsculo e quebraria os duzentos. A chave nasceu entre aspas, com um comentário no arquivo do esquema dizendo por quê. Consertar direito seria reescrever as duzentas chamadas para ganhar zero para quem usa o sistema — dívida que se anota e se deixa viva vale mais que refatoração que ninguém pediu.

07 Qualidade e escala

Quem concede acesso também deixa rastro.

Num portal em que uma pessoa pode abrir o patrimônio da empresa para outra, a pergunta que decide a confiança não é se a permissão funciona. É se dá para saber, depois, quem abriu o quê e quando.

Tela A trilha de auditoria

Tela de Logs: tabela com quem agiu, a ação em etiqueta colorida, o recurso, os detalhes da mudança e a data e hora, em ordem decrescente.
A coluna Detalhes é o que separa uma trilha útil de um contador de eventos: ela diz “app_slug: vagas · de: editor · para: full”, e não apenas “alguém editou uma permissão”. Mudança de acesso guarda de onde veio e para onde foi, porque a pergunta que se faz numa auditoria é sempre a diferença. As etiquetas herdam o mesmo código de cor do resto do sistema — verde cria, âmbar edita, vermelho exclui —, então dá para varrer a coluna procurando o vermelho sem ler uma linha.
Garantia O erro que ela transforma em nada
Permissão como lista de liberação aplicação nova que entrou no catálogo e ninguém lembrou de fechar. Ela nasce invisível.
A barreira é a API, não a tela confiar no que o menu escondeu. Cada rota pergunta de novo, e a recusa diz qual verbo faltou em qual aplicação.
Sessão no servidor, cookie httpOnly credencial guardada no navegador, ao alcance de qualquer script da página.
Trilha sem vínculo com a conta apagar o usuário e apagar junto o histórico do que ele fez. O log sobrevive à exclusão de quem agiu.
Limite de tentativas no login varredura de senha contra a única porta do sistema.

A trilha nunca derruba a operação. Gravar log é a última coisa que acontece numa ação e a falha dela é engolida de propósito: um banco de auditoria indisponível não pode impedir alguém de cadastrar um colaborador. É a escolha oposta à de um sistema financeiro, e é deliberada — aqui a trilha serve para reconstruir o passado, não para autorizar o presente.

O que ainda não está resolvido: a faixa de contadores do topo da tela de Logs conta a base inteira onde o rótulo promete “hoje”. É defeito de leitura, não de registro — a trilha embaixo está correta —, e está na fila junto com a revisão periódica de acesso, que hoje depende de alguém abrir a lista e olhar a coluna de último acesso.

O que vem a seguir no produto

Terminar de trazer as aplicações para o banco próprio: o núcleo de acesso, convite e auditoria já está inteiro nele, e cada aplicação volta a funcionar quando a tabela dela chega. Depois disso, a revisão periódica de acesso — hoje é a lista de usuários mais o olho de quem administra, e devia ser uma pergunta que o sistema faz sozinho.

Quer ver o sistema rodando

As telas desta página são do sistema, e o resto dele também sobe. Demonstração ao vivo, do convite ao registro na trilha de auditoria, é conversa de trinta minutos.