# Supabase + PostgreSQL — configuração do GRAMA CRM

## O que baixar

Para esta aplicação, **não é necessário instalar PostgreSQL, Docker, pgAdmin ou a CLI do Supabase**. O Supabase hospeda PostgreSQL, autenticação e API. A biblioteca JavaScript já está em `vendor/supabase.js`.

Use VS Code e a extensão Live Server para abrir o CRM. Se já usa Live Server, não precisa baixar mais nada para começar.

## 1. Criar o projeto

1. Entre em https://supabase.com/dashboard e crie uma conta.
2. Crie uma organização e clique em **New project**.
3. Escolha um nome, por exemplo `grama-crm`, uma senha forte para o banco e a região disponível mais próxima da sua equipe.
4. Aguarde o projeto ficar pronto. Guarde a senha do banco; ela não será colocada no frontend.

## 2. Criar as tabelas e permissões

1. No projeto, abra **SQL Editor** e crie uma consulta.
2. Copie todo o conteúdo de `supabase/schema.sql` e execute.
3. O script cria `crm_workspaces` (empresas), `crm_members` (usuários da equipe) e `crm_records` (orçamentos e compromissos em JSONB), com regras de acesso por empresa.
4. Execute esse script somente uma vez por projeto. Ele não apaga dados existentes.

## 3. Criar o primeiro usuário

1. Abra **Authentication → Users**.
2. Use a opção para adicionar um usuário com email e senha. Confirme o email no painel quando necessário.
3. Crie os demais usuários da equipe da mesma maneira. A aplicação oferece login para contas existentes; não oferece cadastro público.

## 4. Cadastrar a empresa e a equipe

No SQL Editor, execute:

```sql
insert into public.crm_workspaces (name)
values ('Sultham Grama Sintética')
returning id;
```

Copie o UUID retornado. Esse é o `workspaceId` da aplicação. Em outra consulta, substitua `ID_DA_EMPRESA` pelo UUID e os emails pelos usuários criados:

```sql
insert into public.crm_members (workspace_id, user_id)
select 'ID_DA_EMPRESA'::uuid, id
from auth.users
where email in ('seu-email@empresa.com', 'colega@empresa.com')
on conflict do nothing
returning workspace_id, user_id;
```

Confira se foi retornada uma linha para cada usuário. Usuários que ainda não foram criados em Authentication não serão adicionados. Todos os membros dessa empresa poderão consultar, criar, editar e excluir os seus orçamentos e compromissos. Usuários de outras empresas não terão acesso.

## 5. Configurar a aplicação

1. No painel do projeto, copie a **Project URL** (na conexão/API do projeto) e a chave **publishable** em **Settings → API Keys**. Projetos antigos também podem usar a chave pública `anon`.
2. Abra `config.js` e preencha:

```js
window.GRAMACRM_CONFIG = {
  storageMode: 'supabase',
  timeZone: 'America/Sao_Paulo',
  supabaseUrl: 'https://SEU-PROJETO.supabase.co',
  supabasePublishableKey: 'sb_publishable_SUA_CHAVE_PUBLICA',
  workspaceId: 'UUID_DA_EMPRESA'
}
```

Use somente a chave pública. Chaves `service_role`, `sb_secret_...` e a senha do PostgreSQL não devem ser colocadas no navegador. O acesso aos dados é limitado pela autenticação e pelas políticas RLS no banco.

## 6. Abrir e testar

1. Abra `index.html` com Live Server e atualize a página.
2. Entre com o email e a senha cadastrados.
3. Salve um orçamento e um compromisso. Confira os registros em `crm_records` no Table Editor do Supabase.
4. Para verificar o compartilhamento, abra outro navegador, entre com um colega cadastrado na mesma empresa e confira os registros.
5. Use **Recarregar dados** para buscar alterações feitas pela equipe. Essa ação descarta alterações não salvas nos formulários. Não há atualização em tempo real nesta versão.

A geração de PDF continua no navegador. Os campos do orçamento e da agenda ficam no PostgreSQL; PDFs não são enviados ao Supabase Storage.

## Dados anteriores e modo local

Dados que já estavam no localStorage foram preservados. Eles não são enviados automaticamente para uma empresa na nuvem. Para consultar a versão local, configure `storageMode: 'local'`, use a mesma origem do Live Server e recarregue a página. A transferência desses dados deve ser feita explicitamente; esta versão não oferece um importador automático.

No modo Supabase, falhas de conexão não redirecionam gravações para o localStorage. O sistema informa a falha e mantém os dados do formulário. Login é obrigatório e apenas membros cadastrados podem acessar a empresa.

## Verificações incluídas

- `tests/test_database.mjs`: executa o esquema em PostgreSQL embutido (PGlite), verificando RLS, compartilhamento entre membros, bloqueio de outra empresa e de visitantes, controle de revisões e rollback de transações.
- `tests/test_supabase_ui.py`: login, carregamento, gravação, falhas e logout usando respostas simuladas do Supabase.
- `tests/test_crm.py`: modo local, agenda, PDF e layout.

As ferramentas de teste em `.tools` e `.tools-node` não são necessárias para usar a aplicação. A configuração de um projeto Supabase real ainda precisa ser feita seguindo este guia.

## Documentação oficial

- Criar um projeto: https://supabase.com/docs/guides/getting-started
- Chaves públicas: https://supabase.com/docs/guides/getting-started/api-keys
- Login: https://supabase.com/docs/reference/javascript/auth-signinwithpassword
- Permissões no PostgreSQL: https://supabase.com/docs/guides/database/postgres/row-level-security
## Cadastro de usuários pela tela do CRM

A tela agora oferece **+ Novo usuário** para administradores. O formulário pede nome, email, senha inicial e confirmação. A conta é criada pelo servidor e incluída na mesma empresa como membro; a sessão do administrador é mantida. Não há envio automático de email neste fluxo. O novo usuário entra com a senha definida pelo administrador. Contas já existentes não são alteradas nem vinculadas automaticamente.

### Ativar no projeto existente

1. Execute `supabase/002_user_registration.sql` no SQL Editor. Não execute novamente o schema.sql original.
2. Promova sua conta a administrador. Substitua os dois valores abaixo:

```sql
update public.crm_members
set role = 'admin'
where workspace_id = 'ID_DA_EMPRESA'::uuid
  and user_id = (select id from auth.users where email = 'SEU_EMAIL')
returning workspace_id, user_id, role;
```

Confira que o comando retornou sua conta. Outros membros continuam com `role = 'member'` e não podem criar contas nem alterar permissões.

3. No Supabase, abra **Edge Functions → Deploy a new function → Via Editor**.
4. Nomeie a função exatamente **create-team-user**, substitua o código do editor pelo conteúdo de `supabase/functions/create-team-user/index.ts` e publique.
5. Configure essa função com **Verify JWT desativado** (na configuração da função). A autenticação é feita explicitamente pelo código com `auth.getUser(token)`, que valida a sessão e verifica o papel de administrador na empresa. Isso também funciona com os tokens das novas chaves de assinatura do Supabase. O arquivo `supabase/config.toml` já define essa opção para publicação por CLI.
6. As variáveis `SUPABASE_URL` e `SUPABASE_SERVICE_ROLE_KEY` são variáveis padrão do ambiente Edge Functions do Supabase. Elas são usadas apenas no servidor; nunca copie a chave administrativa para config.js ou para o código do navegador.
7. Atualize a aplicação e saia/entre novamente. O botão **+ Novo usuário** aparecerá na barra superior para sua conta de administrador.

A função verifica a sessão e a permissão antes de criar contas. O vínculo com a equipe é feito por um gatilho na mesma transação de criação do usuário, evitando contas sem vínculo se a empresa não existir. A autorização usa a tabela crm_members, nunca campos enviados no formulário. Novas contas são confirmadas pelo administrador e podem entrar imediatamente.

Se o botão não aparecer, confira se a migração foi executada e se sua conta está como admin na empresa indicada em config.js. Se houver falha ao cadastrar, confira se o nome da função, a publicação e a configuração Verify JWT estão corretos.

Referências oficiais:
- https://supabase.com/docs/reference/javascript/auth-admin-createuser
- https://supabase.com/docs/guides/functions/quickstart-dashboard
- https://supabase.com/docs/reference/javascript/auth-getuser

Testes adicionais: node tests/test_registration.mjs (função com Auth simulado), node tests/test_database.mjs (gatilho, atomicidade e bloqueio de promoção por membros) e python tests/test_supabase_ui.py (formulário e preservação da sessão). A função não foi publicada no seu projeto automaticamente.
## Perfis de acesso: Admin, Analista e Instalador

| Perfil | Módulos | Cadastro de usuários |
| --- | --- | --- |
| Admin (`admin`) | Todos | Permitido |
| Analista (`analyst`) | Todos | Somente Admin cadastra usuários |
| Instalador (`installer`) | Somente Agenda | Não permitido |

Para ativar no projeto existente:

1. Execute `supabase/003_access_profiles.sql` no SQL Editor, após a migração 002. Essa atualização converte os antigos perfis `member` para `analyst` e mantém os administradores.
2. Publique novamente a função `create-team-user` usando a versão atual de `supabase/functions/create-team-user/index.ts`.
3. Saia e entre novamente no CRM. No formulário **Novo usuário**, o administrador agora escolhe o perfil.

Para alterar o perfil de um usuário existente, execute no SQL Editor, substituindo os dados:

```sql
update public.crm_members
set role = 'installer' -- admin, analyst ou installer
where workspace_id = 'ID_DA_EMPRESA'::uuid
  and user_id = (select id from auth.users where email = 'EMAIL_DO_USUARIO')
returning user_id, role;
```

O Instalador abre diretamente a Agenda e os outros itens do menu ficam ocultos. A navegação por hash para módulos restritos também é bloqueada. O PostgreSQL limita consultas e gravações desse perfil a registros de agenda, inclusive em chamadas diretas à API/RPC. Orçamentos não são carregados para esse perfil e o vínculo com orçamento fica oculto no formulário. A agenda mantém suas ações de cadastro, edição e exclusão.

A mudança de perfil é aplicada ao entrar novamente ou usar Recarregar dados. Execute as migrações na ordem 002 → 003; não reaplique 002 após 003, pois a versão antiga do gatilho usa o perfil member. A migração 003 pode ser reaplicada.
## Falha ao verificar permissões no cadastro

Se a função responder “Não foi possível verificar as permissões. Confira a atualização do banco.”, confira os Logs da função create-team-user. Uma causa possível é a falta de SELECT para service_role em crm_members: projetos com os novos padrões do Supabase exigem grants explícitos mesmo para esse papel.

Execute `supabase/004_server_registration_access.sql` no **SQL Editor**. A migração concede apenas o acesso de leitura necessário ao servidor e pode ser reaplicada. Não precisa republicar a função para aplicar essa correção. Tente cadastrar novamente. Se a falha continuar, confira se a coluna role existe (migrações 002 e 003) e consulte os Logs da função antes de alterar outras permissões.

Referência: https://supabase.com/changelog/45329-breaking-change-tables-not-exposed-to-data-and-graphql-api-automatically


## Ordens de trabalho
Execute `supabase/005_work_orders.sql` após as migrações anteriores. A agenda permite abrir uma ordem, selecionar um instalador cadastrado na empresa e informar a data/hora de início em São Paulo. O instalador seleciona seu próprio nome. O encerramento registra automaticamente o horário do servidor. O histórico identifica o tipo da atividade, responsável e usuário que registrou a ação. Ordens encerradas podem ser consultadas marcando “Mostrar ordens encerradas”. No modo local, `config.installers` pode conter uma lista de `{id,name}`; o horário de encerramento usa o relógio do navegador.


Execute `supabase/006_installer_no_creation.sql` para bloquear a criação de compromissos pelo instalador, inclusive via API. Admin e analista continuam criando compromissos. Início e encerramento das ordens existentes permanecem disponíveis.


Execute `supabase/007_required_closing_notes.sql` para exigir observação no encerramento (até 5000 caracteres). A observação fica salva na ordem e no histórico.


## Ficha completa de Ordem de Serviço
Execute `supabase/008_complete_work_orders.sql` após a migração 007 e publique `work-orders.js`, `agenda.js`, `database.js`, `crm.js`, `index.html` e `styles.css`. A migração cria o bucket privado `crm-work-order-media`, com acesso por empresa e limite de 5 MB por foto. As fotos são organizadas antes/durante/depois (10 por etapa), redimensionadas no navegador e consultadas por URLs temporárias. Salvar rascunho preserva descrição, fotos, observação e aceite sem concluir a OS. O cancelamento exige motivo. Concluir exige início prévio, observação, nome do cliente e assinatura desenhada; data/hora de conclusão e aceite vêm do servidor. O aceite é um registro de assinatura desenhada, sem certificação digital. Fotos removidas da ficha permanecem no bucket para evitar apagar arquivos já referenciados por outras versões; uploads não salvos também podem permanecer no bucket. Registros encerrados antes desta migração continuam consultáveis.
