docs: update roadmap and add admin handler tests
This commit is contained in:
parent
c61022a277
commit
69534f5810
2 changed files with 205 additions and 61 deletions
|
|
@ -1,13 +1,40 @@
|
||||||
package handlers_test
|
package handlers_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/DATA-DOG/go-sqlmock"
|
||||||
"github.com/rede5/gohorsejobs/backend/internal/api/handlers"
|
"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) {
|
func TestNewAdminHandlers(t *testing.T) {
|
||||||
h := handlers.NewAdminHandlers(nil, nil, nil, nil)
|
h := handlers.NewAdminHandlers(nil, nil, nil, nil)
|
||||||
if h == nil {
|
if h == nil {
|
||||||
|
|
@ -15,19 +42,69 @@ func TestNewAdminHandlers(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestListAccessRoles(t *testing.T) {
|
func TestAdminHandlers_ListCompanies(t *testing.T) {
|
||||||
h := handlers.NewAdminHandlers(nil, nil, nil, nil)
|
db, mock, err := sqlmock.New()
|
||||||
|
if err != nil {
|
||||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/admin/roles", nil)
|
t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
|
||||||
rr := httptest.NewRecorder()
|
|
||||||
|
|
||||||
h.ListAccessRoles(rr, req)
|
|
||||||
|
|
||||||
if rr.Code != http.StatusOK {
|
|
||||||
t.Errorf("Expected status 200, got %d", rr.Code)
|
|
||||||
}
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
if rr.Header().Get("Content-Type") != "application/json" {
|
handlers := createTestAdminHandlers(t, db)
|
||||||
t.Errorf("Expected Content-Type application/json, got %s", rr.Header().Get("Content-Type"))
|
|
||||||
|
// 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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
165
docs/ROADMAP.md
165
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)
|
## 🏗️ Pilar 1: Fundação & Arquitetura (Já Consolidado)
|
||||||
*O "Merge Hell" e a base sólida.*
|
*O alicerce que permite escalar sem quebrar.*
|
||||||
|
|
||||||
- [x] **Arquitetura Limpa:** Migração completa do Backend para Clean Architecture + DDD.
|
### 1.1 Backend & Core (Go)
|
||||||
- [x] **DevOps & CI/CD:** Pipeline Forgejo Actions com Podman/Docker para deploy automático em Dev.
|
- [x] **Clean Arch + DDD:** Separação estrita entre Handlers, Services, UseCases e Repositories.
|
||||||
- [x] **Conflitos Resolvidos:** Unificação dos branches `hml`, `dev` e `main` (Frontend, Backend, Backoffice).
|
- [x] **UUID v7:** Migração completa de INT para UUIDv7 (time-sorted) em todas as tabelas críticas (`users`, `jobs`, `applications`).
|
||||||
- [x] **Infraestrutura Core:**
|
- *Por que?* Evita fragmentação de índices e permite sharding futuro sem conflitos.
|
||||||
- [x] Auth Híbrida (JWT + Cookies + Sessions).
|
- [x] **Testes de Integração:** Setup de `sqlmock` e `testify` para cobertura crítica de Handlers e Services.
|
||||||
- [x] Migrations V7 (UUIDs).
|
- [x] **Logs Estruturados:** `slog` com rastreamento de RequestID para observabilidade total.
|
||||||
- [x] Logs & Auditoria.
|
|
||||||
|
### 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)
|
## 💎 Pilar 2: Marketplace B2C & Monetização (Q1 2025)
|
||||||
*Transformando tráfego em receita.*
|
*Transformando usuários gratuitos em receita recorrente.*
|
||||||
|
|
||||||
### 2.1 Pagamentos & Assinaturas (Stripe)
|
### 2.1 Engine de Pagamentos (Stripe Integration)
|
||||||
- [ ] **Stripe Checkout:** Venda de "Destaques de Vagas" e "Planos Premium" para empresas.
|
**Objetivo:** Permitir fluxo financeiro fluido para B2B e B2C.
|
||||||
- [ ] **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.2 Marketplace de Serviços (Gigs)
|
- [ ] **Checkout de Vagas (B2B):**
|
||||||
- [ ] **Módulo de Gigs:** Candidatos podem oferecer serviços (ex: "Revisão de CV em Japonês", "Consultoria de Visto").
|
- Empresas pagam para destacar vagas ("Featured") ou furar a fila de moderação.
|
||||||
- [ ] **Escrow de Pagamento:** O dinheiro só é liberado após a conclusão do serviço.
|
- **Regra de Negócio:** Vaga paga entra como `status: published` automaticamente (após check de fraude). Vaga grátis entra como `review`.
|
||||||
- [ ] **Chat de Negociação:** Extensão do chat atual para incluir propostas e aceite de valores.
|
- **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
|
### 2.2 Gamificação & Engajamento
|
||||||
- [ ] **Reviews Bilaterais:** Empresas avaliam candidatos (soft skills) e candidatos avaliam empresas (ambiente).
|
**Objetivo:** Viciar o usuário na plataforma (Retenção).
|
||||||
- [ ] **Trust Score:** Algoritmo que calcula a confiabilidade baseada em histórico de pagamentos, tempo de resposta e reviews.
|
|
||||||
|
- [ ] **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)
|
## 📦 Pilar 3: E-commerce & Logística (Q2 2025)
|
||||||
*Expansão para venda de equipamentos e merch.*
|
*Expansão física: Venda de Merch e Equipamentos para Home Office.*
|
||||||
|
|
||||||
- [ ] **Carrinho de Compras:** Implementação no Frontend (Zustand/Redux).
|
### 3.1 Loja Oficial (Merch)
|
||||||
- [ ] **Cálculo de Frete:** Integração com Correios/Yamato Transport API.
|
- [ ] **Catálogo de Produtos:** Camisetas, Canecas, Adesivos "GoHorse".
|
||||||
- [ ] **Gestão de Pedidos:** Módulo de Orders no Backoffice.
|
- [ ] **Integração de Estoque:** Controle simples de estoque (`product_variants`, `inventory_logs`).
|
||||||
- [ ] **Loja Oficial:** Venda de kits de onboarding, livros e equipamentos.
|
- [ ] **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)
|
## 🧠 Pilar 4: Inteligência & Automação (Q3 2025 - "GoHorse AI")
|
||||||
*O diferencial tecnológico "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.
|
### 4.1 Matching Semântico (Vector Search)
|
||||||
- [ ] **Cover Letter Generator:** AI que escreve cartas de apresentação baseadas no perfil do usuário.
|
- [ ] **Embeddings:** Gerar vetores (OpenAI ou Local LLM) para:
|
||||||
- [ ] **Triagem Automática:** Bot que pré-entrevista candidatos no chat e classifica por fit cultural.
|
- Descrições de Vagas.
|
||||||
- [ ] **Video Interview Analysis:** Transcrição e análise de sentimento de vídeos de apresentação.
|
- 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)
|
## 📱 Pilar 5: Mobile First & Notificações (Ongoing)
|
||||||
- [ ] **PWA Offline:** Cache agressivo para funcionar no metrô (Service Workers).
|
*Estar onde o usuário está: No celular.*
|
||||||
- [ ] **React Native App:** App nativo para iOS/Android focado em notificações push e chat.
|
|
||||||
|
- [ ] **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)
|
## 🛡️ Pilar 6: Segurança & Compliance (LGPD)
|
||||||
*Itens críticos para atingir o nível "Marketplace".*
|
*Protegendo o ativo mais valioso: Dados.*
|
||||||
|
|
||||||
| Área | Gap Identificado | Ação Imediata |
|
- [ ] **Anonimização de Dados:** Opção para candidato "esconder" nome/contato até o match.
|
||||||
|------|------------------|---------------|
|
- [ ] **Auditoria Completa (Audit Trail):**
|
||||||
| **Busca** | Postgres `LIKE` é lento para escala. | Migrar para **Meilisearch** ou **Elasticsearch**. |
|
- Quem acessou o currículo de quem? (Já iniciado em `activity_logs`).
|
||||||
| **SEO** | Páginas de vagas mal indexadas. | Implementar **SSR** e **Schema.org** estruturado no Next.js. |
|
- Registro imutável de alterações salariais ou contratuais.
|
||||||
| **Monetização** | Nenhuma forma de cobrar usuários. | Integrar **Stripe** no Backend (prioridade zero). |
|
- [ ] **Pre-signed URLs:** Curriculos no S3/R2 com links temporários (TTL 15min) para evitar scraping.
|
||||||
| **Segurança** | Uploads públicos vulneráveis. | Forçar Pre-signed URLs privadas com TTL curto. |
|
- [ ] **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."* 🚀
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue