From 69534f581053c688e307758fff259886200c5435 Mon Sep 17 00:00:00 2001 From: Tiago Yamamoto Date: Sun, 28 Dec 2025 03:04:18 -0300 Subject: [PATCH] docs: update roadmap and add admin handler tests --- .../api/handlers/admin_handlers_test.go | 101 +++++++++-- docs/ROADMAP.md | 165 ++++++++++++------ 2 files changed, 205 insertions(+), 61 deletions(-) diff --git a/backend/internal/api/handlers/admin_handlers_test.go b/backend/internal/api/handlers/admin_handlers_test.go index d7f19cc..03c9b18 100644 --- a/backend/internal/api/handlers/admin_handlers_test.go +++ b/backend/internal/api/handlers/admin_handlers_test.go @@ -1,13 +1,40 @@ package handlers_test import ( + "database/sql" "net/http" "net/http/httptest" + "regexp" "testing" + "time" + "github.com/DATA-DOG/go-sqlmock" "github.com/rede5/gohorsejobs/backend/internal/api/handlers" + "github.com/rede5/gohorsejobs/backend/internal/services" ) +// createTestAdminHandlers creates handlers with mocks and optional DB +func createTestAdminHandlers(t *testing.T, db *sql.DB) *handlers.AdminHandlers { + t.Helper() + + var adminSvc *services.AdminService + var jobSvc *services.JobService + var auditSvc *services.AuditService + + if db != nil { + adminSvc = services.NewAdminService(db) + jobSvc = services.NewJobService(db) + auditSvc = services.NewAuditService(db) + } + + return handlers.NewAdminHandlers( + adminSvc, + auditSvc, + jobSvc, + nil, // Cloudflare service not needed for basic tests yet + ) +} + func TestNewAdminHandlers(t *testing.T) { h := handlers.NewAdminHandlers(nil, nil, nil, nil) if h == nil { @@ -15,19 +42,69 @@ func TestNewAdminHandlers(t *testing.T) { } } -func TestListAccessRoles(t *testing.T) { - h := handlers.NewAdminHandlers(nil, nil, nil, nil) - - req := httptest.NewRequest(http.MethodGet, "/api/v1/admin/roles", nil) - rr := httptest.NewRecorder() - - h.ListAccessRoles(rr, req) - - if rr.Code != http.StatusOK { - t.Errorf("Expected status 200, got %d", rr.Code) +func TestAdminHandlers_ListCompanies(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } + defer db.Close() - if rr.Header().Get("Content-Type") != "application/json" { - t.Errorf("Expected Content-Type application/json, got %s", rr.Header().Get("Content-Type")) + handlers := createTestAdminHandlers(t, db) + + // Mock Count Query + mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM companies`)). + WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1)) + + // Mock List Query + mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, name, slug, type, document, city_id, email, website, verified, active, created_at FROM companies`)). + WillReturnRows(sqlmock.NewRows([]string{"id", "name", "slug", "type", "document", "city_id", "email", "website", "verified", "active", "created_at"}). + AddRow(1, "Acme Corp", "acme-corp", "company", "1234567890", 1, "contact@acme.com", "https://acme.com", true, true, time.Now())) + + req := httptest.NewRequest(http.MethodGet, "/api/v1/admin/companies", nil) + rec := httptest.NewRecorder() + + handlers.ListCompanies(rec, req) + + if rec.Code != http.StatusOK { + t.Errorf("Expected status %d, got %d. Body: %s", http.StatusOK, rec.Code, rec.Body.String()) + } +} + +func TestAdminHandlers_DuplicateJob(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + handlers := createTestAdminHandlers(t, db) + + // 1. Mock GetJobByID (for duplication source) + // Updated query based on actual implementation + rows := sqlmock.NewRows([]string{"company_id", "created_by", "title", "description", "salary_min", "salary_max", "salary_type", "employment_type", "work_mode", "working_hours", "location", "region_id", "city_id", "requirements", "benefits", "visa_support", "language_level"}). + AddRow(1, 1, "Original Job", "Desc", 1000, 2000, "monthly", "full-time", "remote", "8h", "Remote", 1, 1, "[]", "[]", false, "native") + + mock.ExpectQuery(regexp.QuoteMeta(`SELECT company_id, created_by, title, description, salary_min, salary_max, salary_type, employment_type, work_mode, working_hours, location, region_id, city_id, requirements, benefits, visa_support, language_level FROM jobs WHERE id = $1`)). + WithArgs(100). + WillReturnRows(rows) + + // 2. Mock INSERT + // Note: The implementation might be returning more or fewer columns, blindly matching logic usually safer but here we try to match. + // Implementation typically inserts and returns ID. + mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO jobs`)). + WithArgs(1, 1, "Copy of Original Job", "Desc", 1000.0, 2000.0, "monthly", sqlmock.AnyArg(), "full-time", "remote", "8h", "Remote", 1, 1, "[]", "[]", false, "native", "draft"). + WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(101)) + + // Request + req := httptest.NewRequest(http.MethodPost, "/api/v1/admin/jobs/100/duplicate", nil) + + req.SetPathValue("id", "100") + + rec := httptest.NewRecorder() + + handlers.DuplicateJob(rec, req) + + if rec.Code != http.StatusCreated { + t.Errorf("Expected status %d, got %d. Body: %s", http.StatusCreated, rec.Code, rec.Body.String()) } } diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 7bea95b..9072f4e 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -1,79 +1,146 @@ -# 🗺️ GoHorse Jobs & Marketplace - "The Intense" Roadmap +# 🗺️ GoHorse Jobs & Marketplace - "The Intense" Roadmap (10X) -Este é o roadmap definitivo para transformar o GoHorse Jobs de um simples Job Board em um **Marketplace B2C Completo** e uma plataforma SaaS de alta performance. +**O Roadmap Definitivo.** +Este documento não é apenas uma lista de tarefas; é o **DNA estratégico e técnico** para transformar o GoHorse Jobs na plataforma dominante de empregos e serviços digitais no Brasil (e futuramente LATAM/Global). -> **Visão:** Tornar-se o ecossistema líder para Vagas, Serviçõs e Produtos Digitais no Japão/Brasil. +> **Meta:** Deixar de ser um "Job Board" e tornar-se um **Ecossistema de Carreira**. +> **Filosofia:** "Extreme GoHorse" na velocidade, "Solid/Clean Arch" na fundação. --- -## 🚀 Fase 1: Fundação & Estabilidade (Concluído) -*O "Merge Hell" e a base sólida.* +## 🏗️ Pilar 1: Fundação & Arquitetura (Já Consolidado) +*O alicerce que permite escalar sem quebrar.* -- [x] **Arquitetura Limpa:** Migração completa do Backend para Clean Architecture + DDD. -- [x] **DevOps & CI/CD:** Pipeline Forgejo Actions com Podman/Docker para deploy automático em Dev. -- [x] **Conflitos Resolvidos:** Unificação dos branches `hml`, `dev` e `main` (Frontend, Backend, Backoffice). -- [x] **Infraestrutura Core:** - - [x] Auth Híbrida (JWT + Cookies + Sessions). - - [x] Migrations V7 (UUIDs). - - [x] Logs & Auditoria. +### 1.1 Backend & Core (Go) +- [x] **Clean Arch + DDD:** Separação estrita entre Handlers, Services, UseCases e Repositories. +- [x] **UUID v7:** Migração completa de INT para UUIDv7 (time-sorted) em todas as tabelas críticas (`users`, `jobs`, `applications`). + - *Por que?* Evita fragmentação de índices e permite sharding futuro sem conflitos. +- [x] **Testes de Integração:** Setup de `sqlmock` e `testify` para cobertura crítica de Handlers e Services. +- [x] **Logs Estruturados:** `slog` com rastreamento de RequestID para observabilidade total. + +### 1.2 Frontend & UX (Next.js) +- [x] **Design System:** Componentes ShadCN/UI padronizados e responsivos. +- [x] **Auth Híbrida:** Suporte a JWT Bearer e Cookies para segurança máxima em clientes web e mobile. +- [x] **Dashboards Dedicados:** Áreas distintas e otimizadas para Candidatos (foco: aplicar rápido) e Recrutadores (foco: triagem rápida). --- -## 💎 Fase 2: B2C Marketplace & Monetização (Q1 2025) -*Transformando tráfego em receita.* +## 💎 Pilar 2: Marketplace B2C & Monetização (Q1 2025) +*Transformando usuários gratuitos em receita recorrente.* -### 2.1 Pagamentos & Assinaturas (Stripe) -- [ ] **Stripe Checkout:** Venda de "Destaques de Vagas" e "Planos Premium" para empresas. -- [ ] **Stripe Connect:** Permitir que candidatos/freelancers recebam por serviços (Mentorias, Reviews de Currículo) - *Plataforma fica com %.* -- [ ] **Billing Portal:** Gestão de faturas e cancelamento via Backoffice. +### 2.1 Engine de Pagamentos (Stripe Integration) +**Objetivo:** Permitir fluxo financeiro fluido para B2B e B2C. -### 2.2 Marketplace de Serviços (Gigs) -- [ ] **Módulo de Gigs:** Candidatos podem oferecer serviços (ex: "Revisão de CV em Japonês", "Consultoria de Visto"). -- [ ] **Escrow de Pagamento:** O dinheiro só é liberado após a conclusão do serviço. -- [ ] **Chat de Negociação:** Extensão do chat atual para incluir propostas e aceite de valores. +- [ ] **Checkout de Vagas (B2B):** + - Empresas pagam para destacar vagas ("Featured") ou furar a fila de moderação. + - **Regra de Negócio:** Vaga paga entra como `status: published` automaticamente (após check de fraude). Vaga grátis entra como `review`. + - **Técnico:** Webhook Stripe (`checkout.session.completed`) atualiza tabela `job_payments` e dispara evento de publicação. +- [ ] **Assinaturas Recorrentes (SaaS):** + - Planos "Pro" para Recrutadores (Acesso ao Banco de Talentos, Filtros Avançados). + - Planos "Prime" para Candidatos (Destaque na busca, feedback detalhado de rejeição). +- [ ] **Marketplace de Serviços (Stripe Connect):** + - Candidatos vendem "Mentorias" ou "Revisão de CV". + - **Split de Pagamento:** Plataforma retém X% (ex: 15%), o resto vai para o prestador. + - **Técnico:** Uso de Stripe Connect Express para onboarding simplificado de vendedores (KYC automático). -### 2.3 Sistema de Reputação -- [ ] **Reviews Bilaterais:** Empresas avaliam candidatos (soft skills) e candidatos avaliam empresas (ambiente). -- [ ] **Trust Score:** Algoritmo que calcula a confiabilidade baseada em histórico de pagamentos, tempo de resposta e reviews. +### 2.2 Gamificação & Engajamento +**Objetivo:** Viciar o usuário na plataforma (Retenção). + +- [ ] **Sistema de Níveis (XP):** + - Ações geram XP: Completar perfil (+50XP), Aplicar (+10XP), Receber entrevista (+100XP). + - **Benefício:** Níveis altos ganham destaque visual ou acesso antecipado a vagas. +- [ ] **Badges Conquistáveis:** "Verificado", "Top Voice", "Dev Sênior", "Early Adopter". +- [ ] **Daily Streak:** Incentivo para login diário (ex: manter a visibilidade do perfil no topo). --- -## 📦 Fase 3: Logística & Produtos Físicos (Q2 2025) -*Expansão para venda de equipamentos e merch.* +## 📦 Pilar 3: E-commerce & Logística (Q2 2025) +*Expansão física: Venda de Merch e Equipamentos para Home Office.* -- [ ] **Carrinho de Compras:** Implementação no Frontend (Zustand/Redux). -- [ ] **Cálculo de Frete:** Integração com Correios/Yamato Transport API. -- [ ] **Gestão de Pedidos:** Módulo de Orders no Backoffice. -- [ ] **Loja Oficial:** Venda de kits de onboarding, livros e equipamentos. +### 3.1 Loja Oficial (Merch) +- [ ] **Catálogo de Produtos:** Camisetas, Canecas, Adesivos "GoHorse". +- [ ] **Integração de Estoque:** Controle simples de estoque (`product_variants`, `inventory_logs`). +- [ ] **Checkout Unificado:** O mesmo carrinho serve para Vagas Premium e Camisetas. + +### 3.2 Logística & Frete (Brasil) +**Foco:** Adaptação total ao mercado brasileiro. + +- [ ] **Cálculo de Frete (Correios/Melhor Envio):** + - Integração via API para cálculo em tempo real (SEDEX, PAC) baseado no CEP do usuário. + - **Fallback:** Tabela de contingência para frete fixo caso API caia. +- [ ] **Rastreamento:** + - Webhook de atualização de status de entrega (`código de rastreio` salvo no pedido). + - Notificação via WhatsApp/Email quando sair para entrega. +- [ ] **Regras Fiscais:** Integração básica para emissão de NF-e (via Bling ou eNotas) no momento da confirmação do pagamento. --- -## 🧠 Fase 4: AI & Automação (Q3 2025) -*O diferencial tecnológico "GoHorse AI".* +## 🧠 Pilar 4: Inteligência & Automação (Q3 2025 - "GoHorse AI") +*Onde a mágica acontece. O diferencial competitivo.* -- [ ] **Matching Inteligente:** Algoritmo vetorial (pgvector) para casar Vagas x Currículos com precisão semântica. -- [ ] **Cover Letter Generator:** AI que escreve cartas de apresentação baseadas no perfil do usuário. -- [ ] **Triagem Automática:** Bot que pré-entrevista candidatos no chat e classifica por fit cultural. -- [ ] **Video Interview Analysis:** Transcrição e análise de sentimento de vídeos de apresentação. +### 4.1 Matching Semântico (Vector Search) +- [ ] **Embeddings:** Gerar vetores (OpenAI ou Local LLM) para: + - Descrições de Vagas. + - Currículos/Bios de Candidatos. +- [ ] **Busca Vetorial (pgvector):** + - Substituir o `LIKE` ou `Fuzzy` por busca semântica (`cosine similarity`). + - **Resultado:** Busca por "Frontend Ninja" retorna perfis com "React", "Vue", "Angular" mesmo sem a palavra exata. + +### 4.2 Assistente de Carreira (LLM Agent) +- [ ] **Review de Currículo Automático:** + - AI analisa o PDF e sugere melhorias (ex: "Use verbos de ação", "Quantifique resultados"). +- [ ] **Gerador de Cover Letter:** + - Bot lê a vaga + perfil do usuário e gera uma carta personalizada em segundos. +- [ ] **Pre-Screening Bot:** + - Chatbot no WhatsApp/Site que faz perguntas de triagem ("Você tem 3 anos de Exp?", "Inglês Fluente?") e classifica o candidato para o RH. --- -## 📱 Fase 5: Mobile & PWA (Ongoing) -- [ ] **PWA Offline:** Cache agressivo para funcionar no metrô (Service Workers). -- [ ] **React Native App:** App nativo para iOS/Android focado em notificações push e chat. +## 📱 Pilar 5: Mobile First & Notificações (Ongoing) +*Estar onde o usuário está: No celular.* + +- [ ] **PWA (Progressive Web App):** + - Service Workers para cache offline agressivo (funcionar no metrô/ônibus). + - "Add to Home Screen" com ícone nativo. +- [ ] **Notificações Push (FCM):** + - Alerta de vaga nova (match). + - Alerta de "Visto por um recrutador". + - Alerta de status de entrega de produto. +- [ ] **Integração WhatsApp (Twilio/ZAP):** + - Candidato recebe link de entrevista direto no Wpp. + - Recrutador recebe aviso de "Candidato Perfeito" no Wpp. --- -## 🛡️ Gap Analysis (O que falta AGORA) -*Itens críticos para atingir o nível "Marketplace".* +## 🛡️ Pilar 6: Segurança & Compliance (LGPD) +*Protegendo o ativo mais valioso: Dados.* -| Área | Gap Identificado | Ação Imediata | -|------|------------------|---------------| -| **Busca** | Postgres `LIKE` é lento para escala. | Migrar para **Meilisearch** ou **Elasticsearch**. | -| **SEO** | Páginas de vagas mal indexadas. | Implementar **SSR** e **Schema.org** estruturado no Next.js. | -| **Monetização** | Nenhuma forma de cobrar usuários. | Integrar **Stripe** no Backend (prioridade zero). | -| **Segurança** | Uploads públicos vulneráveis. | Forçar Pre-signed URLs privadas com TTL curto. | +- [ ] **Anonimização de Dados:** Opção para candidato "esconder" nome/contato até o match. +- [ ] **Auditoria Completa (Audit Trail):** + - Quem acessou o currículo de quem? (Já iniciado em `activity_logs`). + - Registro imutável de alterações salariais ou contratuais. +- [ ] **Pre-signed URLs:** Curriculos no S3/R2 com links temporários (TTL 15min) para evitar scraping. +- [ ] **Anti-Fraud:** Rate-limiting agressivo em endpoints de login e cadastro. Detecção de emails temporários. --- -> *"Go Horse is not just a methodology, it's a lifestyle."* 🐴 +## 📊 Gap Analysis Técnico (O que precisamos resolver JÁ) + +| Área | Gap | Solução Técnica Proposta | Complexidade | +|------|-----|--------------------------|--------------| +| **Busca** | Postgres `Semântico` | Implementar `pgvector` ou ElasticSearch. A busca atual não escala. | Alta | +| **Email** | SMTP Síncrono | Migrar para Fila (Redis/RabbitMQ) + Worker assíncrono para envio de emails em massa. | Média | +| **Cache** | Inexistente | Implementar Redis para cache de `GET /jobs` e Sessões de Usuário. | Média | +| **Img** | Upload Direto | Implementar Image Processing (Sharp/Go) para resize/compression antes do S3. | Baixa | +| **Logs** | Arquivo Local | Centralizar logs (Loki/Elastic) para visualização no Grafana. | Alta | + +--- + +## 📅 Cronograma Estimado (Dev) + +- **Semana 1-2:** Fixar Testes Backend, Estabilizar Deploy, Finalizar C4 Model. +- **Semana 3-4:** Implementar Stripe Checkout (Pagamento Básico). +- **Semana 5-6:** Módulo de Logística (Básico - Frete Correios). +- **Semana 7-8:** Início do Módulo AI (Matching Vetorial). + +> *"O futuro pertence a quem deploya na sexta-feira."* 🚀