new flashcards
All checks were successful
Mindforge API Build and Deploy / Build Mindforge API Image (push) Successful in 4m4s
Mindforge Web Build and Deploy (internal) / Build Mindforge Web Image (push) Successful in 5m29s
Mindforge Web Build and Deploy (internal) / Deploy Mindforge Web (internal) (push) Successful in 9s
Mindforge API Build and Deploy / Deploy Mindforge API (internal) (push) Successful in 8s

This commit is contained in:
2026-05-30 11:59:19 -03:00
parent b9736293d3
commit b80d28f671
27 changed files with 1735 additions and 290 deletions

368
project-context.md Normal file
View File

@@ -0,0 +1,368 @@
# Mindforge
## Visao Geral (Overview)
Mindforge e uma ferramenta de estudo para auxiliar na preparacao para concursos publicos brasileiros. O sistema permite validar e gerar materiais de estudo a partir de arquivos Markdown hospedados em repositorios Git, utilizando IA (OpenRouter/OpenAI-compatible API) para processamento.
A interface e em **portugues brasileiro** e possui um tema escuro com efeito vidro ("glassy-look").
---
## Tech Stack
### Frontend (Mindforge.Web)
| Tecnologia | Versao | Finalidade |
|---|---|---|
| **Preact** | ^10.29.0 | UI library (lightweight React alternative) |
| **Vite** | ^8.0.1 | Build tool e dev server |
| **TypeScript** | ~5.9.3 | Tipagem estatica |
| **marked** | ^17.0.4 | Renderizacao Markdown -> HTML |
| **diff** | ^8.0.3 | Diff de texto (word-level) |
| **Google Fonts (Lato)** | 300/400/700 | Tipografia da interface |
### Backend API (Mindforge.API)
| Tecnologia | Versao | Finalidade |
|---|---|---|
| **.NET 9** | net9.0 | ASP.NET Core Web API |
| **C#** | - | Linguagem |
| **Microsoft.AspNetCore.OpenApi** | 9.0.12 | Suporte OpenAPI/Swagger |
### Cronjob (mindforge.cronjob)
| Tecnologia | Versao | 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 OpenAI-compatible) |
---
## Arquitetura (Architecture)
O projeto e um **monorepo** com tres servicos independentes e deployaveis separadamente.
```
┌─────────────────────────────────────────────────────┐
│ Kubernetes Cluster │
│ ┌──────────────┐ ┌──────────────┐ ┌───────────┐ │
│ │ mindforge-web │ │ mindforge-api│ │ cronjob │ │
│ │ (Preact SPA) │──│ (.NET 9 API) │ │ (Go app) │ │
│ │ port 80 │ │ port 8080 │ │ (weekly) │ │
│ └──────────────┘ └──────┬───────┘ └─────┬─────┘ │
│ │ │ │ │
│ mindforge.haven api.mindforge.haven │ │
└──────────────────────────┼─────────────────┼───────┘
│ │
┌──────┴───────┐ ┌──────┴───────┐
│ OpenRouter │ │ Gitea │
│ (OpenAI API)│ │ (Git repos) │
└──────────────┘ └──────┬───────┘
┌────────┴────────┐
│ Discord │
│ Webhooks │
└─────────────────┘
```
### Servicos
#### 1. Mindforge.Web (Frontend)
- **Tipo**: Single Page Application (SPA)
- **Funcao**: Interface do usuario para validacao de arquivos e geracao de flashcards
- **Modulos**: Home, Verificador, Flashcards
- **Roteamento**: State-based manual via `useState` (nao usa react-router). Componentes sao alternados com `display: block/none`.
- **Estado**: Apenas `useState`/`useEffect` locais. Sem store global, sem Context API.
#### 2. Mindforge.API (Backend)
- **Tipo**: REST API
- **Padrao arquitetural**: Clean layered architecture
- **Controllers** -> validacao e roteamento HTTP
- **Services** -> logica de negocio (FileService, FlashcardService, AgentService, GiteaService)
- **Providers** -> abstracao de APIs externas (OpenAIApiProvider implementa ILlmApiProvider)
- **Middlewares** -> cross-cutting concerns (ExceptionHandlingMiddleware)
- **Models** -> DTOs e tipos de request/response
- **DI**: Todos servicos e providers registrados como Scoped
- **CORS**: Allow all origins
- **Auth**: Nenhuma no momento
#### 3. Mindforge.Cronjob (Background Worker)
- **Tipo**: Kubernetes CronJob
- **Schedule**: Sabados as 9:00 AM
- **Pipeline**:
1. Clona repositorio Git via SSH
2. Encontra arquivos modificados nos ultimos 7 dias (`.md`, exceto `Conteudos.md`)
3. Filtra commits de "refactor" via `git log`
4. Ranqueia por linhas alteradas, seleciona top N (default 10)
5. Gera resumo em texto com IA para cada arquivo
6. Formata resumo em Markdown
7. Envia para Discord via webhook (chunked em 1800 chars)
- **Error handling**: Reporta ao Haven Notify
### Decisoes de Arquitetura (Architecture Decisions)
1. **Sem banco de dados**: Totalmente stateless. Conteudo de estudo vive em repositorios Git, acessados via Gitea API em tempo de request.
2. **Git como content store**: Nao ha upload de arquivos - o conteudo e lido diretamente do repositorio Git.
3. **IA como engine de processamento**: Toda validacao e geracao e delegada ao LLM via OpenRouter.
4. **Provider abstraction**: `ILlmApiProvider` permite trocar o backend de IA sem alterar a logica de negocio.
5. **Monorepo com deploys independentes**: Cada servico tem seu proprio Dockerfile, manifesto K8s e pipeline CI.
6. **Roteamento manual no frontend**: Sem lib de router, toggle de visibilidade via estado.
7. **Preact em vez de React**: Bundle size menor.
---
## Estrutura do Projeto (Project Structure)
```
mindforge/
├── AGENTS.md # Instrucoes para agentes AI
├── project-context.md # Este arquivo - fonte da verdade do projeto
├── README.md
├── mindforge.png # Logo do projeto
├── dev.ps1 / dev.sh # Scripts de inicializacao dev
├── .gitea/workflows/ # CI/CD pipelines
│ ├── mindforge-api.yaml
│ ├── mindforge-web.yaml
│ └── mindforge-cronjob.yaml
├── Mindforge.API/ # Backend .NET 9
│ ├── Program.cs # Entry point: DI, CORS, middleware
│ ├── Controllers/
│ │ ├── FileController.cs # POST /api/v1/file/check
│ │ ├── FlashcardController.cs # POST /api/v1/flashcard/generate
│ │ └── RepositoryController.cs # GET /api/v1/repository/*
│ ├── Services/ # Logica de negocio
│ │ ├── AgentService.cs
│ │ ├── FileService.cs
│ │ ├── FlashcardService.cs
│ │ ├── GiteaService.cs
│ │ └── Interfaces/
│ ├── Providers/
│ │ ├── ILlmApiProvider.cs # Interface do provedor LLM
│ │ └── OpenAIApiProvider.cs # Implementacao OpenAI/OpenRouter com retry
│ ├── Middlewares/
│ │ └── ExceptionHandlingMiddleware.cs
│ ├── Models/
│ │ ├── FileTreeNode.cs
│ │ └── Requests/ # DTOs de request
│ ├── Exceptions/
│ │ └── UserException.cs # 400 Bad Request customizado
│ └── deploy/
│ └── mindforge-api.yaml # Manifest K8s (Deployment + Service + Ingress)
├── Mindforge.Web/ # Frontend Preact + Vite
│ ├── vite.config.ts
│ ├── tsconfig.app.json # Target ES2023, JSX preact, strict mode
│ ├── .env # VITE_API_BASE_URL=http://localhost:5123
│ ├── src/
│ │ ├── main.tsx # Entry point
│ │ ├── app.tsx # Componente raiz: header, sidebar, modulos
│ │ ├── app.css # Estilos hero, animacoes
│ │ ├── index.css # CSS variables, reset, layout base
│ │ ├── services/
│ │ │ └── MindforgeApiService.ts # Cliente API (fetch, interfaces tipadas)
│ │ └── components/
│ │ ├── Button.tsx / .css # Botao reutilizavel (primary/secondary)
│ │ ├── Header.tsx / .css # Header fixo com logo + nome do repo
│ │ ├── Sidebar.tsx / .css # Navegacao lateral
│ │ ├── VerificadorComponent.tsx / .css # Validador de arquivos
│ │ ├── FlashcardComponent.tsx / .css # Gerador de flashcards
│ │ └── FileTreeComponent.tsx / .css # Arvore de arquivos do repo
│ └── deploy/
│ └── mindforge-web.yaml # Manifest K8s
└── mindforge.cronjob/ # CronJob em Go
├── cmd/mindforge.cronjob/main.go # Entry point
├── internal/
│ ├── agent/agent.go # Cria e formata resumos
│ ├── llm/ # Servico LLM
│ ├── git/git.go # Clone, diff, SSH
│ ├── errors/errors.go # Reporte de erros
│ └── message/messages.go # Notificacoes Discord
└── deploy/
└── mindforge-cronjob.yaml # Manifest K8s CronJob
```
---
## API Endpoints
### File Controller (`/api/v1/file`)
| Metodo | Rota | Descricao |
|---|---|---|
| POST | `/api/v1/file/check` | Valida linguagem ou conteudo de um arquivo |
```json
// Request
{
"fileContent": "string (conteudo do arquivo)",
"fileName": "string",
"checkType": "language" | "content"
}
// Response
{
"result": "string (resultado da validacao)"
}
```
### Flashcard Controller (`/api/v1/flashcard`)
| Metodo | Rota | Descricao |
|---|---|---|
| POST | `/api/v1/flashcard/generate` | Gera flashcards em CSV |
```json
// Request
{
"fileContent": "string",
"fileName": "string",
"amount": 10,
"mode": "Basic" | "Simple" | "Detailed" | "Hyper"
}
// Response
{
"result": "string (CSV: Frente;Verso\nFrente;Verso\n...)"
}
```
### Repository Controller (`/api/v1/repository`)
| Metodo | Rota | Descricao |
|---|---|---|
| GET | `/api/v1/repository/info` | Nome do repositorio |
| GET | `/api/v1/repository/tree` | Arvore de arquivos do repositorio |
| GET | `/api/v1/repository/file?path=...` | Conteudo de um arquivo especifico |
---
## Convencoes de Desenvolvimento (Development Conventions)
### Frontend (Preact/TypeScript)
- **Componentes**: Funcoes nomeadas exportadas com `export function Nome()`. Sem `export default`.
- **Props**: Interfaces TypeScript definidas no mesmo arquivo do componente.
- **Hooks**: `useState`, `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**: Alternancia de componentes via `display: block/none` com estado `activeModule`. Nao usa react-router.
- **API**: Chamadas via `MindforgeApiService` (objeto singleton com metodos estaticos usando `fetch`).
- **TypeScript**: Strict mode, `erasableSyntaxOnly`, `verbatimModuleSyntax`, `noUnusedLocals`, `noUnusedParameters`.
- **Alias**: `react` e `react-dom` mapeados para `preact/compat/` no tsconfig.
### Backend (C#/.NET 9)
- **Namespaces**: `Mindforge.API.Controllers`, `Mindforge.API.Services`, etc.
- **Interfaces**: Prefixo `I` (ex: `IFileService`, `ILlmApiProvider`).
- **DI**: Todos servicos registrados como `Scoped` em `Program.cs`.
- **Controllers**: Atributo `[Route("api/v1/...")]`. Metodos retornam `IActionResult`.
- **Tratamento de erros**: `ExceptionHandlingMiddleware` captura `UserException` (400) e excecoes genericas (500).
### UI/UX
- **Idioma**: Todo texto em **portugues brasileiro**.
- **Tema**: Escuro com efeito vidro (glassy). `backdrop-filter: blur()`, fundos `rgba` semitransparentes.
- **Botoes**: Estilo iOS-like, modernos. Variantes `primary` (com blur) e `secondary` (transparente).
- **Tipografia**: Lato (Google Fonts), pesos 300/400/700.
- **Background**: `#005873` (azul petroleo escuro). Nao muito escuro.
### CSS Variables (definidas em `index.css`)
```css
--color-bg: #005873;
--color-header: #0f0f0f;
--color-sidebar: #013a4c;
--color-text-creamy: #f4f5f5;
--color-accent: #00b4d8;
--color-accent-rgb: 0, 180, 216;
--color-accent-hover: #0096c7;
--font-main: 'Lato', sans-serif;
```
### Git
- Branches: `main` (producao)
- CI/CD: Gitea Actions dispara no push para main, build com Docker Buildx multi-arch, push para Gitea Container Registry, deploy no K8s.
---
## Configuracao & Environment Variables
### API (Mindforge.API)
| Variavel | Descricao |
|---|---|
| `OPENAI_API_URL` | URL do endpoint OpenAI-compatible (OpenRouter) |
| `OPENAI_TOKEN` | Token de autenticacao da API |
| `OPENAI_MODEL` | Modelo LLM a ser usado |
| `GITEA_REPO_URL` | URL do repositorio Gitea |
| `GITEA_ACCESS_TOKEN` | Token de acesso ao Gitea |
### Web (Mindforge.Web)
| Variavel | Descricao |
|---|---|
| `VITE_API_BASE_URL` | URL base da API (default: `http://localhost:5123`) |
### Cronjob
| Variavel | Descricao |
|---|---|
| `GIT_REPOSITORY` | URL do repo Git a clonar |
| `DISCORD_WEBHOOK_URL` | Webhook do Discord para notificacoes |
| `OPENAI_API_URL` | URL do endpoint OpenAI |
| `OPENAI_TOKEN` | Token de autenticacao |
| `HAVEN_NOTIFY_URL` | URL do servico 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/Analise e Engenharia de Dados/Data Lake e Data Warehouse.md
- [base]/Concursos/TI/Rede/VLAN.md
- [base]/Concursos/TI/Rede/Email/IMAP e POP3.md
---
## Atualizacao - Flashcards Persistidos (2026-05-30)
### Mudancas de Arquitetura
- A API deixa de ser totalmente stateless para o dominio de flashcards.
- Flashcards agora sao persistidos em PostgreSQL (`mindforge`) via `Dapper` + `Npgsql`.
- O schema e criado de forma idempotente no startup da API.
### Tabelas de Flashcard
- `flashcard_libraries`: `id`, `file_path` (unico), `file_name`, `subject`, `difficulty`, `card_count`, `created_at`, `updated_at`.
- `flashcards`: `id`, `library_id`, `front`, `back`, `position`, `created_at`.
### API de Flashcards (v1)
- `POST /api/v1/flashcard/generate`
Request: `{ filePaths: string[], amount: 10-30, difficulty: "Easy" | "Hard" }`
Comportamento: gera por arquivo selecionado, substitui biblioteca anterior do mesmo `file_path` e retorna bibliotecas com cards.
- `GET /api/v1/flashcard/libraries`
Lista todas as bibliotecas persistidas, com `subject` para agrupamento na UI.
- `GET /api/v1/flashcard/libraries/{id}`
Retorna detalhes de uma biblioteca com seus cards.
- `POST /api/v1/flashcard/review-session`
Request: `{ libraryIds: number[] }`
Retorna os cards combinados para sessao de revisao (sem repeticao espaciada nesta fase).
### Frontend
- Modulo `Flashcards` atualizado para:
- selecionar multiplos arquivos;
- definir quantidade fixa por arquivo (10-30);
- definir dificuldade (`Facil`/`Dificil`);
- gerar e exibir resumo das bibliotecas salvas (sem download CSV).
- Novo modulo `Revisao Flashcards`:
- lista bibliotecas agrupadas por materia (`subject`);
- permite selecionar multiplas bibliotecas;
- inicia sessao estilo Anki simplificada (frente, revelar verso, anterior/proximo, progresso visual).
### Novas Configuracoes
- `ConnectionStrings:MindforgeDb` para conexao PostgreSQL.
- Fallback local/default:
`Host=localhost;Port=3307;Database=mindforge;Username=root;Password=root`.