Skip to content

Persistência de dados ​

Regra central ​

Todo acesso ao banco de dados passa pelo app backoffice.

Nenhum outro app do monorepo deve ter drizzle.config.ts, conexão direta com PostgreSQL ou migrations próprias. Dados são lidos e gravados exclusivamente via HTTP para os endpoints do backoffice.

Por que centralizar? ​

Problema sem centralizaçãoSolução com backoffice centralizado
Migrations desconexas entre appsUm único histórico de migrations em ordem garantida
Schema duplicado / divergenteUm schema Drizzle canônico para toda a base
Scripts setup:local múltiplosUm único pnpm setup:local para toda a infraestrutura
Conflitos de drizzle_migrationsTabela de controle compartilhada, sem duplicatas

Diagrama ​

graph TD
    subgraph Calculadoras
        A[prev-tc]
        B[prev-rvt]
        C[prev-atrasados]
        D[prev-rpps]
    end

    subgraph APIs de cálculo
        E[prev-api]
        F[rmi-api]
    end

    subgraph Backoffice
        G[APIs públicas /indices/api/v1]
        H[APIs públicas /apps/api/v1]
        I[Painel privado e serviços internos]
        N[(PostgreSQL)]
    end

    subgraph Apps full stack
        O[base-servicos — proxies server-side]
    end

    A -->|useFetch| G
    B -->|useFetch| G
    C -->|useFetch| G
    D -->|useFetch| G
    E -->|HTTP| G
    F -->|HTTP| G
    A -->|useFetch| O
    O -->|HTTP autenticado| I
    G --> N
    H --> N
    I --> N

Estrutura de endpoints ​

Públicos (CORS habilitado) ​

PrefixoResponsabilidade
GET /indices/api/v1/**Indexadores monetários, reajustes, tábua de mortalidade
GET /apps/api/v1/calculadorasCatálogo público de calculadoras e URLs por ambiente
POST /apps/api/v1/exchangeCriar token de exchange (X-Api-Key)

Persistência de cálculos salvos, pastas e preferências não é pública. A central arquivos-online e as calculadoras full-stack chamam proxies server-side herdados de base-servicos. Esses proxies, por sua vez, chamam o backoffice por endpoints internos autenticados por header proprietário. Há também um bloco de rotas administrativas, isolado por gateway/firewall e protegido por sessão admin verificada — esse bloco é exclusivo do painel e nunca é acessado por outras apps.

Persistência no navegador ​

Cada aba trabalha em um workspace isolado. Antes de o Pinia hidratar as stores, a camada base-ui carrega do IndexedDB os estados daquele workspace para um cache síncrono. Uma fila preserva a ordem das escritas, e presença/heartbeat evitam que duas abas assumam acidentalmente o mesmo workspace.

O IndexedDB é o armazenamento principal e permite recuperação depois de reload, fechamento do navegador ou reinício do computador. Se estiver indisponível, o sistema tenta sessionStorage e depois memória da aba. Esses fallbacks mantêm o trabalho durante a sessão corrente, mas não garantem recuperação após encerramento; por isso o aviso ostensivo permanece visível.

Há dois ciclos locais distintos:

  • um Rascunho local preserva automaticamente um Cálculo offline assim que aparecem dados relevantes;
  • um Rascunho de recuperação preserva alterações de um Arquivo online ainda não confirmadas pela nuvem, mantendo identificador, revisão-base, geração e prova de completude.

O Rascunho de recuperação não aparece na lista de Rascunhos locais. Em uma queda de rede, ele permite continuar editando na mesma aba e volta a sincronizar quando a conexão retorna. Depois de um reinício, a abertura do Arquivo online oferece retomar a cópia local ou descartá-la e usar a versão da nuvem. Uma cópia incompleta é preservada, mas não entra em autosave e não é transformada em .calc aparentemente completo.

Ao exportar ou abrir um arquivo .calc, o vínculo de nuvem é sempre removido. A cópia passa a ser um Cálculo offline independente; salvá-la depois na nuvem cria outro Arquivo online.

Abrir um arquivo .calc tem quatro etapas, nesta ordem: conferir o envelope, migrar, validar e hidratar. Confere-se que o arquivo se identifica como um cálculo da plataforma e que pertence àquela calculadora; ele é levado ao formato atual pela cadeia de migradores da calculadora; seu conteúdo é validado; e só então substitui o cálculo em edição. Nenhum dado da aba é descartado antes de a validação passar. As calculadoras e os endpoints que recebem arquivo usam o mesmo percurso e, portanto, aceitam o mesmo arquivo.

Isso separa dois modos de falha. Um arquivo malformado é aquele cujo envelope sequer identifica um cálculo. Um arquivo recusado é íntegro e foi migrado, mas contém um valor que a calculadora não aceita: a mensagem indica o registro e o parâmetro, e o cálculo aberto permanece inalterado.

Cálculos online usam controle otimista por revisao: o registro salvo no backoffice incrementa a revisão a cada atualização. Ao salvar, a calculadora envia a revisão que abriu; se outra aba ou outro usuário já tiver salvo uma versão mais nova, o backoffice retorna 409 Conflict. A interface oferece salvar as alterações como novo Arquivo online ou descartá-las e usar a versão da nuvem.

Links de compartilhamento usam token opaco de alta entropia com lookup direto no banco.

Administrativas (sem CORS, mesmo domínio) ​

PrefixoResponsabilidade
GET /admin/**Leitura de dados para o painel
POST /admin/**Edição com justificativa e trilha de auditoria
GET /admin/_painel/**Interface web administrativa (CSR)

Como outros apps consomem dados ​

Índices monetários (ex: base-calculadora) ​

typescript
// Em apps/base-calculadora/app/plugins/00.indices.ts
const dados = await $fetch('/api/v1/tabela', {
  baseURL: useRuntimeConfig().public.indicesApiUrl,
})

Exchange de dados PrevJud ​

typescript
// 1. App back-end cria token (servidor → servidor, com X-Api-Key)
const { token } = await $fetch('<url-interna-do-backoffice>/apps/api/v1/exchange', {
  method: 'POST',
  headers: { 'X-Api-Key': process.env.EXCHANGE_KEY },
  body: { app: 'rgps.beneficios', payload: { numeroProcesso, cnis } },
})

// 2. Usuário é redirecionado para `urlAbrir`; a calculadora consome o token
//    por um proxy server-side autenticado:
const dados = await $fetch('<rota-server-side-da-calculadora>')

Banco de dados ​

O PostgreSQL é compartilhado por todos os domínios em um único banco. As migrations são aplicadas em sequência pelo backoffice e cobrem famílias de tabelas para: indexadores e taxas (com auditoria por linha), administração e log de acessos, cálculos em nuvem (com soft delete e controle otimista), pastas e grupos de compartilhamento, comunicados e documentos legais, telemetria de uso e cadastro de API keys (armazenadas como hash).

Cada tabela de dados tem uma tabela *_audit correspondente, com colunas atualizadoEm, atualizadoPor (CPF do operador ou SISTEMA), tipoAlteracao (enum) e justificativa (obrigatória em operações manuais).

O catálogo literal de tabelas e a sequência completa de migrations versionadas ficam restritos à documentação interna do projeto.

Inicialização local ​

bash
cd apps/backoffice
cp .env.example .env
# Preencher as variáveis obrigatórias no .env
pnpm setup:local

O script setup:local verifica o Docker, valida o .env, sobe os containers, aplica migrations, popula o banco com dados iniciais e atualiza os índices com dados atuais do Banco Central e IBGE.