Vibe Coding — a tua primeira app sem saber programar — 7. Base de dados: os teus dados em todo o lado

19 min read min de lecture
Capítulo 07

Base de dados: os teus dados em todo o lado

Capítulo 7 de 10 · 70%

Objetivos deste capítulo

  • Compreender o que é uma base de dados e como se organiza
  • Migrar a tua app do localStorage para uma verdadeira base online
  • Garantir que cada utilizador só vê os seus próprios dados

A peça em falta

Os alunos do Tom ligam-se agora com o email — mas a Lina, fiel ao posto, assinala que os hábitos da biblioteca continuam a não estar no telemóvel dela. Normal: a autenticação diz quem está ali, mas os dados, esses, ainda vivem no localStorage de cada aparelho. Falta um lugar central onde arrumar os hábitos de cada conta: uma base de dados online. É o trabalho deste capítulo, e é provavelmente o mais transformador do curso — depois dele, a tua app deixa de ser um gadget de navegador para se tornar um verdadeiro serviço.

A mudança de lógica cabe numa frase: em vez de cada navegador guardar a sua própria cópia dos dados, todos os aparelhos leem e escrevem no mesmo sítio, um servidor de base de dados. A tua app torna-se um balcão: mostra o que a base diz, e regista lá cada ação. A Lina marca «Leitura» no telemóvel; a marcação parte para a base; no dia seguinte na biblioteca, a app pergunta à base «mostra-me os hábitos da Lina» e está tudo lá.

Uma base de dados, em concreto

Se já abriste uma folha de cálculo, conheces 80 % do conceito. Uma base de dados é um conjunto de tabelas; cada tabela parece uma folha de cálculo com colunas (os tipos de informação) e linhas (os registos). Cada linha possui um identificador único (id), e — é a parte mágica — uma linha pode apontar para outra: a coluna user_id de um hábito diz «este hábito pertence a este utilizador». É o que se chama uma relação, e é ela que liga limpamente os dados às contas do capítulo 6.

O modelo do Tom é minimalista: uma tabela habits (uma linha por hábito, com o nome e o user_id do dono) e uma tabela checks (uma linha por dia marcado, ligada ao seu hábito). Duas tabelas, quatro colunas úteis cada — resiste à tentação de prever dez «para mais tarde». Não precisas de escrever tu mesmo o que se segue, mas deves saber lê-lo: é a linguagem SQL que a IA gerará para criar as tabelas.

sql
create table habits (
  id uuid primary key default gen_random_uuid(),
  user_id uuid references auth.users not null,
  name text not null,
  created_at timestamptz default now()
);

create table checks (
  id uuid primary key default gen_random_uuid(),
  habit_id uuid references habits not null,
  day date not null
);

Lê-o como quase-português: «cria uma tabela habits; cada linha tem um id único, pertence a um utilizador, tem um nome, e guarda a data de criação». A linha references auth.users é a relação: impossível criar um hábito órfão, sem dono. Pede sempre à IA que te explique o esquema que propõe — é nestas leituras comentadas que mais aprendes.

flowchart LR
  T["Telemóvel da Lina"] -->|"Marca um hábito"| B["Base de dados Supabase"]
  O["Computador da biblioteca"] -->|"Mesma conta"| B
  B -->|"Devolve os mesmos dados"| T
  B -->|"Devolve os mesmos dados"| O
Um único lugar de verdade: todos os aparelhos de uma mesma conta leem e escrevem na mesma base.

A segurança primeiro: cada um vê os seus dados

Pergunta crucial antes de escrever o mínimo dado: o que impede a app da Lina de ler os hábitos do Karim? Resposta: nada, por omissão. Cabe-te a ti exigi-lo, através do que o Supabase chama Row Level Security (RLS) — a «segurança ao nível das linhas». O princípio é límpido: cada tabela recebe uma regra do tipo «um utilizador só pode ler e modificar as linhas cujo user_id é o seu». A própria base recusa tudo o resto, faça o que fizer o código da app.

Sem a RLS ativada, qualquer utilizador ligado pode tecnicamente ler os dados de todos os outros — bastam algumas manipulações na consola do navegador. Exige sempre, palavra por palavra, no teu prompt: «ativa a Row Level Security com uma regra por tabela: cada utilizador só acede às suas próprias linhas». É inegociável.

Migrar sem perder nada

Os teus utilizadores existentes têm dados no localStorage deles: deitá-los fora seria fazê-los pagar a tua subida de nível. O plano de migração é clássico e elegante: no primeiro login de um utilizador, a app verifica se restam dados locais, e propõe-lhe importá-los para a conta dele. Depois da importação bem-sucedida, o localStorage é limpo, e a base torna-se a única fonte de verdade. Eis o prompt completo do Tom — repara que é ele próprio que divide o trabalho em etapas:

PROMPT
Faz evoluir a minha app de acompanhamento de hábitos do localStorage para o Supabase.
Contexto: a autenticação por link mágico já funciona (capítulo anterior).
Etapas que quero, por esta ordem:
1. cria as tabelas habits e checks, ligadas ao utilizador ligado via user_id
2. ativa a Row Level Security com uma regra por tabela: cada utilizador só lê e modifica as suas próprias linhas
3. faz a app ler e escrever na base em vez do localStorage: adição, eliminação, marcação, cálculo do streak
4. no primeiro login de um utilizador que ainda tenha dados locais, propõe-lhe importá-los para a conta dele, e depois limpa o localStorage
Faz UMA etapa de cada vez e espera que eu confirme o meu teste antes de passar à seguinte.
A cada etapa, explica-me em duas frases o que fizeste.

Este prompt condensa tudo o que aprendeste: a visão completa anunciada à partida (capítulo 3), a divisão em etapas testáveis (capítulo 4), a segurança exigida explicitamente, e o pedido de explicação que transforma cada etapa numa lição. Quando a IA acabar a etapa 1, vai ver as tuas tabelas no painel de controlo do Supabase (separador «Table Editor»): ver os teus dados «a sério», na interface do serviço, torna todo o conceito concreto.

Testar a persistência a sério

A migração toca no coração da tua app: o teste deve estar à altura. Não te contentes com «parece que funciona» — desenrola um cenário completo, com várias contas e vários aparelhos. Eis a checklist do Tom:

  • Persistência: marca um hábito, recarrega a página, fecha o navegador, volta — a marcação continua lá.
  • Multi-aparelhos: marca no telemóvel, recarrega no computador — a marcação aparece.
  • Isolamento: cria duas contas de teste, adiciona hábitos diferentes em cada uma, e verifica que nenhuma vê os dados da outra.
  • Migração: num navegador com dados locais antigos, liga-te e verifica que a importação é proposta, e depois que tudo chegou à conta.
  • Logout: desligado, a app não deve mostrar nenhum dado.

Para o teste de isolamento — o mais importante — faz-te ajudar ativamente. A IA é excelente a gerar cenários de teste mais espertos do que os teus:

PROMPT
Criei duas contas de teste: aluno1@teste.pt e aluno2@teste.pt.
Dá-me um cenário de teste passo a passo para verificar que:
- cada conta só vê os seus próprios hábitos e marcações
- uma marcação feita num aparelho aparece noutro aparelho da mesma conta após recarregamento
- um utilizador desligado não vê nenhum dado
Explica-me depois como verificar diretamente no painel de controlo do Supabase que cada linha de habits tem o user_id certo, e como testar que a Row Level Security bloqueia mesmo um acesso cruzado.
Ganha o hábito de abrir o painel de controlo do Supabase em paralelo com os teus testes: vês as linhas aparecer em direto quando marcas na app. É a melhor forma de compreender o que se passa «por trás» — e de detetar imediatamente uma linha com um user_id em falta ou errado.

Latência e estados de carregamento

Uma mudança subtil acompanha a migração: os teus dados já não são instantâneos. Com o localStorage, estava tudo no local; com uma base online, cada leitura e cada escrita faz uma ida e volta de rede de algumas dezenas ou centenas de milissegundos. Na maior parte das vezes, é impercetível — mas numa ligação lenta, uma lista que demora um segundo a aparecer sem nenhum indicador dá a impressão de uma app partida. Pede à IA que adicione estados de carregamento («um pequeno indicador enquanto os hábitos carregam») e uma mensagem clara se a rede falhar («impossível contactar o servidor, tenta de novo»).

É também o momento de aprender um reflexo de profissional: testar a tua app simulando uma rede má. Nas ferramentas de desenvolvimento do navegador (F12), o separador «Network» permite limitar a ligação («Slow 3G»). Trinta segundos de teste nestas condições mostram-te exatamente o que viverão os teus utilizadores com pior ligação — e o que é preciso melhorar.

O plano gratuito do Supabase cobre muito largamente uma app como a do Tom: 500 MB de base de dados são anos de marcações de hábitos. Não te preocupes com os limites antes de teres centenas de utilizadores ativos — e nesse dia, será um bom problema para ter.

O que o Tom acabou de ganhar

Mede o caminho: a app do Tom tem agora contas, dados centralizados, protegidos linha a linha, e sincronizados entre todos os aparelhos. A Lina marca na biblioteca, verifica o streak no autocarro, e tudo é coerente. Mas há um ganho mais discreto: o Tom dispõe agora de um verdadeiro backend. Todas as funcionalidades «impossíveis» de antes — enviar emails, aceitar um pagamento, ligar IA — tornam-se acessíveis, porque têm finalmente um sítio onde se apoiar. É exatamente o programa do próximo capítulo.

🛠️ É a tua vez

Contexto

O Tom dedica o fim de semana à migração: é o trabalho mais estruturante desde o início do projeto, e quer fazê-lo de forma limpa — tabelas, segurança, migração dos dados existentes, testes multi-contas. Segue o mesmo caminho na tua app, etapa a etapa, sem nunca avançar antes de validar a etapa em curso. No fim, os teus dados seguir-te-ão para todo o lado.

Instruções

  1. Descreve à IA o teu modelo de dados em português («uma tabela para…, uma tabela para…») e pede-lhe o esquema SQL comentado.
  2. Envia o prompt de migração exigindo explicitamente a Row Level Security, uma etapa de cada vez.
  3. Depois da etapa das tabelas, abre o painel de controlo do Supabase e verifica a estrutura delas no Table Editor.
  4. Desenrola a checklist completa: persistência, multi-aparelhos, isolamento entre duas contas de teste, migração dos dados locais.
  5. Pede a adição de estados de carregamento e de uma mensagem de erro de rede, e depois testa em modo «Slow 3G» via F12.
  6. Commit final: «migração da base de dados completa e testada» — é um marco importante do teu projeto.
Dica — Se a app mostrar uma lista vazia depois da migração quando a base contém linhas, é quase sempre a RLS a bloquear (regra em falta ou mal escrita). Dá à IA a mensagem de erro da consola E a tua regra RLS atual: o diagnóstico é imediato.

Em resumo

  • Uma base de dados online é o lugar central onde todos os aparelhos leem e escrevem os mesmos dados.
  • Tabelas, colunas, linhas: uma base parece uma folha de cálculo, com identificadores únicos e relações.
  • A coluna user_id liga cada dado ao seu dono — é a ponte com a autenticação do capítulo 6.
  • A Row Level Security é inegociável: sem ela, cada utilizador pode tecnicamente ler os dados dos outros.
  • Migra sem perdas: propõe a importação dos dados locais no primeiro login, e depois limpa o localStorage.
  • Testa a sério: persistência, multi-aparelhos, isolamento entre contas, e comportamento em rede lenta.
  • Com um verdadeiro backend, as funcionalidades avançadas (emails, pagamento, IA) tornam-se finalmente acessíveis.

Quiz — verifica a tua compreensão

1. Que problema resolve a base de dados, que a autenticação sozinha não resolvia?

A autenticação diz QUEM está ali; a base de dados guarda O QUÊ no mesmo sítio para todos os aparelhos. As duas juntas dão a sincronização que a Lina esperava.

2. Para que serve a coluna user_id na tabela habits?

user_id aponta para o utilizador dono: é a relação que permite mostrar a cada um os seus hábitos, e à RLS bloquear os outros.

3. O que acontece se te esqueceres de ativar a Row Level Security?

Por omissão, nada isola as linhas entre utilizadores. A RLS faz a própria base aplicar a regra «cada um as suas linhas» — exige-a palavra por palavra no teu prompt.

4. Como migrar os dados localStorage dos utilizadores existentes sem os perder?

A importação no primeiro login preserva o histórico de cada um: a base torna-se depois a única fonte de verdade. Os teus utilizadores não pagam a tua subida de nível.

5. Depois da migração, a lista aparece vazia quando a base contém linhas. Qual é a causa mais provável?

É o sintoma clássico: a base recusa a leitura porque a regra RLS não reconhece o utilizador. Consola + regra RLS enviadas à IA = diagnóstico imediato.

Auteur(s)

R

REHOUMA Haythem

Haythem Rehouma est un ingénieur et architecte IA et cloud, formateur et enseignant technique, avec un profil orienté IA médicale, AWS, MLOps, LLM/RAG et vision par ordinateur.