README de entrada do projeto — "do zero por terceiro" (issue #80 / META-4). Este arquivo mora no repo do back e documenta o setup completo dos dois repositórios: o backend (
lab-dev-software-back, este repo) e o frontend/BFF (lab-dev-software-front). Seguindo-o num ambiente limpo, cada app sobe sem passos faltando.
O Plot Twist é um guia de streaming: o usuário busca um filme ou série e descobre onde assistir no Brasil, com sinopse, elenco, nota da TMDB e os provedores disponíveis. Usuários autenticados podem avaliar (1–10), marcar como visto e favoritar títulos.
Arquitetura BFF: o navegador fala só com o Next (front, same-origin
/api/*); o Next fala com esta API Nest server-to-server, injetando a chave
interna. Ver docs/PRD.md (§8.1), CONTEXT.md e docs/sprint-1-plan.md.
[Navegador] ──same-origin──▶ [Next.js / BFF (Vercel)] ──server-to-server──▶ [Nest API (Azure VM)] ──▶ [TMDB]
cookie `session` HttpOnly X-Internal-Key + Bearer (protegidas) Postgres
| Repositório | Papel | Stack | No ar |
|---|---|---|---|
lab-dev-software-back (este repo) |
API + alvo do BFF | NestJS 11 · Prisma 7 · PostgreSQL 18 | https://api-uva.eduoncode.com |
lab-dev-software-front |
Front-end + BFF | Next.js 16 · React 19 · pnpm | https://lab-dev-software-front.vercel.app |
- Cadastro e login com sessão segura (cookie HttpOnly, JWT 24h).
- Busca de filmes e séries (TMDB, em português, região Brasil).
- Descoberta por gênero e "Em alta" na Home.
- Ficha do título: sinopse, elenco, nota TMDB, gêneros, duração/temporadas.
- "Onde assistir" no Brasil: assinatura (flatrate), aluguel e compra.
- Avaliar (nota 1–10), marcar como visto e favoritar títulos.
- Perfil com totais e listas de vistos, avaliados e favoritos.
- Tema claro/escuro e layout responsivo.
| Nome | RA | Função |
|---|---|---|
| Caio Parada Oliveira Planinschek | 1240205596 | Product Owner, Backend, Frontend |
| João Victor Berçot Chabudet Cabral | 1240108001 | Backend |
| Igor Rocha Lobato | 1240114118 | Backend, Frontend |
| Carlos Matheus Marinho Tavares | 1240119803 | Frontend, Documentação |
| Eduardo de Oliveira Fernandes | 1240104170 | Backend, QA |
| Luiz Felipe de Aguiar Passaroni | 1240114559 | QA |
| Lucas Vasconcelos Tabosa de Almeida | 1250100134 | Documentação |
| Gabriel Albuquerque Varela Santarello | 1240110815 | Documentação, QA |
| Davi Hasson Castro | 1240117220 | Frontend |
| Maria Fernanda Lourenço Class Teixeira | 1240113501 | Documentação, QA |
As telas da aplicação estão documentadas em docs/telas/, com captura em tema claro e escuro de cada uma das 6 telas.
Serviço backend (NestJS), atrás do BFF. O navegador nunca chama esta API diretamente — quem fala com ela é o Next, server-to-server.
- Node.js 20 + TypeScript 5
- NestJS 11
- Prisma 7 (ORM) sobre PostgreSQL 18
- JWT (
@nestjs/jwt+passport-jwt) e bcrypt para senha - TMDB (API v4) como fonte do catálogo
- class-validator (validação de DTOs e de env), @nestjs/throttler (rate limit), @nestjs/cache-manager (cache TTL 1h)
- Testes com Jest
Para rodar num ambiente limpo você precisa de uma das duas opções abaixo:
Opção A — local (sem Docker):
- Node.js 20+ e npm
- Um PostgreSQL acessível (local ou remoto)
Opção B — Docker (recomendado para subir rápido):
- Docker + Docker Compose (sobe Postgres + API juntos)
Em ambos os casos você precisa de um token v4 da TMDB (https://www.themoviedb.org/settings/api) para que a busca/ficha funcionem.
# 1. Clonar e entrar no projeto
git clone https://github.com/luizpassaroni/lab-dev-software-back.git
cd lab-dev-software-back
# 2. Instalar dependências
npm install
# 3. Configurar variáveis de ambiente
cp .env.example .env
# edite o .env (ver tabela abaixo). No mínimo:
# - DATABASE_URL apontando para o seu Postgres
# - JWT_SECRET e INTERNAL_API_KEY com 16+ caracteres
# - TMDB_API_TOKEN com o seu token v4
# Gere segredos seguros com: openssl rand -base64 32
# 4. Gerar o Prisma Client (OBRIGATÓRIO antes de buildar/testar)
npx prisma generate
# 5. Aplicar as migrations no banco
npx prisma migrate deploy # ou: npx prisma migrate dev (em desenvolvimento)
# 6. Subir em modo desenvolvimento (watch)
npm run start:devA API sobe em http://localhost:3000 (porta configurável via PORT).
Verifique com:
curl http://localhost:3000/health
# -> {"status":"ok"}
⚠️ Gate obrigatório —prisma generate. O Prisma Client não é gerado automaticamente nonpm install(não hápostinstall). Rodenpx prisma generateantes denpm run builde antes denpm test— sem isso a compilação e os testes falham por falta dos tipos do@prisma/client.
Copie .env.example para .env e preencha:
| Variável | Obrigatória | Default | Descrição |
|---|---|---|---|
DATABASE_URL |
sim | — | String de conexão do PostgreSQL (postgresql://user:pass@host:5432/db) |
JWT_SECRET |
sim | trocar-em-producao |
Segredo do JWT. Mín. 16 caracteres — o app não sobe se for menor. Nunca use o default em produção. |
INTERNAL_API_KEY |
sim | trocar-em-producao |
Segredo compartilhado com o BFF (Next). Vai no header X-Internal-Key de toda chamada Next → Nest. Mín. 16 caracteres. Use o mesmo valor nos dois lados. |
TMDB_API_TOKEN |
sim (para titles) | — | Token v4 (Read Access / Bearer) da TMDB |
NODE_ENV |
não | development |
Ambiente de execução |
PORT |
não | 3000 |
Porta do servidor |
As variáveis são validadas no boot (src/env.validation.ts): se JWT_SECRET
ou INTERNAL_API_KEY tiverem menos de 16 caracteres, a aplicação falha ao
iniciar com mensagem explícita.
npm run start:dev # desenvolvimento (watch)
npm run start # desenvolvimento (sem watch)
npm run build # compila para dist/ (rode prisma generate antes)
npm run start:prod # produção: node dist/src/main
npm run lint # ESLint --fix
npm run format # Prettiernpx prisma generate # gate: necessário antes da primeira execução
npm run test # testes unitários (Jest)
npm run test:watch # watch
npm run test:cov # cobertura
npm run test:e2e # testes end-to-end- Schema:
prisma/schema.prisma— modelosUser,Rating,Watched,Favorite. Títulos não são persistidos localmente: são referenciados portmdbId+tmdbType(MOVIE/TV). - Migration inicial:
prisma/migrations/20260523123455_init.
npx prisma generate # gera o Prisma Client (gate de build/test)
npx prisma migrate dev # cria/aplica migration em desenvolvimento
npx prisma migrate deploy # aplica migrations existentes (produção/CI)
npx prisma studio # inspeciona o banco no navegadorLocal (Postgres + API, com hot-reload e migrations automáticas):
docker compose -f docker-compose.local.yml up --buildSobe um Postgres 18 e a API em http://localhost:3000. O container espera o
Postgres ficar pronto, roda prisma migrate deploy e inicia em modo watch.
Produção (docker-compose.prod.yml): usa a imagem publicada
ghcr.io/luizpassaroni/nestjs-api:latest atrás de um reverse proxy Caddy
(TLS automático nas portas 80/443) + Postgres com volume persistente. Exige as
variáveis POSTGRES_PASSWORD, JWT_SECRET, INTERNAL_API_KEY e
TMDB_API_TOKEN no ambiente. A infra (Azure VM, região Brazil South) está
descrita em infra/main.bicep; o deploy é automatizado em
.github/workflows/deploy.yml (pipeline estrita à main).
O deploy de producao roda na Azure VM com Docker compose e e disparado pelo GitHub Actions em pushes para main que alterem arquivos de infra, Docker, Prisma, package ou codigo fonte.
Fluxo de producao:
- O workflow provisiona/atualiza a infraestrutura via Bicep.
- A imagem Docker da API e buildada e publicada no GitHub Container Registry.
- A VM recebe o
docker-compose.prod.ymle um.envgerado pelo workflow. docker compose up -d --force-recreaterecria os containers.- O workflow executa
npx prisma migrate deploydentro do container da API.
A API publica o dominio api-uva.eduoncode.com por meio do Caddy definido no docker-compose.prod.yml. O registro DNS A aponta para o IP publico estatico da VM. O Caddy:
- encaminha as requisicoes para o servico
api:3000; - emite e renova automaticamente o certificado TLS pela Let's Encrypt;
- redireciona requisicoes HTTP para HTTPS;
- persiste certificados e configuracao nos volumes
caddy_dataecaddy_config.
As portas 80 e 443 precisam permanecer liberadas no NSG. A porta 80 tambem e usada pelo desafio HTTP-01 durante a emissao ou renovacao do certificado.
Verificacao publica:
# Deve responder 200 sem usar -k.
curl -I https://api-uva.eduoncode.com/health
# Deve redirecionar para HTTPS.
curl -I http://api-uva.eduoncode.com/healthNa VM, em ~/app, valide os containers e as migrations:
docker compose ps
docker compose exec -T api npx prisma migrate statusPara confirmar as variaveis obrigatorias sem imprimir os valores:
docker compose exec -T api sh -lc '
for name in DATABASE_URL JWT_SECRET INTERNAL_API_KEY TMDB_API_TOKEN; do
eval value=\$$name
if [ -n "$value" ]; then
echo "$name=present"
else
echo "$name=missing"
fi
done'Depois de cada gate develop para main, o pipeline deve ficar verde e o fluxo publicado deve validar cadastro, login, sessao, busca, ficha e os recursos de historico disponiveis. O custo do resource group rg-faculdade-prod deve ser acompanhado no Azure Cost Management durante a sprint.
Variaveis e secrets de producao:
| Nome | Origem em producao | Uso |
|---|---|---|
DATABASE_URL |
Montada no docker-compose.prod.yml a partir do servico Postgres interno. |
Conexao do Prisma com o PostgreSQL. |
JWT_SECRET |
GitHub Secret PROD_JWT_SECRET, escrito no .env da VM pelo workflow. |
Assinatura e validacao dos JWTs. |
TMDB_API_TOKEN |
GitHub Secret PROD_TMDB_API_TOKEN, escrito no .env da VM pelo workflow. |
Token Bearer v4 para chamadas TMDB. |
INTERNAL_API_KEY |
GitHub Secret PROD_INTERNAL_API_KEY, escrito no .env da VM pelo workflow. |
Chave compartilhada com o BFF do frontend. |
NODE_ENV |
Definido como production na imagem Docker. |
Modo de execucao da aplicacao. |
PORT |
.env da VM e docker-compose.prod.yml. |
Porta interna da API; default 3000. |
POSTGRES_PASSWORD |
GitHub Secret PROD_POSTGRES_PASSWORD, escrito no .env da VM pelo workflow. |
Senha do banco PostgreSQL de producao. |
Valores reais de secrets nunca devem ser versionados.
Header obrigatório. Um guard global (
InternalKeyGuard) exige o headerX-Internal-Key: <INTERNAL_API_KEY>em todas as rotas, exceto as públicas (/health). Em produção, quem injeta esse header é o BFF (Next) — o navegador nunca chama esta API diretamente. Há também rate limit global (100 req/min por IP).
| Método | Rota | Descrição |
|---|---|---|
GET |
/health |
Health check (público, sem header) |
POST |
/auth/register |
Cadastro (nome, email, senha) |
POST |
/auth/login |
Login — emite JWT (expira em 24h) |
GET |
/titles/search?q=<termo>&page=<n> |
Busca filmes + séries na TMDB (região BR) |
GET |
/titles/:type/:id |
Ficha do título (type = movie/tv, id = id da TMDB) |
Sobre logout: não há endpoint server-side — a sessão é descartada no BFF
(remoção do cookie). Ver CONTEXT.md e a issue de contrato de logout.
A referência completa da API (todos os endpoints, payloads e autenticação) está
em docs/api.md.
src/
├── auth/ # cadastro, login, JWT, guards de autenticação
├── titles/ # busca e ficha de títulos (cliente TMDB + cache)
├── user/ # dados do usuário
├── prisma/ # PrismaModule/Service
├── common/ # guards (InternalKey, throttler), decorators (@Public)
├── env.validation.ts
└── main.ts
prisma/ # schema + migrations
infra/ # main.bicep (Azure)
docs/ # PRD, contratos de API, planos de sprint, issues
Front-end e BFF do Plot Twist. O navegador fala só com o Next
(same-origin, /api/*); o Next fala com a API Nest (Parte 1) server-to-server,
injetando a chave interna. O token de sessão vive num cookie HttpOnly — o JS
do browser nunca o lê.
- Node.js 20 + TypeScript 5
- Next.js 16 (App Router, React Compiler) + React 19
- pnpm 10 (gerenciador de pacotes)
- Tailwind CSS 4 + Radix UI (componentes estilo shadcn/ui)
- TanStack Query (data fetching) + TanStack Form & Zod (validação)
- Biome (lint + format) e Vitest + Testing Library (testes)
- Node.js 20+ (o CI roda em Node 20)
- pnpm 10+ — instale com
npm i -g pnpm@10oucorepack enable
# 1. Clonar e entrar no projeto
git clone https://github.com/luizpassaroni/lab-dev-software-front.git
cd lab-dev-software-front
# 2. Instalar dependências
pnpm install
# 3. Configurar variáveis de ambiente
cp .env.local.example .env.local
# Para usar a API real, preencha API_INTERNAL_URL e INTERNAL_API_KEY.
# Sem elas, o BFF responde com mocks de dev (dá pra rodar o front isolado).
# 4. Subir em modo desenvolvimento
pnpm devA aplicação sobe em http://localhost:3001.
💡 Funciona sem backend. Enquanto
API_INTERNAL_URLnão estiver definida, os route handlers/api/*respondem com mocks de dev que seguem o mesmo contrato da API — útil para desenvolver o front isolado.
Copie .env.local.example para .env.local. As variáveis do BFF são
server-only (sem prefixo NEXT_PUBLIC_), então o segredo nunca chega ao
browser:
| Variável | Obrigatória | Default | Descrição |
|---|---|---|---|
API_INTERNAL_URL |
para API real | — (mock) | URL interna da API Nest, usada só server-side pelos route handlers /api/*. Local: http://localhost:3000. Ausente → BFF usa mocks de dev. |
INTERNAL_API_KEY |
para API real | — | Segredo compartilhado com o back; vai no header X-Internal-Key em toda chamada Next → Nest. Use o mesmo valor dos dois lados. |
pnpm dev # desenvolvimento — http://localhost:3001
pnpm build # build de produção
pnpm start # serve o build de produção
pnpm test # testes (Vitest, run único)
pnpm lint # Biome (checagem)
pnpm format # Biome (corrige)No MVP o front tem apenas testes simbólicos (2-3 testes de componente),
conforme PRD §8.3. No CI (.github/workflows/ci.yml), pnpm lint, pnpm test
e pnpm build rodam a cada PR.
Cada chamada do browser passa por um route handler /api/* (src/app/api/...),
que lê o cookie session, injeta os headers internos (X-Internal-Key,
Authorization: Bearer, X-Client-IP) e chama o Nest. Enquanto o backend não
está configurado (API_INTERNAL_URL ausente), os handlers caem em mocks de
dev com o mesmo contrato — trocar para o backend real é só preencher o
.env.local, sem mudar código. Exemplo:
src/modules/auth/queries/register.ts.
src/
├── app/ # App Router (rotas + BFF)
│ ├── (auth)/ # login e cadastro
│ ├── api/ # route handlers /api/* (BFF → Nest)
│ ├── busca/ # resultados de busca
│ ├── titulo/ # ficha do título
│ ├── perfil/ # perfil do usuário
│ ├── layout.tsx # layout global (header, tema)
│ └── page.tsx # home (hero + busca + chips de gênero)
├── modules/ # lógica por domínio: auth, titles, profile (queries + mocks)
├── shared/ # componentes e utilitários compartilhados
└── test/ # setup de testes
- Suba o back (Parte 1) na porta
3000— não esqueça onpx prisma generate. - No front, no
.env.local, aponte para o back local e use o mesmo segredo:API_INTERNAL_URL=http://localhost:3000 INTERNAL_API_KEY=<o mesmo valor do .env do back>
- Suba o front (
pnpm dev) na porta3001e abra http://localhost:3001.
Fluxo de ponta a ponta: criar conta → login → buscar um título → abrir a ficha → ver "onde assistir" no Brasil.
- Front (Vercel): https://lab-dev-software-front.vercel.app
- API (Azure VM + Caddy/HTTPS): https://api-uva.eduoncode.com —
GET /healthresponde{"status":"ok"}.
Ordem de leitura recomendada do projeto:
docs/PRD.md— o quê e o porquêCONTEXT.md— glossário canônico (vocabulário do time; idêntico nos 2 repos)docs/sprint-1-plan.md— o recorte da sprint- A issue — a tarefa
Referência e artefatos:
docs/api.md— referência completa da API REST (endpoints, payloads, autenticação).docs/telas/— capturas e descrição das 6 telas.docs/arquitetura.pngedocs/banco_de_dados.png— diagramas de arquitetura e do modelo de dados.- O relatório acadêmico completo (PDF, template UVA) acompanha a entrega final da disciplina.