{"id":31690241,"url":"https://github.com/matheusscarvalho1/fastify-api","last_synced_at":"2026-04-20T19:03:45.455Z","repository":{"id":310576186,"uuid":"1037531825","full_name":"matheusscarvalho1/fastify-api","owner":"matheusscarvalho1","description":"Uma API RESTful robusta para gerenciamento de cursos, com autenticação JWT e controle de acesso por roles. Coberta por testes end-to-end com Vitest e Supertest.","archived":false,"fork":false,"pushed_at":"2025-12-24T21:06:25.000Z","size":124,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-26T09:02:20.170Z","etag":null,"topics":["fastify","jwt-authentication","node","restful-api","supertest","typescript","vitest","zod-validation"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/matheusscarvalho1.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-13T18:02:40.000Z","updated_at":"2025-12-24T21:06:29.000Z","dependencies_parsed_at":null,"dependency_job_id":"1ab7bf15-4dc6-42b7-9b9e-02b7c7af8d9c","html_url":"https://github.com/matheusscarvalho1/fastify-api","commit_stats":null,"previous_names":["matheusscarvalho1/fastify-api"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/matheusscarvalho1/fastify-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matheusscarvalho1%2Ffastify-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matheusscarvalho1%2Ffastify-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matheusscarvalho1%2Ffastify-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matheusscarvalho1%2Ffastify-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/matheusscarvalho1","download_url":"https://codeload.github.com/matheusscarvalho1/fastify-api/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matheusscarvalho1%2Ffastify-api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32061251,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-20T11:35:06.609Z","status":"ssl_error","status_checked_at":"2026-04-20T11:34:48.899Z","response_time":94,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fastify","jwt-authentication","node","restful-api","supertest","typescript","vitest","zod-validation"],"created_at":"2025-10-08T12:42:27.853Z","updated_at":"2026-04-20T19:03:45.450Z","avatar_url":"https://github.com/matheusscarvalho1.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fastify Project - API de Cursos\n\nEste projeto é uma API RESTful desenvolvida com [Fastify](https://www.fastify.io/) e [TypeScript](https://www.typescriptlang.org/), utilizando [Drizzle ORM](https://orm.drizzle.team/) para integração com banco de dados PostgreSQL. O objetivo principal é gerenciar cursos, permitindo criar, listar, buscar, atualizar e deletar cursos, com autenticação JWT e controle de permissões por papel (role - student/manager).\n\n## Funcionalidades\n\n- Criar um novo curso\n- Listar todos os cursos\n- Buscar curso por ID\n- Atualizar curso por ID\n- Deletar curso por ID\n\n## Tecnologias Utilizadas\n\n- [Fastify](https://www.fastify.io/)\n- [TypeScript](https://www.typescriptlang.org/)\n- [Drizzle ORM](https://orm.drizzle.team/)\n- [PostgreSQL](https://www.postgresql.org/)\n- [Zod](https://zod.dev/) (validação de dados)\n- [Swagger](https://swagger.io/) (documentação de API)\n\n## Instalação\n\n1. **Clone o repositório:**\n\n   ```bash\n   git clone \u003curl-do-repositorio\u003e\n   cd fastify\n   ```\n\n2. **Instale as dependências:**\n\n   ```bash\n   npm install\n   ```\n\n3. **Configure as variáveis de ambiente:**\n\n   - Crie um arquivo `.env` na raiz do projeto com a string de conexão do banco:\n  \n        ```env\n        # Ambiente da aplicação (development, test ou production)\n        NODE_ENV=\"development\"\n        \n        # Formato: postgresql://[usuario]:[senha]@[host]:[porta]/[nome_do_banco]\n        DATABASE_URL=\"postgres://postgres:postgres@localhost:5432/desafio\"\n\n        # Chave secreta para assinatura de tokens JWT (pode ser qualquer string longa e segura)\n        JWT_SECRET=\"secret\"\n        ```\n   \n\n4. **Configure o banco de dados:**\n\n   - O projeto utiliza Docker para o banco PostgreSQL. Inicie o serviço com:\n   \n        ```bash\n        docker-compose up -d\n        ```\n   - O banco será iniciado na porta padrão `5432` com usuário e senha `postgres` e banco `desafio_dev`.\n  \n 5. **Execute para criar os arquivos de migração do banco de dados:**\n\n      ```bash\n      npm run db:generate\n      ```\n\n6. **Execute as migrações para criar a estrutura do banco de dados baseado no que foi generado no comando generate, anteriormente:**\n\n      ```bash\n      npm run db:migrate\n      ```\n\n7. **Execute as seeds para popular o banco:**\n\n      ```bash\n      npm run db:seed\n      ```\n\n8. **Inicie o servidor em modo desenvolvimento:**\n      ```bash\n      npm run dev\n      ```\n\n9. **Veja os dados populados no banco:**\n      ```bash\n      npm run db:studio\n      ```\n\n**Utilize um dos usuários que foram populados vendo pelo studio do drizzle para autenticar e obter um login no sistema**\n\n- OBS: A senha padrão é `Teste@123`.\n\nO servidor estará disponível em `http://localhost:3333`.\n\n## Documentação da API\n\nDurante o desenvolvimento, a documentação Swagger estará disponível em:\n\n- `http://localhost:3333/docs`\n\n## Rotas Principais\n\n### 🔐 Autenticação e Autorização\n\nO sistema utiliza JWT (JSON Web Token) para autenticação.\n\nCada usuário possui um papel definido no token (``role``):\n\n#### Papel\t\u0026 Permissões\n\nmanager\t- Pode criar, listar, buscar, atualizar e deletar cursos\nstudent\t- Pode apenas visualizar cursos (`GET /courses` e `GET /courses/:id`)\n\n\n### 🔑 Obter Token JWT\n\n- Utilize um dos usuários que foram populados vendo pelo studio do drizzle para autenticar e obter um login no sistema, então utilize:\n`npm run db:studio`\n\n- Após isso ao abrir o drizzle studio, vá na tabela usuários e use o e-mail de um dos usuários como no exemplo abaixo para realizar a requisição.\n\n- **POST** `/sessions`\n- Body:\n\n```json\n{\n  \"email\": \"test@email.com\",\n  \"password\": \"Teste@123\"\n}\n```\n\n\n#### Resposta:\n```json\n{\n  \"token\": \"\u003cseu_token_jwt\u003e\"\n}\n```\n\n### 📤 Enviar Token em Requisições\n\nInclua o token no cabeçalho da requisição:\n\n```json\n{\n  \"Authorization\": \"\u003cseu_token_jwt\u003e\"\n}\n\n```\n\n### Criar Curso\n\n- **POST** `/courses`\n- Body:\n  ```json\n  {\n    \"title\": \"Nome do Curso\",\n    \"description\": \"Descrição opcional\"\n  }\n  ```\n\n### Listar Todos os Cursos\n\n- **GET** `/courses`\n\n### Buscar Curso por ID\n\n- **GET** `/courses/:id`\n\n### Atualizar Curso\n\n- **PUT** `/courses/:id`\n- Body:\n  ```json\n  {\n    \"title\": \"Novo Título\",\n    \"description\": \"Nova descrição\"\n  }\n  ```\n\n### Deletar Curso\n\n- **DELETE** `/courses/:id`\n\n## Estrutura do Banco de Dados\n\nTabela `courses`:\n\n- `id` (UUID, PK)\n- `title` (string, único, obrigatório)\n- `description` (string, opcional)\n\nTabela `users`:\n\n- `id` (UUID, PK)\n- `name` (string, obrigatório)\n- `email` (string, único, obrigatório)\n- `password` (string, obrigatório)\n- `role` (enum `user_role`, obrigatório, padrão: `student` onde user_role: `student | manager`)\n\nTabela `enrollments`:\n\n- `id` (UUID, PK)\n- `userId` (UUID, FK -\u003e `users.id`, obrigatório)\n- `courseId` (UUID, FK -\u003e `courses.id`, obrigatório)\n-  `createdAt` (timestamp com timezone, obrigatório, padrão: now() )\n\n  ## Testes automatizados\n- Este projeto utiliza Vitest para a execução de testes de integração, garantindo que as rotas e regras de negócio funcionem corretamente. Para garantir a integridade dos dados, os testes em 2025 são executados em um ambiente PostgreSQL totalmente isolado.\n\n### 🛠️ Configuração do Ambiente de Testes\n\n1. Banco de Dados no Docker (setup.sql)\n   - O projeto utiliza um script de inicialização automática no Docker. O arquivo localizado em ./docker/setup.sql garante que o ambiente suba com dois bancos independentes:\n         ```\n         -- Criado automaticamente ao subir o container\n         CREATE DATABASE desafio_test;\n         ```\n2. Arquivo de configuração `.env.test`\n   - É necessário criar um arquivo `.env.test` na raiz do projeto para instruir o Vitest a utilizar as credenciais de teste. Sem este arquivo, os testes podem falhar por falta de conexão ou por tentar acessar o banco de desenvolvimento:\n   \n      ```\n      # Define o ambiente como teste\n      NODE_ENV=\"test\"\n      \n      # URL de conexão apontando especificamente para o banco de testes criado via setup.sql\n      DATABASE_DOCKER_URL=\"postgres://postgres:postgres@localhost:5432/desafio_test\"\n      \n      # Segredo JWT exclusivo para o ambiente de testes\n      JWT_SECRET=\"secret\"\n      ```\n   - Dessa forma, o banco desafio_dev fica reservado para uso manual (via Drizzle Studio ou Postman), enquanto o desafio_test é utilizado exclusivamente pela suíte de testes.\n  \n   ### Explicação dos Scripts de Teste\n   - A automação no `package.json` já garante que o banco de dados esteja pronto antes da execução dos testes:\n     \n      -    `npm run pretest`:    \n      -       \"pretest\": \"dotenv -e .env.test drizzle-kit push\"\n         -    Este comando é acionado automaticamente sempre que você executa `npm run test`, ele utiliza o `dotenv -e .env.test` para carregar as credencias do banco de teste e o `drizzle-kit push` para sincronizar instantaneamente o seu schema (`src/database/schema.ts`) com o banco `desafio_test`. Isso elimina a necessidade de rodar migrações manuais para os testes, garantindo que as tabelas existam e estejam atualizadas.\n           \n      -    `npm run test`:\n      -        \"test\": \"dotenv -e .env.test vitest run\"\n        -   Este é o comando principal que inicia o executor de testes Vitest. Ele força a aplicação a ler o arquivo `.env.test`, garantindo que tanto o servidor Fastify quanto as factories de dados (como a criação de usuários e cursos) se conectem excluisvamente ao banco de testes, mantendo o seu bancode desenvolveimento(`desafio_dev`) intacto.\n       \n   ### Como executar os testes\n      1. Certifique-se de que o container Docker está rodando: `docker-compose up -d`;\n      2. Garante que o arquivo `.env.test` foi criado corretamente na raiz do projeto.\n      3. No terminal, execute apenas:```npm run test```  \n\n## Scripts Disponíveis\n\n- `npm run dev` — Inicia o servidor em modo desenvolvimento\n- `npm run db:generate` — Gera os arquivos SQL do Drizzle ORM com base nas alterações feitas nas tabelas no arquivo `src/database/schema.ts`.\n- `npm run db:migrate` — Executa as migrations SQL e aplica as alterações no banco de dados.\n- `npm run db:seed` — Popula o banco de dados com dados iniciais baseado no arquivo `src/database/seed.ts`.\n- `npm run db:studio` — Abre o Drizzle Studio para visualização e inspeção do banco de dados.\n- `npm run pretest` — Prepara o banco de testes sincronizando o schema.\n- `npm run test` — Executa todos os testes de integração de forma sequencial utilizando o ambiente de testes.\n\n## 👨‍💻 Desenvolvido por\n\n**Matheus Carvalho**\n\n- LinkedIn: [@matheusscarvalho](https://www.linkedin.com/in/matheusscarvalho/)\n- GitHub: [@matheusscarvalho1](https://github.com/matheusscarvalho1)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatheusscarvalho1%2Ffastify-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmatheusscarvalho1%2Ffastify-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatheusscarvalho1%2Ffastify-api/lists"}