270 lines
10 KiB
Markdown
Executable file
270 lines
10 KiB
Markdown
Executable file
# Backend - GoHorse Jobs API
|
|
|
|
[](https://golang.org/)
|
|
[](https://postgresql.org/)
|
|
|
|
> **Last Updated:** 2024-12-29
|
|
|
|
API REST desenvolvida em Go seguindo princípios de **Clean Architecture** e **DDD**.
|
|
|
|
---
|
|
|
|
## 🏗️ Arquitetura
|
|
|
|
```
|
|
backend/
|
|
├── cmd/
|
|
│ ├── api/ # Entrypoint principal
|
|
│ └── manual_migrate/ # Migration runner
|
|
│
|
|
├── internal/
|
|
│ ├── api/ # Clean Architecture Layer
|
|
│ │ ├── handlers/ # HTTP Handlers (Admin, Auth, Settings, Storage, Tickets)
|
|
│ │ └── middleware/ # Auth, CORS, Rate Limiting, Sanitize
|
|
│ │
|
|
│ ├── core/ # Domain Layer (DDD)
|
|
│ │ ├── domain/entity/ # Entidades (User, Company, Email)
|
|
│ │ ├── ports/ # Interfaces (Repositories)
|
|
│ │ └── usecases/ # Casos de uso (Auth, Register)
|
|
│ │
|
|
│ ├── infrastructure/ # Infrastructure Layer
|
|
│ │ ├── auth/ # JWT Service implementation
|
|
│ │ └── persistence/ # Repository implementations (Postgres)
|
|
│ │
|
|
│ ├── services/ # Business logic services (Email, Notification, Tickets)
|
|
│ │
|
|
│ ├── dto/ # Data Transfer Objects
|
|
│ ├── models/ # GORM models (Legacy/Transition)
|
|
│ ├── router/ # Route configuration
|
|
│ └── utils/ # Helpers (JWT, Sanitizer)
|
|
│
|
|
├── migrations/ # SQL Migrations (30+)
|
|
├── tests/ # E2E and Integration tests
|
|
└── docs/ # Swagger documentation
|
|
```
|
|
|
|
### 📊 Diagrama de Fluxo (C4 Simplificado)
|
|
|
|
```mermaid
|
|
graph TD
|
|
Client[📱 Clients Frontend/App] -->|JSON/HTTP| Router[🚦 Router Mux]
|
|
|
|
subgraph CoreBackend [Core Backend]
|
|
Router --> Middleware[🛡️ Middleware Auth/CORS]
|
|
Middleware --> Handlers[🎮 HTTP Handlers]
|
|
Handlers --> UseCases[🧠 Services & UseCases]
|
|
UseCases --> Repos[💾 Repositories]
|
|
UseCases --> Adapters[🔌 External Adapters]
|
|
end
|
|
|
|
Repos --> DB[(🐘 PostgreSQL)]
|
|
|
|
Adapters --> Firebase[🔥 Firebase FCM]
|
|
Adapters --> LavinMQ[📨 LavinMQ]
|
|
Adapters --> Storage[☁️ S3/R2 Storage]
|
|
Adapters --> Stripe[💳 Stripe]
|
|
```
|
|
|
|
---
|
|
|
|
## 🚀 Deployment & CI/CD (Forgejo)
|
|
|
|
O deployment é automatizado via **Forgejo Actions**.
|
|
|
|
### Workflow: `Deploy Backend (Dev)`
|
|
Arquivo: `.forgejo/workflows/deploy.yaml`
|
|
|
|
Este workflow é disparado automaticamente ao realizar um push para o branch `dev` com alterações na pasta `backend/`.
|
|
|
|
**Etapas do CI/CD:**
|
|
1. **Trigger:** Push no branch `dev` (apenas alterações em `backend/**`).
|
|
2. **Runner:** Executa no ambiente `docker` (verifique as labels do seu runner).
|
|
3. **SSH Action:** Conecta no servidor de desenvolvimento (Apolo) via SSH.
|
|
4. **Atualização de Código:**
|
|
* Navega até `/mnt/data/gohorsejobs` (ou caminho configurado).
|
|
* Faz `git fetch` e `git checkout dev`.
|
|
* `git pull origin dev`.
|
|
5. **Build & Restart (Podman):**
|
|
* Constrói a imagem: `podman build -t localhost/gohorsejobs-backend-dev ./backend`
|
|
* Reinicia o serviço: `sudo systemctl restart gohorsejobs-backend-dev`
|
|
* Limpeza: `podman image prune -f`
|
|
|
|
**Secrets Necessários (Forgejo):**
|
|
* `HOST`: IP do servidor.
|
|
* `USERNAME`: Usuário SSH.
|
|
* `SSH_KEY`: Chave privada SSH.
|
|
* `PORT`: Porta SSH (ex: 22).
|
|
|
|
---
|
|
|
|
## 🔧 Services
|
|
|
|
| Service | Arquivo | Descrição |
|
|
|---------|---------|-----------|
|
|
| **AdminService** | `admin_service.go` | CRUD de empresas, usuários, candidatos, tags, email templates |
|
|
| **JobService** | `job_service.go` | CRUD de vagas com filtros avançados |
|
|
| **ApplicationService** | `application_service.go` | Gestão de candidaturas |
|
|
| **TicketService** | `ticket_service.go` | **(Novo)** Sistema de tickets de suporte |
|
|
| **ChatService** | `chat_service.go` | Mensagens e conversas (Appwrite) |
|
|
| **NotificationService** | `notification_service.go` | Notificações push |
|
|
| **EmailService** | `email_service.go` | Produtor de emails via LavinMQ |
|
|
| **FCMService** | `fcm_service.go` | Firebase Cloud Messaging |
|
|
| **StorageService** | `storage_service.go` | Pre-signed URLs (S3/R2) |
|
|
| **CredentialsService** | `credentials_service.go` | **(Novo)** Gestão de credenciais criptografadas |
|
|
| **CloudflareService** | `cloudflare_service.go` | Cache purge via API |
|
|
| **SettingsService** | `settings_service.go` | System settings |
|
|
| **AppwriteService** | `appwrite_service.go` | Integração Appwrite Realtime |
|
|
| **AuditService** | `audit_service.go` | Logs de auditoria |
|
|
|
|
---
|
|
|
|
## 🔒 Segurança
|
|
|
|
### Middlewares Implementados
|
|
|
|
| Middleware | Arquivo | Descrição |
|
|
|------------|---------|-----------|
|
|
| **Auth** | `middleware/auth.go` | Validação JWT + RBAC |
|
|
| **CORS** | `middleware/cors.go` | Whitelist de origens via `CORS_ORIGINS` |
|
|
| **Rate Limiting** | `middleware/rate_limit.go` | 100 req/min por IP |
|
|
| **Security Headers** | `middleware/security_headers.go` | OWASP headers (XSS, CSP, etc.) |
|
|
| **Sanitize** | `middleware/sanitize.go` | XSS sanitization em JSON bodies |
|
|
|
|
### Autenticação
|
|
|
|
- **JWT** com expiração configurável
|
|
- **Password Pepper** via `PASSWORD_PEPPER` env var
|
|
- **HttpOnly Cookies** para refresh tokens
|
|
- **RSA Encryption** para credenciais sensíveis
|
|
|
|
---
|
|
|
|
## 📡 Endpoints (API Reference)
|
|
|
|
### 🔐 Auth & Core
|
|
| Método | Endpoint | Descrição | Roles |
|
|
|--------|----------|-----------|-------|
|
|
| `POST` | `/api/v1/auth/login` | Autenticação de usuário | Public |
|
|
| `POST` | `/api/v1/auth/register` | Registro de Candidato | Public |
|
|
| `POST` | `/api/v1/auth/register/company` | Registro de Empresa | Public |
|
|
| `GET` | `/api/v1/users/me` | Dados do usuário logado | Auth |
|
|
| `PATCH` | `/api/v1/users/me/profile` | Atualizar perfil | Auth |
|
|
| `GET` | `/api/v1/notifications` | Listar notificações | Auth |
|
|
| `POST` | `/api/v1/tokens` | Salvar token FCM | Auth |
|
|
|
|
### 💼 Jobs (Vagas)
|
|
| Método | Endpoint | Descrição | Roles |
|
|
|--------|----------|-----------|-------|
|
|
| `GET` | `/api/v1/jobs` | Listar vagas (filtros) | Public |
|
|
| `GET` | `/api/v1/jobs/{id}` | Detalhes da vaga | Public |
|
|
| `POST` | `/api/v1/jobs` | Criar nova vaga | Recruiter |
|
|
| `PUT` | `/api/v1/jobs/{id}` | Editar vaga | Recruiter |
|
|
| `DELETE` | `/api/v1/jobs/{id}` | Remover vaga | Recruiter |
|
|
|
|
### 📝 Applications (Candidaturas)
|
|
| Método | Endpoint | Descrição | Roles |
|
|
|--------|----------|-----------|-------|
|
|
| `POST` | `/api/v1/applications` | Candidatar-se a uma vaga | Candidate |
|
|
| `GET` | `/api/v1/applications` | Minhas candidaturas | Auth |
|
|
| `GET` | `/api/v1/applications/{id}` | Detalhes da candidatura | Auth |
|
|
| `PUT` | `/api/v1/applications/{id}/status` | Atualizar status | Recruiter |
|
|
| `DELETE` | `/api/v1/applications/{id}` | Desistir/Remover | Auth |
|
|
|
|
### 🎫 Support (Tickets)
|
|
| Método | Endpoint | Descrição | Roles |
|
|
|--------|----------|-----------|-------|
|
|
| `GET` | `/api/v1/support/tickets` | Meus tickets de suporte | Auth |
|
|
| `POST` | `/api/v1/support/tickets` | Abrir novo ticket | Auth |
|
|
| `GET` | `/api/v1/support/tickets/{id}` | Ver conversa do ticket | Auth |
|
|
| `POST` | `/api/v1/support/tickets/{id}/messages` | Enviar mensagem | Auth |
|
|
| `PATCH` | `/api/v1/support/tickets/{id}/close` | Fechar ticket | Auth |
|
|
|
|
### 💬 Chat & Locais
|
|
| Método | Endpoint | Descrição | Roles |
|
|
|--------|----------|-----------|-------|
|
|
| `GET` | `/api/v1/conversations` | Listar conversas | Auth |
|
|
| `GET` | `/api/v1/conversations/{id}/messages` | Ver mensagens | Auth |
|
|
| `POST` | `/api/v1/conversations/{id}/messages` | Enviar mensagem | Auth |
|
|
| `GET` | `/api/v1/locations/search` | Buscar cidade/estado | Public |
|
|
|
|
### 🛡️ Admin & System
|
|
| Método | Endpoint | Descrição | Roles |
|
|
|--------|----------|-----------|-------|
|
|
| `GET` | `/api/v1/users` | Listar todos usuários | Admin |
|
|
| `GET` | `/api/v1/jobs/moderation` | Moderação de vagas | Admin |
|
|
| `GET` | `/api/v1/system/credentials` | Ver credenciais (mascaradas) | Admin |
|
|
| `POST` | `/api/v1/system/credentials` | Salvar credencial | Admin |
|
|
| `POST` | `/api/v1/system/cloudflare/purge` | Limpar cache CDN | Admin |
|
|
| `GET` | `/api/v1/admin/email-templates` | Gerenciar emails | Admin |
|
|
|
|
---
|
|
|
|
## 🗄️ Migrations
|
|
|
|
O projeto usa um sistema de migrations manuais via `cmd/manual_migrate`.
|
|
|
|
### Executar Migrations
|
|
```bash
|
|
go run ./cmd/manual_migrate
|
|
```
|
|
|
|
---
|
|
|
|
## 💻 Desenvolvimento Local
|
|
|
|
### Pré-requisitos
|
|
- Go 1.22+
|
|
- Docker & Docker Compose **OU** Podman
|
|
- PostgreSQL
|
|
|
|
### Executar com Go
|
|
```bash
|
|
# Copiar .env
|
|
cp .env.example .env
|
|
|
|
# Executar migrations
|
|
go run ./cmd/manual_migrate
|
|
|
|
# Iniciar servidor
|
|
go run ./cmd/api
|
|
```
|
|
|
|
### Executar com Podman
|
|
```bash
|
|
# Build
|
|
podman build -t gohorse-backend ./backend
|
|
|
|
# Run
|
|
podman run -p 8080:8080 --env-file ./backend/.env gohorse-backend
|
|
```
|
|
|
|
### Testes
|
|
```bash
|
|
# Todos os testes
|
|
go test ./...
|
|
|
|
# Com cobertura
|
|
go test -cover ./...
|
|
```
|
|
|
|
---
|
|
|
|
## ❓ Troubleshooting (CI/CD & Runner)
|
|
|
|
### O Workflow não inicia (`Waiting for runner...`)
|
|
* **Causa:** Nenhuma maquina registrada com o label correto.
|
|
* **Solução:**
|
|
1. Verifique, no arquivo `.forgejo/workflows/deploy.yaml`, o campo `runs-on`.
|
|
2. Se estiver como `docker`, seu `act_runner` deve ter suporte a este label (ex: `labels: "docker:docker://node:16-bullseye,ubuntu-latest:docker://node:16-bullseye"` no `config.yaml`).
|
|
3. Se o runner for genérico, use `ubuntu-latest`.
|
|
|
|
### Falha de SSH (`ssh: handshake failed`)
|
|
* **Solução:**
|
|
1. Verifique se a chave pública (`id_rsa.pub`) correspondente à `SSH_KEY` do secret está no arquivo `~/.ssh/authorized_keys` da máquina de destino.
|
|
2. Confira se o IP (`HOST`) está acessível da rede onde o runner está.
|
|
|
|
### Falha de Build no Podman
|
|
* **Causa:** Falta de permissão ou serviço parado.
|
|
* **Solução:**
|
|
1. Rode `podman logs -f <conteiner>` na máquina de destino.
|
|
2. Verifique se o usuário tem permissão de usar podman (rootless ou sudo).
|