Skip to main content
Glama
README.md
# 🌎 Geo-Explorer

> Explorador de trilhas de aprendizagem em linha de comando, com servidor MCP integrado.
> Projeto do desafio **"Construindo Seu Primeiro Produto com um Agente de IA"** da [DIO](https://dio.me).

[![Python](https://img.shields.io/badge/Python-3.10%2B-blue)](https://www.python.org/)
[![Testes](https://img.shields.io/badge/testes-74%20passando-brightgreen)](#-como-executar-os-testes)
[![Licença](https://img.shields.io/badge/licen%C3%A7a-MIT-green)](LICENSE)

---

## đź“– O que Ă© o Geo-Explorer

O Geo-Explorer é uma ferramenta de linha de comando que ajuda alguém a **explorar uma trilha de estudos** de ponta a ponta:

1. escolhe uma tecnologia e recebe um **plano de estudos** com módulos, tópicos e carga horária;
2. pede um **desafio de código** no nível em que está;
3. ao terminar, emite um **certificado fictĂ­cio** de conclusĂŁo.

Tudo roda sobre uma base de trilhas fictícia (`trilhas.json`) criada especialmente para o projeto — **nenhum dado aqui representa um curso real, e o certificado não tem validade legal**.

Além da CLI, o projeto expõe os mesmos três comandos como um **servidor MCP**, permitindo que ferramentas de IA (Claude Desktop, Claude Code, IDEs compatíveis) usem o Geo-Explorer como fonte de dados sem precisar do terminal.

### Base de trilhas

| Trilha | Categoria | Níveis | Carga horária total | Desafios |
|---|---|---|---|---|
| Python | Backend | iniciante, intermediário, avançado | 180h | 6 |
| JavaScript | Frontend | iniciante, intermediário, avançado | 164h | 6 |
| SQL e Dados | Dados | iniciante, intermediário, avançado | 144h | 6 |
| DevOps | Infraestrutura | iniciante, intermediário, avançado | 156h | 6 |
| Inteligência Artificial | IA | iniciante, intermediário, avançado | 146h | 6 |

**5 trilhas · 15 planos de estudo · 30 desafios de código**

---

## 🚀 Como executar o projeto

### Pré-requisitos

- Python 3.10 ou superior
- Nada além disso: o projeto tem **zero dependências externas** em runtime

### Instalação

```bash
# 1. clone o repositĂłrio
git clone https://github.com/GuiC1ntra/geo-explorer.git
cd geo-explorer

# 2. (recomendado) crie um ambiente virtual
python3 -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate

# 3. instale em modo editável, com as dependências de teste
pip install -e ".[dev]"
```

Depois disso o comando `geo-explorer` fica disponĂ­vel no terminal.

> **Sem instalar nada?** Também funciona direto do código-fonte:
> ```bash
> PYTHONPATH=src python3 -m geo_explorer listar
> ```

---

## đź§­ Como usar os comandos

### `listar` — ver todas as trilhas

```bash
geo-explorer listar
```

```
================================================================
  TRILHAS DISPONIVEIS
================================================================

  devops       DevOps
               Infraestrutura | 156h totais
               niveis: iniciante, intermediario, avancado

  ia           Inteligencia Artificial
               IA | 146h totais
               niveis: iniciante, intermediario, avancado
  ...
```

### `trilha` — plano de estudos

Apresenta o plano de estudos da tecnologia escolhida.

```bash
geo-explorer trilha python
geo-explorer trilha python --nivel intermediario
geo-explorer trilha "InteligĂŞncia Artificial" --nivel avancado
geo-explorer trilha frontend            # busca por tag também funciona
```

```
================================================================
  TRILHA: PYTHON
================================================================
Categoria......: Backend
Nivel..........: intermediario
Carga horaria..: 60h
Modulos........: 5

PLANO DE ESTUDOS
----------------------------------------------------------------

  1. Programacao orientada a objetos  (12h)
     - Classes e heranca
     - dataclasses
     - Metodos magicos
  ...

Proximo passo: nivel 'avancado' (geo-explorer trilha python --nivel avancado)
```

| Opção | Descrição | Padrão |
|---|---|---|
| `tecnologia` | Id, nome ou tag da trilha | obrigatĂłrio |
| `--nivel`, `-n` | `iniciante`, `intermediario` ou `avancado` | `iniciante` |

### `desafio` — gerar um desafio de código

```bash
geo-explorer desafio sql --nivel avancado
geo-explorer desafio ia --nivel intermediario --seed 42
```

```
================================================================
  DESAFIO: Carga incremental idempotente
================================================================
Id.............: sql-avc-02
Trilha.........: SQL e Dados
Nivel..........: avancado
Tempo estimado.: 120 min

ENUNCIADO
----------------------------------------------------------------
Monte um MERGE que carregue apenas registros novos ou alterados
e possa ser reexecutado sem duplicar dados.

CRITERIOS DE ACEITE
----------------------------------------------------------------
  [ ] Usar chave de negocio
  [ ] Tratar updates e inserts
  [ ] Ser idempotente

DICA
----------------------------------------------------------------
  Uma coluna updated_at mais MERGE ON chave resolve os dois casos.
```

| Opção | Descrição | Padrão |
|---|---|---|
| `tecnologia` | Id, nome ou tag da trilha | obrigatĂłrio |
| `--nivel`, `-n` | NĂ­vel do desafio | `iniciante` |
| `--seed`, `-s` | Semente do sorteio — a mesma semente devolve sempre o mesmo desafio | aleatório |

### `certificado` — emitir certificado fictício

```bash
geo-explorer certificado "Guilherme Cintra" --trilha python --nivel intermediario
geo-explorer certificado "Guilherme Cintra" -t ia -n avancado --data 2026-08-28
```

```
+--------------------------------------------------------------+
|                                                              |
|                   CERTIFICADO DE CONCLUSAO                   |
|           (documento ficticio - projeto de estudo)           |
|                                                              |
|                       Certificamos que                       |
|                                                              |
|                       GUILHERME CINTRA                       |
|                                                              |
|         concluiu a trilha de Inteligencia Artificial         |
|             no nivel intermediario, com 50 horas             |
|                  distribuidas em 4 modulos.                  |
|                                                              |
|                    Emitido em 2026-08-28                     |
|           Codigo de validacao: GEO-8028-633F-AD41            |
|                                                              |
+--------------------------------------------------------------+
```

| Opção | Descrição | Padrão |
|---|---|---|
| `aluno` | Nome de quem concluiu | obrigatĂłrio |
| `--trilha`, `-t` | Id ou nome da trilha | obrigatĂłrio |
| `--nivel`, `-n` | NĂ­vel concluĂ­do | `iniciante` |
| `--data`, `-d` | Data de emissĂŁo (`AAAA-MM-DD`) | hoje |

O **código de validação** é gerado por um hash SHA-256 dos dados do certificado. Ele é determinístico: os mesmos dados sempre produzem o mesmo código, e qualquer alteração produz um código diferente. Não é uma assinatura criptográfica de verdade — é o que dá cara de documento ao resultado e o torna testável.

### SaĂ­da em JSON

Qualquer comando aceita `--json`, o que torna o Geo-Explorer utilizável dentro de scripts:

```bash
geo-explorer --json trilha python --nivel avancado | jq '.modulos[].titulo'
geo-explorer --json desafio devops --seed 1 | jq -r '.enunciado'
```

---

## 🔌 Servidor MCP

O **MCP (Model Context Protocol)** é um protocolo baseado em JSON-RPC 2.0 que permite que ferramentas de IA descubram e chamem funções de um programa externo. Na prática: em vez de você digitar `geo-explorer trilha python`, o agente de IA chama a ferramenta sozinho durante a conversa.

O servidor foi escrito Ă  mĂŁo, sem SDK, para manter o projeto com zero dependĂŞncias e deixar visĂ­vel o que acontece em cada mensagem do protocolo.

### Ferramentas expostas

| Tool | Descrição |
|---|---|
| `listar_trilhas` | Lista todas as trilhas disponĂ­veis |
| `consultar_trilha` | Plano de estudos de uma trilha/nĂ­vel |
| `gerar_desafio` | Sorteia um desafio de cĂłdigo |
| `emitir_certificado` | Emite um certificado fictĂ­cio |

### Testando manualmente

```bash
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | geo-explorer-mcp
```

### Configurando no Claude Desktop / Claude Code

Adicione ao arquivo de configuração MCP:

```json
{
  "mcpServers": {
    "geo-explorer": {
      "command": "geo-explorer-mcp"
    }
  }
}
```

A documentação completa do protocolo, com exemplos de todas as mensagens, está em [`docs/mcp.md`](docs/mcp.md).

---

## đź§Ş Como executar os testes

```bash
pip install -e ".[dev]"
pytest
```

```
74 passed in 0.12s
```

Outras formas de rodar:

```bash
pytest -v                        # saĂ­da detalhada
pytest tests/test_mcp_server.py  # sĂł o servidor MCP
pytest -k certificado            # sĂł o que menciona "certificado"
```

### O que Ă© testado

| Arquivo | Testes | Cobre |
|---|---|---|
| `test_repository.py` | 18 | Carga da base, busca com acento/caixa/tag, consistência dos dados, arquivos inválidos |
| `test_comando_trilha.py` | 12 | Plano de estudos, nĂ­veis, sugestĂŁo de prĂłximo nĂ­vel, listagem |
| `test_comando_desafio.py` | 9 | Sorteio, reprodutibilidade por seed, cobertura de todas as combinações |
| `test_comando_certificado.py` | 12 | Dados, determinismo e unicidade do código, validação de entrada |
| `test_cli.py` | 11 | CĂłdigos de saĂ­da, formato texto e JSON, erros de argumento |
| `test_mcp_server.py` | 12 | Handshake, catálogo de tools, execução, erros JSON-RPC, sessão completa |

Vale destacar dois testes que pegam problemas de verdade na base de dados:

- `test_carga_horaria_do_nivel_bate_com_a_soma_dos_modulos` — impede que a carga horária declarada divirja da soma dos módulos ao adicionar uma trilha nova;
- `test_toda_trilha_tem_desafio_em_cada_nivel` — impede que uma trilha nova entre sem desafio em algum nível, o que quebraria o comando `desafio`.

---

## 🗂️ Estrutura do projeto

```
geo-explorer/
├── src/geo_explorer/
│   ├── data/trilhas.json      # base fictícia de trilhas e desafios
│   ├── commands/              # um arquivo por comando
│   │   ├── trilha.py
│   │   ├── desafio.py
│   │   └── certificado.py
│   ├── models.py              # dataclasses do domínio
│   ├── repository.py          # única camada que conhece o JSON
│   ├── formatters.py          # dicionário → texto do terminal
│   ├── errors.py              # exceções de domínio
│   ├── cli.py                 # interface de linha de comando
│   └── mcp_server.py          # servidor MCP (JSON-RPC sobre stdio)
├── tests/                     # 74 testes com pytest
├── docs/
│   ├── arquitetura.md
│   ├── mcp.md
│   └── base-de-dados.md
├── examples/                  # exemplos de uso e configuração
├── .claude/commands/          # slash commands para agentes de IA
└── .github/workflows/ci.yml   # testes automáticos a cada push
```

A decisão de arquitetura mais importante: **os comandos devolvem dicionários, não texto**. A formatação vive separada, em `formatters.py`. Foi isso que permitiu que a CLI e o servidor MCP compartilhassem exatamente a mesma lógica — o MCP entrega o texto formatado *e* o JSON estruturado na mesma resposta, sem duplicar uma linha de regra de negócio.

Mais detalhes em [`docs/arquitetura.md`](docs/arquitetura.md).

---

## ✨ Melhorias que eu fiz

Além do fluxo pedido no desafio (trilha, desafio, certificado e servidor MCP):

1. **Comando `listar`** — o desafio original não previa uma forma de descobrir o que existe na base. Sem ele, a pessoa precisa adivinhar o nome da trilha.
2. **Busca tolerante** — `python`, `Python`, `PYTHON`, `Inteligência Artificial`, `inteligencia artificial` e a tag `frontend` chegam à trilha certa. Normalizo removendo acento e caixa antes de comparar.
3. **Mensagens de erro que ensinam** — errar o nome da trilha devolve a lista das trilhas disponíveis, em vez de um "não encontrado" seco.
4. **Flag `--json` global** — todo comando pode ser consumido por script, `jq` ou outro programa.
5. **Desafio reprodutível com `--seed`** — sem isso, um comando que sorteia é impossível de testar de forma determinística.
6. **Código de certificado determinístico** — SHA-256 dos dados, no formato `GEO-XXXX-XXXX-XXXX`, com teste garantindo que muda se qualquer campo mudar.
7. **Sugestão de próximo nível** — ao final do plano de estudos, o comando indica qual é o passo seguinte e como pedi-lo.
8. **Testes de consistência da base** — não testam só o código, testam os *dados*: carga horária coerente, ids únicos, todo nível com desafio.
9. **Zero dependências em runtime** — o servidor MCP foi escrito à mão sobre JSON-RPC. Clona e roda, sem instalar nada.
10. **CI no GitHub Actions** — os testes rodam em Python 3.10, 3.11 e 3.12 a cada push.
11. **Slash commands em `.claude/commands/`** — atalhos para usar o projeto de dentro de um agente de IA.
12. **Três trilhas a mais que o mínimo** — SQL, DevOps e IA, cada uma com 3 níveis e 6 desafios.

---

## 🎓 O que eu aprendi

**Separar dados de apresentação vale mais do que parece.** Comecei fazendo os comandos imprimirem direto na tela. Quando cheguei no servidor MCP, percebi que teria de reescrever tudo — o MCP precisa de dados estruturados, não de texto formatado. Refiz para que cada comando devolvesse um dicionário e a formatação virasse uma camada separada. A partir daí, adicionar o MCP custou quase nada: ele chama a mesma função da CLI.

**Testar aleatoriedade exige projetar para isso.** O comando `desafio` sorteia. Não dava para testar até eu adicionar o parâmetro `seed` e usar `random.Random(seed)` em vez do `random` global. Foi a primeira vez que mudei uma assinatura de função *por causa* do teste — e o resultado ficou melhor também para quem usa, porque agora dá para repetir um desafio específico.

**MCP é mais simples do que o nome sugere.** É JSON-RPC 2.0 sobre stdin/stdout: uma mensagem JSON por linha. Implementar `initialize`, `tools/list` e `tools/call` à mão me fez entender o protocolo de verdade, em vez de só configurar um SDK. Aprendi também uma distinção importante: erro de domínio (trilha inexistente) volta como resultado com `isError: true`, para o agente ler e corrigir; erro de protocolo (método desconhecido) volta como erro JSON-RPC.

**Teste de dados pega o que teste de código não pega.** O `test_carga_horaria_do_nivel_bate_com_a_soma_dos_modulos` falhou de verdade enquanto eu montava a base — eu tinha digitado uma carga horária que não batia com a soma dos módulos. O código estava certo; os dados é que estavam errados.

**Revisar o que o agente escreve é parte do trabalho.** Usei IA como apoio o tempo todo, mas cada arquivo passou por leitura minha. O ponto do desafio não é gerar muitos arquivos — é conseguir explicar cada escolha. Escrever este README foi o teste final disso: o que eu não conseguia explicar, eu não tinha entendido.

---

## 🤝 Créditos

Projeto desenvolvido por **Guilherme Cintra** para o desafio *Construindo Seu Primeiro Produto com um Agente de IA* da [Digital Innovation One](https://dio.me).

- GitHub: [@GuiC1ntra](https://github.com/GuiC1ntra)
- LinkedIn: [guilherme-cintr4](https://linkedin.com/in/guilherme-cintr4)

## 📄 Licença

[MIT](LICENSE) — use, estude e adapte à vontade.