Skip to content

Privacidade e segurança ​

O Estudar guarda notas, planos e hábitos de estudo — dados pessoais. O desenho parte de uma regra simples: cada pessoa só vê os seus dados, e as chaves nunca chegam ao browser.

Onde ficam os dados ​

OndeO quê
O teu browser (localStorage)Uma cópia de trabalho de tudo, para a app abrir instantaneamente e funcionar offline
Supabase (user_data)Uma linha por utilizador com o mesmo documento, para sincronizar dispositivos
Supabase (ai_usage)Um contador por utilizador e por dia, só se ativares o limite
Fornecedor de IASó o que é preciso para cada pedido (ver abaixo)

Não há analytics nem telemetria.

Quem pode entrar ​

Há três tipos de conta:

VêEditaUsa a IAVê a configuração
Dono (o email do Configurar)o seu plano e progressosimsimsim
Leitoro plano e o progresso do dononãonãonão
Outra conta (criada com os registos abertos)nadanãonãonão
  • Registos fechados. Ao carregares em Configurar com o teu email, a app cria a tua conta de dono e desliga os registos novos no Supabase. Um email desconhecido recebe "Esta instalação não aceita novas contas" e nenhum email é enviado. O ponto Registos do painel de estado fica vermelho enquanto estiverem abertos.
  • Leitores. Em Servidor e chaves → Login → Quem pode entrar juntas leitores pelo email; entram com o código, como tu, e veem a app em modo só leitura: sem timer, sem editar, sem IA, sem configuração.
  • Remover. O botão Remover apaga a linha de leitor e a conta: o acesso acaba logo, mesmo numa sessão aberta, e os teus dados não são tocados.

O que garante isto não é o ecrã, é o servidor:

  • a base de dados só deixa o leitor ler o documento do dono, e só enquanto existir a linha em viewers — que nenhum cliente consegue escrever;
  • o Worker só deixa o dono usar a IA e ver o estado do servidor;
  • a configuração (chaves, publicar, acessos) só existe no servidor local (npx estudar), que só responde a este computador — no endereço publicado essas rotas não existem, nem para o dono.

A app também recusa chaves no campo errado: a chave secreta colada no campo público seria enviada a todos os browsers, por isso nem é guardada nem é servida.

Regras de acesso (RLS) ​

As duas tabelas têm Row Level Security ativa. Em user_data, as quatro operações exigem auth.uid() = user_id: mesmo com a chave pública, ninguém lê ou escreve a linha de outra pessoa. Em ai_usage não há nenhuma regra para clientes — só o servidor, com a chave secreta, lhe acede. O SQL está em supabase/migrations e explicado em Modelo de dados.

Chaves ​

ChaveOnde viveChega ao browser?
Supabase publishable/anonSegredo do Worker; entregue por /api/configSim — foi feita para isso; a RLS protege os dados
Supabase secret/service_roleSegredo do Worker (.dev.vars localmente)Nunca
Chave da IASegredo do Worker (.dev.vars localmente)Nunca
Token pessoal do Supabase (sbp_…)Memória do servidor local (npx estudar), só durante a sessãoNunca e nunca é gravado

.dev.vars e .deploy.json ficam em ~/.estudar (ou, numa cópia do repositório, na pasta do projeto, onde estão no .gitignore). Só a pasta public/ é publicada como ficheiros estáticos, por isso um ficheiro de segredos na raiz nunca é servido.

O que a IA vê ​

PedidoEnviado
Gerar planoNomes e siglas das disciplinas, tipo, carga, ECTS, datas de exame, horas por dia, as tuas notas para a IA, a fatia sugerida, o domínio medido e as bases fracas
Ler o plano de estudosA imagem que escolheste (reduzida para ~1800 px)

A IA nunca recebe o teu email, os teus registos de estudo, exercícios ou respostas. O que ela devolve é tratado como não confiável: é limpo e validado (datas, notas entre 0 e 20, disciplinas existentes) antes de chegar ao ecrã, e tu confirmas antes de guardar.

Cada pedido exige uma sessão válida (o servidor confirma o token no Supabase) e conta para o limite diário, se estiver ativo.

Dispositivos partilhados ​

Ao terminar sessão, a app apaga a cópia local (dados, timer, sessão). Se outra pessoa entrar no mesmo dispositivo, os dados locais de quem lá estava antes nunca são juntados à conta nova.

Conteúdo escrito por ti ​

Nomes de disciplinas, notas e textos são sempre escapados antes de aparecerem no ecrã — um nome como <img onerror=…> aparece como texto.

Proteções técnicas ​

  • Cabeçalhos de segurança em todas as respostas (app e API): Content-Security-Policy estrita — só scripts da própria app, sem scripts inline, sem código de terceiros (o cliente do Supabase vem incluído na app, numa versão fixa) —, frame-ancestors 'none' contra clickjacking, nosniff, Referrer-Policy: no-referrer, HSTS e Permissions-Policy.
  • Dados limpos à entrada e escapados à saída. Tudo o que chega de fora (a tua linha no Supabase, a do dono para um leitor, atualizações em tempo real, cópias de segurança, a resposta da IA) passa por um filtro que só deixa os campos conhecidos, com os tipos e tamanhos certos; e todo o texto é escapado antes de ir para o ecrã.
  • Sessão. O login usa PKCE: os links de email e o Google devolvem um código de uso único, não os tokens da sessão. Terminar sessão apaga os dados deste dispositivo.
  • IA. Só o dono a usa; o limite diário é reservado de forma atómica na base de dados antes de chamar o modelo; pedidos grandes (mais de 8 MB) são recusados antes de tudo.
  • Servidor local. Só responde a este computador (127.0.0.1, verificação do Host contra DNS rebinding), e o ecrã de configuração exige uma chave que muda a cada arranque — vem no link que o npx estudar abre. Uma chave guardada só é enviada para o endereço para que foi escrita: mudar o URL da IA ou do Supabase apaga-a.
  • Base de dados. Além das regras de acesso, as permissões (grants) retiram aos clientes tudo o que não usam, e cada documento tem um limite de 2 MB.
  • Dependências. Versões fixas, GitHub Actions fixadas por commit, Dependabot semanal, e publicação no npm pela CI sem tokens, com aprovação por 2FA.

Reportar um problema de segurança ​

Não abras uma issue pública: usa Security → Report a vulnerability no repositório. Detalhes em SECURITY.md.

Publicado sob a licença MIT.