# Mindforge

## Visão Geral

Mindforge é uma ferramenta de estudo para auxiliar na preparação para concursos públicos brasileiros. O sistema permite validar e gerar materiais de estudo a partir de arquivos Markdown hospedados em repositórios Git, utilizando IA (API compatível com OpenRouter/OpenAI) para processamento.

A interface é em **português brasileiro** e possui um tema claro quente com estética vintage acadêmica — tons de creme, pergaminho e dourado com texturas de papel, seguindo as diretrizes em `GUIDELINES-ESTILO.md`.

---

## Stack Tecnológica

### Frontend (Mindforge.Web)
| Tecnologia | Versão | Finalidade |
|---|---|---|
| **Preact** | ^10.29.0 | Biblioteca de interface (alternativa leve ao React) |
| **Vite** | ^8.0.1 | Ferramenta de build e servidor de desenvolvimento |
| **TypeScript** | ~5.9.3 | Tipagem estática |
| **marked** | ^17.0.4 | Renderização Markdown -> HTML |
| **diff** | ^8.0.3 | Diff de texto (word-level) |

> Nota: `marked` v17+ inclui tipos TypeScript nativos. `@types/marked` foi removido. `@types/diff` v7 permanece em devDependencies como fallback de tipos.
| **Google Fonts (Inter)** | 400..950 (variável) | Tipografia da interface |

### Backend API (Mindforge.API)
| Tecnologia | Versão | Finalidade |
|---|---|---|
| **.NET 9** | net9.0 | ASP.NET Core Web API |
| **C#** | - | Linguagem |
| **Microsoft.AspNetCore.OpenApi** | 9.0.12 | Suporte OpenAPI/Swagger |
| **Dapper** | 2.1.66 | Acesso a dados do domínio de flashcards |
| **Npgsql** | 9.0.4 | Driver PostgreSQL para persistência de flashcards |

### Cronjob (mindforge.cronjob)
| Tecnologia | Versão | Finalidade |
|---|---|---|
| **Go** | 1.22 | Linguagem |
| **godotenv** | v1.5.1 | Carregamento de arquivos .env |

### Infraestrutura
| Tecnologia | Finalidade |
|---|---|
| **Docker** | Imagens multi-arch (amd64, arm64) |
| **Kubernetes** | Orquestracao (Deployments, CronJobs, Services, Ingress) |
| **Gitea** | Git hosting + Container registry (`git.ivanch.me`) |
| **Gitea Actions** | CI/CD (build & deploy no push para main) |
| **Nginx Ingress** | K8s ingress controller |
| **OpenRouter API** | Provedor LLM (endpoint compatível com OpenAI) |

---

## Arquitetura

O projeto é um monorepo com três serviços independentes.
- `Mindforge.Web`: SPA em Preact/Vite com navegação manual por estado e sem `react-router`.
- `Mindforge.API`: REST API em camadas com Controllers, Services, Repositories, Providers, Middlewares e Models; o domínio de flashcards é persistido em PostgreSQL (`mindforge`) via `Dapper` + `Npgsql`, com schema criado no startup.
- `mindforge.cronjob`: worker em Go executado semanalmente para resumir alterações recentes em arquivos `.md`.
- Integrações principais: OpenRouter para IA, Gitea como repositório de conteúdo e Discord via webhook para notificações.
- Deploy: cada serviço possui Dockerfile, manifesto Kubernetes e pipeline independente no Gitea Actions.
- Decisões-chave: Git como content store, revisão espaçada calculada em leitura e Preact em vez de React.

---

## Estrutura do Projeto

- `mindforge/`: raiz do projeto com documentação, scripts, logo e workflows do Gitea.
- `Mindforge.API/`: backend .NET 9 com controllers, services, repositories, providers, models e deploy Kubernetes.
- `Mindforge.Web/`: frontend Preact + Vite com componentes de interface, cliente de API e deploy Kubernetes.
- `mindforge.cronjob/`: worker em Go com lógica de IA, Git, erros e mensagens do Discord, além do deploy Kubernetes.

---

## Endpoints da API

### Controller de Arquivos (`/api/v1/file`)
| Método | Rota | Descrição |
|---|---|---|
| POST | `/api/v1/file/check` | Valida a linguagem ou o conteúdo de um arquivo |

```json
// Request
{
  "fileContent": "string (conteudo do arquivo)",
  "fileName": "string",
  "checkType": "language" | "content"
}

// Response
{
  "result": "string (resultado da validacao)"
}
```

### Controller de Flashcards (`/api/v1/flashcard`)
| Método | Rota | Descrição |
|---|---|---|
| POST | `/api/v1/flashcard/generate` | Gera ou substitui bibliotecas de flashcards a partir dos arquivos selecionados |
| GET | `/api/v1/flashcard/libraries` | Lista todas as bibliotecas persistidas |
| GET | `/api/v1/flashcard/libraries/{id}` | Retorna uma biblioteca específica com seus cards |
| POST | `/api/v1/flashcard/review-session` | Inicia uma sessão de revisão com bibliotecas selecionadas |
| POST | `/api/v1/flashcard/review-answer` | Registra se a resposta do card estava correta |
| GET | `/api/v1/flashcard/rag-status` | Retorna o dashboard de revisão espaçada por matéria/submatéria |

Formas de requisição principais:
- `POST /api/v1/flashcard/generate`: `{ filePaths: string[], amount: 10-30, difficulty: "Easy" | "Hard" }`
- `POST /api/v1/flashcard/review-session`: `{ libraryIds: number[] }`
- `POST /api/v1/flashcard/review-answer`: `{ cardId: number, correct: boolean }`

### Controller de Repositório (`/api/v1/repository`)
| Método | Rota | Descrição |
|---|---|---|
| GET | `/api/v1/repository/info` | Nome do repositório |
| GET | `/api/v1/repository/tree` | Árvore de arquivos do repositório |
| GET | `/api/v1/repository/file?path=...` | Conteúdo de um arquivo específico |

---

## Convenções de Desenvolvimento

### Frontend (Preact/TypeScript)
- **Componentes**: Funções nomeadas exportadas com `export function Nome()`. Sem `export default`.
- **Props**: Interfaces TypeScript definidas no mesmo arquivo do componente.
- **Hooks**: `useState` e `useEffect` importados de `preact/hooks`.
- **Children**: Tipados como `ComponentChildren` de `preact`.
- **CSS**: Um arquivo `.css` por componente, importado diretamente. **Sem CSS Modules.**
- **Estado**: Apenas estado local (`useState`). Sem store global, sem Context API.
- **Roteamento**: Alternância de componentes via `display: block/none` com o estado `activeModule`. Não usa `react-router`.
- **API**: Chamadas via `MindforgeApiService` (objeto singleton com métodos assíncronos usando `fetch`).
- **TypeScript**: Modo estrito, `erasableSyntaxOnly`, `verbatimModuleSyntax`, `noUnusedLocals`, `noUnusedParameters`.
- **Alias**: `react` e `react-dom` mapeados para `preact/compat/` no tsconfig.
- **Layout**: `.app` usa CSS Grid (`grid-template-columns: 288px 1fr`) com Sidebar sticky + `.main` contendo Topbar e área de conteúdo.

### Backend (C#/.NET 9)
- **Namespaces**: `Mindforge.API.Controllers`, `Mindforge.API.Services`, etc.
- **Interfaces**: Prefixo `I` (ex.: `IFileService`, `ILlmApiProvider`).
- **DI**: Todos os serviços registrados como `Scoped` em `Program.cs`. `HttpClient` obtido via `IHttpClientFactory` (não injetado diretamente).
- **Controllers**: Atributo `[Route("api/v1/...")]`. Métodos retornam `IActionResult`.
- **Tratamento de erros**: `ExceptionHandlingMiddleware` captura `UserException` (400) e exceções genéricas (500).

### UI/UX
- **Idioma**: Todo texto em **português brasileiro**, com acentuação e grafia corretas nas telas e mensagens.
- **Navegação**: Os rótulos visíveis da revisão usam "Revisão de Flashcards" e "Revisão espaçada" como nomes canônicos. A marca Mindforge na sidebar navega para a página inicial.
- **Revisão de flashcards**: "Revisão de Flashcards" e "Revisão espaçada" mantêm seleção/filtros próprios, mas compartilham a mesma sessão visual (`FlashcardStudySession`) com título "Sessão de Revisão", flip 3D, atalhos, fila/progresso, carimbo e confete.
- **Tema**: Claro quente vintage ("mesa de estudo pessoal"). Fundos creme/pergaminho/dourado com textura de papel (grid via `body::before`). Vidro translúcido com `backdrop-filter` em tons quentes.
- **Botões**: Estilo pill quente com sombras marrons. Variantes `primary` (gradiente azul, com brilho hover) e `secondary` (translúcido pergaminho).
- **Tipografia**: Inter (UI global), Georgia/Times New Roman (marca e cabeçalhos), Segoe UI/Inter (conteúdo do flashcard).
- **Background**: Gradiente radial quente (dourado/azul) sobre base `#fff8e6` com overlay de grid de papel 24px.
- **Layout**: CSS Grid (`grid-template-columns: 288px minmax(0, 1fr)`). Sidebar sticky com textura diagonal. Topbar integrada ao fluxo (não fixa).
- **Animações**: Apenas sob ação do usuário (flip 3D do flashcard, carimbo, saída do cartão, confete canvas). Sem animações infinitas ou spinners.
- **Flashcard**: Cartão 3D com efeito `rotateY(180deg)`, frente papel pautado com borda tracejada, verso azulado que mostra pergunta menor + resposta principal. Carimbo de feedback ("Correto"/"Incorreto") é renderizado no verso visível antes da saída do cartão. Confete canvas ao acertar.
- **Responsivo**: Breakpoints em 1120px (sidebar colapsada) e 760px (layout single-column).

### Variáveis CSS (definidas em `index.css`)
```css
--bg: #fbf3df;
--bg-soft: #fff9ea;
--paper: #fffaf0;
--paper-deep: #f2dfb3;
--ink: #2b241c;
--muted: #7b6a50;
--line: rgba(82, 60, 28, 0.18);
--blue: #3f7cac;
--blue-deep: #255f8d;
--green: #4f8f5a;
--green-deep: #32683b;
--red: #b75b4d;
--red-deep: #8d3c32;
--gold: #c79539;
--violet: #7e65a8;
--shadow: 0 28px 70px rgba(58, 42, 17, 0.18);
--card-shadow: 0 30px 90px rgba(76, 48, 12, 0.20);
--radius-xl: 32px;
--radius-lg: 22px;
--radius-md: 16px;
--ease: cubic-bezier(.2,.75,.2,1);
```

### Git e Scripts de Build/Deploy
- Branches: `main` (produção)
- CI/CD: Gitea Actions dispara no push para `main`, faz build com Docker Buildx multi-arch, envia para o Gitea Container Registry e faz o deploy no K8s.
- Build Local: `re-build.ps1` detecta Docker local; se ausente, envia o projeto via SSH para `iris.haven` e executa `docker buildx bake --load` remotamente. Se Docker CLI presente, usa `DOCKER_HOST` para fallback remoto.
- Deploy Local: `re-deploy.ps1` executa o build das imagens e aplica as atualizações no cluster Kubernetes.
- API Dockerfile: mapeia `TARGETARCH=amd64` para `x64` (arquitetura esperada pelo .NET).


---

## Configuração e Variáveis de Ambiente

### API (Mindforge.API)
| Variável | Descrição |
|---|---|
| `OPENAI_API_URL` | URL do endpoint compatível com OpenAI (OpenRouter) |
| `OPENAI_TOKEN` | Token de autenticação da API |
| `OPENAI_MODEL` | Modelo LLM a ser usado |
| `GITEA_REPO_URL` | URL do repositório Gitea |
| `GITEA_ACCESS_TOKEN` | Token de acesso ao Gitea |
| `ConnectionStrings:MindforgeDb` | Conexão PostgreSQL usada pelo domínio de flashcards |

Fallback local/padrão para o banco de flashcards:
`Host=localhost;Port=3307;Database=mindforge;Username=root;Password=root`.

### Web (Mindforge.Web)
| Variável | Descrição |
|---|---|
| `VITE_API_BASE_URL` | URL base da API (padrão: `http://localhost:5123`) |

### Cronjob
| Variável | Descrição |
|---|---|
| `GIT_REPOSITORY` | URL do repositório Git a clonar |
| `DISCORD_WEBHOOK_URL` | Webhook do Discord para notificações |
| `OPENAI_API_URL` | URL do endpoint OpenAI |
| `OPENAI_TOKEN` | Token de autenticação |
| `HAVEN_NOTIFY_URL` | URL do serviço de reporte de erros |

## Repositório base para os arquivos
A base do repositório para os arquivos de estudo (compartilhado pelo Obsidian) é https://git.ivanch.me/ivanch/concurso.
Ele segue o padrão `[base]/concurso/[Matéria]/[SubMatéria*]/[Arquivo]`, onde [base] é a URL do Git, `concurso` é o nome da pasta dentro do Git base, `Matéria` é o nome da matéria (ex.: `Direito Constitucional`), `SubMatéria` é o nome da submatéria (ex.: `Poder Legislativo`) - podendo ser opcional e com múltiplas submatérias - e `Arquivo` é o nome do arquivo (ex.: `Câmara dos Deputados.md`).

Exemplos:
- [base]/Concursos/Direito Constitucional/Poder Legislativo/Câmara dos Deputados.md
- [base]/Concursos/Direito Constitucional/Poder Legislativo/CPIs.md
- [base]/Concursos/Direito Constitucional/Ciência, Meio Ambiente e Índios.md
- [base]/Concursos/Direito Constitucional/Ciência, Meio Ambiente e Índios.md
- [base]/Concursos/TI/Análise e Engenharia de Dados/Data Lake e Data Warehouse.md
- [base]/Concursos/TI/Rede/VLAN.md
- [base]/Concursos/TI/Rede/E-mail/IMAP e POP3.md
