Módulo 3 — Sua primeira aplicação no ar
Modelando e construindo sua aplicação
Lição 1 de 2
🎬
Vídeo desta lição ainda não foi gravado.
O conteúdo em texto abaixo já está completo.
Módulo 3, Lição 1 — Modelando e construindo sua aplicação
Tempo estimado: 6h · Pré-requisito: Módulos 0-2
1. Uma confissão antes de começar
Essa lição é diferente das outras: não é sobre um servidor abstrato ou uma rede de exemplo. É sobre a própria página que você está lendo agora. Toda essa plataforma — o cadastro, a lista de módulos, o vídeo, o questionário que você respondeu na última lição — foi construída do zero, ao vivo, no mesmo espírito de "aprender em público" do resto do curso. Não existia um roteiro perfeito escrito antes; foi decisão por decisão, exatamente como você vai ver aqui.
A ideia desta lição é te dar o suficiente pra você conseguir construir e publicar sua própria aplicação simples — não pra virar programador profissional, mas pra entender o outro lado da moeda de tudo que você aprendeu até aqui: de que adianta saber montar um servidor perfeito se você não sabe colocar nada útil rodando nele?
2. Escolhendo as ferramentas (a analogia da caixa de ferramentas)
Antes de martelar o primeiro prego, um profissional escolhe as ferramentas certas pro trabalho. Construir uma aplicação web tem a mesma lógica — e as escolhas aqui não foram aleatórias:
| Peça | O que escolhemos | Por quê |
|---|---|---|
| Framework | Next.js | Já resolve roteamento, renderização no servidor e formulários sem precisar montar isso na mão — o "kit" mais usado do mercado hoje pra esse tipo de aplicação |
| Banco de dados | PostgreSQL | O mesmo banco que você já viu em ação nas VPS ao longo do curso — robusto, gratuito, roda em qualquer lugar |
| ORM | Drizzle | Uma camada que traduz entre "tabelas do banco" e "código", pra você não escrever SQL cru toda hora (mais sobre isso já já) |
| Autenticação | Feita à mão (senha com hash + sessão) | Sem depender de um serviço externo pago — dá pra entender exatamente o que está acontecendo, sem caixa-preta |
💡 Dica de professor: não existe "a stack perfeita" — existe a que resolve seu problema com o que você já sabe. A gente escolheu Postgres, por exemplo, porque você já tinha visto Postgres rodando numa VPS antes — reaproveitar conhecimento é tão válido quanto aprender ferramenta nova.
3. O que é um ORM (a analogia do tradutor)
Um banco de dados fala uma língua própria, chamada SQL (SELECT * FROM alunos WHERE...). O código da sua aplicação fala outra língua (nesse caso, TypeScript). Um ORM (Object-Relational Mapper) é o tradutor entre os dois — você escreve código na sua linguagem normal, e ele converte pra SQL por baixo dos panos.
Exemplo real, tirado direto do código desta plataforma (src/db/schema.ts):
export const alunos = pgTable("alunos", {
id: serial("id").primaryKey(),
email: varchar("email", { length: 255 }).notNull().unique(),
senhaHash: text("senha_hash").notNull(),
nome: varchar("nome", { length: 255 }).notNull(),
criadoEm: timestamp("criado_em").notNull().defaultNow(),
});
Essas poucas linhas descrevem uma tabela inteira — quais colunas existem, qual o tipo de cada uma (varchar, text, timestamp), quais são obrigatórias (notNull()) e quais precisam ser únicas (unique()). O Drizzle lê isso e sabe gerar o SQL de criação da tabela sozinho — é literalmente o que aconteceu quando essa plataforma criou sua própria tabela de alunos.
3.1 Migrations — o histórico de mudanças do banco
Bancos de dados reais nunca ficam parados: você começa com uma tabela simples e vai adicionando campos conforme precisa (foi exatamente o que aconteceu aqui: a tabela alunos começou só com nome/email/senha, e ganhou campos de nível de experiência e objetivo depois). Uma migration é um arquivo que registra "o banco mudou de tal jeito, nessa ordem" — assim, qualquer cópia do banco (a sua local, a da VPS em produção) consegue chegar no mesmo estado final, na mesma ordem, sem ninguém ter que lembrar manualmente o que foi feito.
npx drizzle-kit generate # olha o schema.ts, gera o arquivo de migration
npx drizzle-kit migrate # aplica a migration pendente no banco de verdade
4. Modelando dados de verdade — tabelas que se relacionam
O pulo do gato de modelar um banco não é criar uma tabela — é decidir como as tabelas se conectam. Esta plataforma tem 6 tabelas conectadas entre si (alunos, modulos, licoes, questoes, respostas, progresso). O padrão se repete: cada lição "pertence a" um módulo, cada questão "pertence a" uma lição, cada resposta "pertence a" um aluno e uma questão.
Essa conexão se chama chave estrangeira (foreign key, ou FK) — um número numa tabela que aponta pra outra:
export const licoes = pgTable("licoes", {
id: serial("id").primaryKey(),
moduloId: integer("modulo_id")
.notNull()
.references(() => modulos.id, { onDelete: "cascade" }),
// ...resto dos campos
});
moduloId é uma FK: garante que toda lição está presa a um módulo que realmente existe (o banco recusa criar uma lição apontando pra um módulo inexistente). O onDelete: "cascade" é uma decisão de segurança consciente: se um módulo for apagado, todas as lições dele (e as questões, e as respostas dos alunos) somem junto — evita deixar "lixo" órfão no banco.
5. Autenticação — provando quem você é sem expor a senha
Toda vez que você faz login, duas coisas precisam acontecer com cuidado:
5.1 Nunca guardar a senha "pura"
Se o banco de dados vazasse um dia (acontece, até com empresas grandes), a última coisa que você quer é que as senhas dos seus alunos estejam ali, legíveis. Por isso, a senha nunca é guardada — só um hash dela: um resultado matemático de mão única, que transforma "senha12345" numa sequência tipo $2a$12$KIx... que não dá pra reverter de volta pra senha original.
export function hashPassword(password: string) {
return bcrypt.hash(password, 12);
}
export function verifyPassword(password: string, hash: string) {
return bcrypt.compare(password, hash);
}
No cadastro, a senha vira hash antes de ir pro banco. No login, a gente não "descriptografa" nada — só pede pro bcrypt comparar a senha digitada com o hash guardado, e ele responde sim/não.
5.2 Sessão — como o site "lembra" que você está logado
HTTP (o protocolo da web) não tem memória — cada clique é, tecnicamente, uma conversa nova do zero com o servidor. Pra você não ter que digitar a senha em toda página, o servidor entrega um token (uma sequência assinada digitalmente) guardado num cookie no seu navegador, que é enviado automaticamente em cada requisição seguinte.
export function createSessionToken(payload: SessionPayload) {
return new SignJWT(payload)
.setProtectedHeader({ alg: "HS256" })
.setIssuedAt()
.setExpirationTime("30d")
.sign(secret);
}
Esse token é um JWT (JSON Web Token) — assinado com uma chave secreta que só o servidor conhece. Se alguém tentar forjar ou alterar o conteúdo do token, a assinatura não bate mais, e o servidor rejeita. É assim que esta plataforma sabe seu nome quando você abre uma lição, sem pedir login de novo a cada clique.
⚠️ Atenção de segurança: o cookie que guarda esse token é marcado como
httpOnly— isso significa que nem o próprio JavaScript da página consegue ler o valor dele, só o navegador manda de volta pro servidor automaticamente. Protege contra um tipo comum de ataque (roubo de sessão via script malicioso).
6. Exercícios práticos
Exercício 1 — Se você tem Node.js instalado, crie um projeto Next.js vazio e explore a estrutura de pastas:
npx create-next-app@latest meu-teste
Não precisa terminar nada funcional — só olhar como o framework organiza os arquivos.
Exercício 2 — Pegue uma ideia simples (uma lista de tarefas, um catálogo de filmes) e desenhe, no papel, que tabelas você precisaria e como elas se conectariam com FK. Não precisa código nenhum — só o modelo.
Exercício 3 (reflexão) — Releia a seção 5.1. Por que armazenar a senha em texto puro (sem hash) é perigoso mesmo se o site "nunca vai vazar"? Pense em pelo menos dois motivos diferentes.
Exercício 4 (gravação) — Grave a tela criando uma tabela simples com Drizzle (mesmo que seja um projeto de teste), gerando e aplicando a migration, e mostrando ela criada de verdade no banco.
Responda o questionário abaixo pra fechar a lição.
Teste de fixação
Responda pra fechar a lição — suas respostas ficam registradas na sua conta.
Crie uma conta grátis pra responder o teste e registrar seu progresso.
Criar conta grátis