Files
mindforge/project-context.md
Jose Henrique 475a7c120d
All checks were successful
Mindforge Web Build and Deploy (internal) / Build Mindforge Web Image (push) Successful in 2m34s
Mindforge Web Build and Deploy (internal) / Deploy Mindforge Web (internal) (push) Successful in 7s
ui fixes
2026-06-14 15:15:39 -03:00

230 lines
12 KiB
Markdown

# 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.
- **Filtro RAG da "Revisão espaçada"**: o painel inicia com apenas Vermelho e Amarelo selecionados. Os checkboxes de status funcionam como multi-select comum (clicar num selecionado o remove, clicar num não selecionado o adiciona); se o usuário chegar a uma seleção vazia, o sistema força `['Red']` automaticamente para impedir revisão sem status. A lista de arquivos é filtrada pela união dos status marcados.
- **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 e verso azulado. O verso exibe a resposta em cima e a pergunta original embaixo, ambos visíveis ao virar o cartão. Clicar no verso retorna à frente. Os botões "Correto" e "Incorreto" ficam desabilitados enquanto a frente está visível. O card não exibe status RAG, metadados de assunto/subassunto/desempenho/última revisão, dificuldade nem nome do arquivo de origem. O carimbo de feedback ("Correto"/"Incorreto") é renderizado no verso visível antes da saída do cartão, e há 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