UTUpTechDeskAcademia
← Voltar aos módulos

Módulo 3Sua 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çaO que escolhemosPor quê
FrameworkNext.jsJá 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 dadosPostgreSQLO mesmo banco que você já viu em ação nas VPS ao longo do curso — robusto, gratuito, roda em qualquer lugar
ORMDrizzleUma 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çãoFeita à 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