-- ---------------------------------------------------------------------------
-- Papéis de acesso ao banco (F1.9).
--
-- ESTE ARQUIVO NÃO RODA SOZINHO. As senhas chegam como variáveis do psql
-- (`:'senha_app'`), posta por scripts/criar-papeis.sh a partir
-- do ambiente. Sem elas o psql para na primeira linha que as usa.
--
-- A substituição é do psql, e não textual, de propósito. A primeira versão
-- usava `sed` sobre marcadores, e errava com senha que contivesse `/`, `&` ou
-- `\` -- os dois últimos EM SILÊNCIO, gravando senha diferente da digitada.
-- `:'variavel'` produz um literal SQL corretamente escapado, sem camada de
-- texto no caminho.
--
-- (A extensão `.modelo` fica como aviso. Vem de um erro real: em 25/08/2026 o
-- scripts/anonimizar.sql foi rodado direto e gravou o marcador como hash de
-- senha em todos os usuários.)
--
-- IDEMPOTENTE: rodar de novo não duplica nem derruba nada.
--
-- ---------------------------------------------------------------------------
-- POR QUE ESTE ARQUIVO EXISTE
--
-- Até aqui, tudo — aplicação, carga, conferência — conectava como `franquiabv`,
-- que é **superusuário**. E superusuário **ignora Row-Level Security**, mesmo
-- com `FORCE`. Medido em 27/08/2026:
--
--     sessão nova, sem declarar inquilino:
--       franquiabv (superusuário) ....... 61 unidades  (RLS não é avaliado)
--       papel comum ..................... ERROR: unrecognized configuration
--                                         parameter "app.inquilino_id"
--
-- Ou seja: as 75 políticas de isolamento escritas na F1.3 **não estavam em
-- vigor**. Elas passam a valer no instante em que quem conecta deixa de ser
-- superusuário — que é o que este arquivo faz.
--
-- Repare no segundo caso: a falta do parâmetro dá **erro**, não silêncio. Isso
-- é bom, e é o oposto do que eu supunha: uma configuração faltando derruba a
-- consulta em vez de devolver uma tela vazia que parece falta de dado.
-- ---------------------------------------------------------------------------

\set ON_ERROR_STOP on

-- ---------------------------------------------------------------------------
-- 1. bvip_app — a aplicação.
--
-- Lê e escreve, e NÃO é superusuário: é essa a diferença que faz o RLS existir.
-- ---------------------------------------------------------------------------

DO $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'bvip_app') THEN
        CREATE ROLE bvip_app LOGIN;
    END IF;
END
$$;

ALTER ROLE bvip_app WITH PASSWORD :'senha_app' NOSUPERUSER NOCREATEDB NOCREATEROLE NOBYPASSRLS;

GRANT CONNECT ON DATABASE :"banco" TO bvip_app;
GRANT USAGE ON SCHEMA bvip TO bvip_app;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA bvip TO bvip_app;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA bvip TO bvip_app;

-- Tabela criada depois disto já nasce acessível. Sem esta linha, o próximo
-- `CREATE TABLE` deixa a aplicação sem permissão e o sintoma aparece só em
-- produção, na primeira vez que a tela nova é aberta.
ALTER DEFAULT PRIVILEGES IN SCHEMA bvip
    GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO bvip_app;
ALTER DEFAULT PRIVILEGES IN SCHEMA bvip
    GRANT USAGE, SELECT ON SEQUENCES TO bvip_app;

ALTER ROLE bvip_app SET search_path = bvip, public;

-- ---------------------------------------------------------------------------
-- 2. O que ninguém pode
--
-- `PUBLIC` é todo mundo, inclusive papel criado depois. Por padrão o
-- PostgreSQL deixa `PUBLIC` criar objetos no schema `public` — que é como um
-- papel só-leitura acaba conseguindo gravar em algum canto.
-- ---------------------------------------------------------------------------

REVOKE CREATE ON SCHEMA public FROM PUBLIC;
REVOKE ALL ON SCHEMA bvip FROM PUBLIC;
REVOKE ALL ON DATABASE :"banco" FROM PUBLIC;
