Comando: cat projects/multi-company-onboarding.md
Plataforma de onboarding multiempresa com isolamento no banco
Duas empresas de um grupo empresarial usam a mesma plataforma para integrar quem acabou de entrar, no mesmo banco, sem que uma enxergue um único dado da outra. Cada pessoa recebe uma trilha guiada por fases, montada para o seu setor, cargo e contrato, e o painel acompanha o progresso em tempo real sem mandar nenhum dado pessoal pelo canal de tempo real.
abrir demonstraçãosimulação do sistema com dados fictícios · 6 telas
- Papel
- Único engenheiro, do produto à operação
- Período
- jul/2026 – set/2026
- O que eu fiz
Eu: Produto, arquitetura, modelo de dados, regras de acesso no banco, todas as telas do app e do painel, testes, deploy e operação.
Projeto privado, descrito sem identificar cliente, produto ou empresa.
Diagrama
O app do colaborador, com a trilha por fases, e o painel da área de pessoas, onde também atua o operador de plataforma, passam por Server Actions. Os dados ficam num Postgres só, e a fronteira entre as empresas é do banco: RLS em todas as tabelas, chaves compostas com a empresa e gatilhos contra vínculo entre empresas. Os arquivos ficam no Storage, conferidos pelos primeiros bytes e servidos por links assinados que expiram. O Realtime publica só o aviso de que um escopo mudou, e a tela refaz a consulta com as mesmas regras de acesso.
Contexto
Um grupo com duas empresas precisava integrar quem acabava de entrar sem depender de planilhas e de repasses de mão em mão. Cada empresa tem a sua identidade, os seus setores, cargos e contratos, e os dados de uma não podem aparecer para a outra.
O que eu construí
- O app do colaborador. Um início que diz o próximo passo e a prontidão, a trilha por fases (pré-embarque, primeiro dia, primeira semana, 30, 60 e 90 dias), a leitura de cada etapa com vídeo, documento e checklist, a biblioteca de documentos, a escada de carreira e a equipe.
- O painel da área de pessoas. Estrutura da empresa, documentos versionados, framework de carreira, editor de trilhas com prévia idêntica à do colaborador, fichas e acessos, visão geral com time-to-productivity e gargalos por etapa, auditoria e exportação.
- O operador de plataforma. Uma conta transversal que troca de empresa num seletor. A empresa ativa fica no servidor, e todas as regras do banco passam a servir a outra empresa.
- A cor de cada empresa com contraste calculado. O servidor escolhe texto claro ou escuro pelo contraste da WCAG e avisa quando nenhum dos dois atinge 4,5:1.
O que eu faria diferente
Separaria desde o primeiro dia a empresa de origem de uma conta da empresa que ela está gerenciando. Misturar as duas trancou o próprio dono fora do produto num incidente, e a correção exigiu mover a identidade para colunas imutáveis garantidas pelo banco.
Restrições
- Duas empresas no mesmo banco, sem que uma veja um dado da outra, nem por erro de consulta.
- Dado pessoal só vai para o navegador de quem precisa dele, inclusive no tempo real.
- Uma única pessoa técnica para construir e operar.
- Conteúdo montado pela área de pessoas, sem depender de desenvolvedor para cada mudança.
Decisões
Isolamento no banco, e não só na aplicação
- Contexto
- Com duas empresas na mesma base, um filtro esquecido numa consulta bastaria para mostrar os colaboradores de uma para a outra.
- Escolha
- Row-Level Security em todas as tabelas, chaves estrangeiras compostas com a empresa e gatilhos que recusam qualquer vínculo entre empresas diferentes.
- Ganhos
- Um bug na aplicação não atravessa a fronteira entre empresas.
- O isolamento é testado contra as migrations reais, e não contra um mock.
- Custos
- Regras avaliadas linha a linha pesaram no desempenho e precisaram ser reescritas.
Tempo real sem dado pessoal
- Contexto
- A replicação padrão de linhas mandaria nome, e-mail e gestor de cada colaborador para o navegador de todos os administradores.
- Escolha
- O banco publica só um aviso de que algo mudou naquele escopo; a tela refaz a consulta com as mesmas regras de acesso de sempre.
- Ganhos
- Nenhum dado pessoal trafega no canal de tempo real.
- Quando o mecanismo do provedor falhou, deu para trocar o transporte sem mudar a decisão.
- Custos
- Cada aviso custa uma nova consulta, o que exigiu debounce e intervalo mínimo por tela.
Trilhas por composição, com inclusão aditiva
- Contexto
- Cada pessoa precisa da soma certa de conteúdos para o seu setor, cargo e tipo de contrato.
- Escolha
- Trilhas com escopo em camadas, somadas automaticamente pelo perfil, mais a inclusão de alguém pelo nome. Remover uma pessoa de uma trilha não apaga o que ela já concluiu.
- Ganhos
- A área de pessoas monta o onboarding sem pedir código.
- Recolocar alguém traz de volta as etapas já concluídas.
- Custos
- Mais regras para explicar no painel, o que pediu uma prévia de como o colaborador vê.
Stack e por quê
- Next.js 15 e React 19
- App do colaborador e painel no mesmo projeto, com Server Actions.
- TypeScript estrito
- Tipos de ponta a ponta, com acesso a índice verificado.
- Supabase (Postgres, Auth, Storage, Realtime)
- Isolamento por empresa no próprio banco.
- Vitest com PGlite
- Testes de isolamento que rodam as migrations reais num Postgres em processo.
- Playwright
- Fluxos completos com uma empresa de teste criada e removida a cada execução.
- Vercel
- Funções fixadas na mesma região do banco.
Resultados
Row-Level Security habilitada em todas as 25 tabelas, com suítes de isolamento e de escalada de privilégio rodando contra as migrations reais.
repositório privado auditadoMigrations e testes do repositório(Auditoria do repositório privado, set/2026)26 decisões de arquitetura registradas em ADRs, incluindo a correção de decisões anteriores.
repositório privado auditadoRegistro de decisões do projeto(Auditoria do repositório privado, set/2026)Regras de acesso de 130 ms para 4,4 ms na leitura de 223 etapas, depois de reescritas para avaliar uma vez por consulta, com prova de que ninguém passou a ver nada diferente.
declaradoRegistro de desempenho do projeto
Ângulo de segurança
Superfície de ataque
- Painel administrativo com dados pessoais de colaboradores.
- Canal de tempo real entre o banco e os navegadores.
- Upload de documentos para a biblioteca de cada empresa.
- Conteúdo das etapas escrito em markdown pelo painel.
Controles implementados
- Row-Level Security, chaves compostas e gatilhos contra vínculo entre empresas.
- Colunas de identidade imutáveis, garantidas por gatilho no banco.
- Avisos de tempo real que carregam só o escopo, nunca o dado.
- Arquivo validado pela assinatura real dos primeiros bytes, e links assinados que expiram em uma hora.
- Markdown num subconjunto seguro, sem HTML e com esquema de link validado.
- Exportação CSV protegida contra injeção de fórmula, e trilha de auditoria só de inserção.
O que eu testaria hoje
- Troca de empresa pelo operador de plataforma tentando ler dados da empresa anterior.
- Assinatura dos canais de tempo real de outra empresa.
- Upload de arquivo com extensão forjada.
Evidências
- repositório privado auditadoRepositório privado auditado(Auditoria do repositório privado, set/2026)