- Atualiza hash hardcoded em 010_seed_super_admin.sql para hash válido gerado com pepper=gohorse-pepper (o antigo hash estava inválido e causava AUTH_INVALID_CREDENTIALS em qualquer reset do banco) - Corrige valor de PASSWORD_PEPPER e CORS_ORIGINS no DEVOPS.md para refletir os valores reais do Coolify DEV - Adiciona seção de troubleshooting no DEVOPS.md com diagnóstico e fix passo-a-passo para mismatch de pepper - Adiciona seção "Known Gotchas" no AGENTS.md documentando: * Regra do PASSWORD_PEPPER (deve ser gohorse-pepper em todos ambientes) * Campo de login é email no DTO, não identifier * Hashes bcrypt em SQL devem usar arquivo -f, nunca -c ($ é expandido) * Credenciais de teste do ambiente DEV Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
371 lines
13 KiB
Markdown
371 lines
13 KiB
Markdown
# AGENTS.md - GoHorse Jobs
|
|
|
|
> **Last Updated:** 2026-02-18
|
|
> **Purpose:** Context for AI coding assistants (Claude, Cursor, etc.)
|
|
|
|
---
|
|
|
|
## Project Overview
|
|
|
|
GoHorse Jobs is a B2B SaaS recruitment platform connecting companies with candidates. It is structured as a monorepo with multiple services sharing a single PostgreSQL database.
|
|
|
|
**Business model**: Freemium (Free / Pro R$199/month / Enterprise custom pricing).
|
|
|
|
---
|
|
|
|
## Repository Structure
|
|
|
|
```
|
|
gohorsejobs/
|
|
├── backend/ # Go 1.24 REST API (Clean Architecture + DDD)
|
|
├── frontend/ # Next.js 15 web application (App Router)
|
|
├── backoffice/ # NestJS 11 admin/worker API (Fastify adapter)
|
|
├── seeder-api/ # Node.js Express database seeder
|
|
├── job-scraper-multisite/# Job scraping service
|
|
├── k8s/ # Kubernetes manifests (dev, hml, prd)
|
|
├── docs/ # Central documentation
|
|
├── .forgejo/ # Forgejo CI/CD workflows
|
|
├── .drone.yml # Drone CI/CD pipelines
|
|
└── start.sh # Interactive dev startup script
|
|
```
|
|
|
|
---
|
|
|
|
## Tech Stack
|
|
|
|
| Service | Language | Framework | Key Libraries |
|
|
|---------|----------|-----------|---------------|
|
|
| Backend | Go 1.24 | stdlib net/http | JWT v5, lib/pq, GORM, Stripe, AWS SDK v2, RabbitMQ, Firebase Admin, Swaggo |
|
|
| Frontend | TypeScript 5 | Next.js 15 (App Router) | React 19, Tailwind CSS 4, shadcn/ui, Zustand, React Hook Form + Zod, Framer Motion |
|
|
| Backoffice | TypeScript 5 | NestJS 11 (Fastify) | TypeORM, Passport + JWT, Stripe, AMQP, Nodemailer, Pino, Firebase Admin |
|
|
| Seeder | JavaScript (ESM) | Express 5 | pg, bcrypt |
|
|
|
|
**Database**: PostgreSQL 16+ with UUID v7 primary keys. 43+ SQL migration files in `backend/migrations/`.
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
./start.sh # Interactive menu
|
|
```
|
|
|
|
| Option | Action |
|
|
|--------|--------|
|
|
| 1 | Start Frontend + Backend |
|
|
| 2 | Reset DB + Seed + Start |
|
|
| 3 | Start all services (Frontend + Backend + Backoffice) |
|
|
| 4 | Run migrations only |
|
|
| 5 | Seed database (append) |
|
|
| 6 | Full DB reset + migrate + seed |
|
|
| 7 | Run backend E2E tests |
|
|
| 8 | Seed reset LITE (skip 153k cities) |
|
|
| 9 | Run all tests (Backend + Frontend) |
|
|
|
|
### Service Ports
|
|
|
|
| Service | Port |
|
|
|---------|------|
|
|
| Backend | 8521 |
|
|
| Frontend | 8963 |
|
|
| Backoffice | 3001 |
|
|
| Swagger (Backend) | 8521/swagger/index.html |
|
|
| Swagger (Backoffice) | 3001/api/docs |
|
|
|
|
---
|
|
|
|
## Build & Test Commands
|
|
|
|
### Backend (Go)
|
|
|
|
```bash
|
|
cd backend && go run cmd/api/main.go # Run
|
|
go test -v ./... -count=1 # All unit tests
|
|
go test -tags=e2e -v ./tests/e2e/... # E2E tests
|
|
swag init -g cmd/api/main.go --parseDependency --parseInternal # Swagger
|
|
go mod tidy # Dependencies
|
|
```
|
|
|
|
### Frontend (Next.js)
|
|
|
|
```bash
|
|
cd frontend
|
|
npm install # Install deps
|
|
npm run dev # Dev server (use -p 8963 for project convention)
|
|
npm run build # Production build
|
|
npm run lint # ESLint
|
|
npm run test # Jest unit tests
|
|
```
|
|
|
|
### Backoffice (NestJS)
|
|
|
|
```bash
|
|
cd backoffice
|
|
pnpm install # Uses pnpm
|
|
npm run start:dev # Dev server with watch
|
|
npm run build # Production build
|
|
npm run lint # ESLint with auto-fix
|
|
npm run test # Jest unit tests
|
|
npm run test:e2e # E2E tests
|
|
```
|
|
|
|
### Seeder
|
|
|
|
```bash
|
|
cd seeder-api
|
|
npm install
|
|
npm run migrate # Run migrations
|
|
npm run seed # Seed data
|
|
npm run seed:reset # Drop all tables
|
|
npm run seed:lite # Seed without 153k cities
|
|
```
|
|
|
|
---
|
|
|
|
## Architecture & Conventions
|
|
|
|
### Backend (Go) - Clean Architecture + DDD
|
|
|
|
```
|
|
backend/internal/
|
|
├── api/ # (legacy) HTTP handlers
|
|
├── handlers/ # HTTP request handlers (current)
|
|
├── middleware/ # Auth, CORS, rate limiting, security headers
|
|
├── core/
|
|
│ ├── domain/entity/ # Business entities (User, Company, Job, etc.)
|
|
│ ├── ports/ # Repository interfaces
|
|
│ └── usecases/ # Business logic (LoginUseCase, RegisterUseCase, etc.)
|
|
├── infrastructure/
|
|
│ ├── auth/ # JWT service
|
|
│ ├── persistence/ # PostgreSQL repository implementations
|
|
│ └── storage/ # S3/R2 storage adapter
|
|
├── services/ # Business services (Email, FCM, Storage, Admin)
|
|
├── dto/ # Data Transfer Objects
|
|
├── router/ # Route definitions
|
|
├── models/ # GORM models (legacy, being migrated)
|
|
├── database/ # DB connection & migration runner
|
|
└── utils/ # Utilities (JWT, sanitizer)
|
|
```
|
|
|
|
**Patterns**:
|
|
- Constructor injection: `func NewService(db *sql.DB) *Service`
|
|
- All DB operations accept `ctx context.Context`
|
|
- Error handling: `(T, error)` return tuples
|
|
- Repository interfaces in `core/ports/`, implementations in `infrastructure/persistence/`
|
|
- Test files: `*_test.go`
|
|
|
|
### Frontend (Next.js) - App Router
|
|
|
|
```
|
|
frontend/src/
|
|
├── app/ # File-based routing (20+ routes)
|
|
│ ├── dashboard/ # Protected routes (12+ sub-pages)
|
|
│ ├── jobs/ # Job listing & details
|
|
│ └── auth/ # Login, register flows
|
|
├── components/ # Reusable components (44+)
|
|
│ └── ui/ # shadcn/ui primitives (24+)
|
|
├── hooks/ # Custom React hooks
|
|
├── contexts/ # React contexts (auth, theme)
|
|
├── lib/ # Utilities (API calls, validation)
|
|
└── i18n/ # Internationalization (PT, EN, ES, JA)
|
|
```
|
|
|
|
**Patterns**:
|
|
- Server Components by default; use `'use client'` for interactivity
|
|
- Tailwind CSS utility classes
|
|
- Path alias: `@/*` maps to `./src/*`
|
|
- Form validation: React Hook Form + Zod schemas
|
|
- Global state: Zustand stores
|
|
- Test files: `*.test.tsx`
|
|
|
|
### Backoffice (NestJS) - Modular
|
|
|
|
```
|
|
backoffice/src/
|
|
├── admin/ # Dashboard & statistics
|
|
├── auth/ # JWT authentication (Passport)
|
|
├── email/ # Email worker (AMQP/LavinMQ consumer)
|
|
├── external-services/ # Credential management
|
|
├── fcm-tokens/ # Firebase push tokens
|
|
├── plans/ # Subscription plans
|
|
├── stripe/ # Stripe payment integration
|
|
└── tickets/ # Support tickets
|
|
```
|
|
|
|
**Patterns**:
|
|
- NestJS module pattern: `*.module.ts`, `*.controller.ts`, `*.service.ts`
|
|
- Guards: `@UseGuards(JwtAuthGuard)`
|
|
- DTOs: `create-*.dto.ts`, `update-*.dto.ts` with class-validator
|
|
- Prettier: single quotes, trailing commas
|
|
|
|
---
|
|
|
|
## Authentication & Authorization
|
|
|
|
- **JWT**: HS256 with HttpOnly cookies (web) + Bearer tokens (API/mobile)
|
|
- **4 roles**: `superadmin` > `admin` > `recruiter` > `candidate`
|
|
- **Middleware stack**: Auth (JWT+RBAC) -> CORS -> Rate Limiting (100 req/min) -> Security Headers -> XSS Sanitizer
|
|
- **JWT secret must match** between Backend and Backoffice
|
|
- **Test credentials**: See [TEST_USERS.md](TEST_USERS.md) for all test accounts
|
|
|
|
---
|
|
|
|
## Database
|
|
|
|
- PostgreSQL 16+ with UUID v7 for primary keys (SERIAL for reference tables)
|
|
- Migrations: `backend/migrations/` (43+ SQL files, numbered `000_` through `999_`)
|
|
- Core tables: `users`, `companies`, `user_companies`, `jobs`, `applications`, `favorite_jobs`, `notifications`, `tickets`, `activity_logs`, `job_payments`
|
|
|
|
---
|
|
|
|
## API Routes
|
|
|
|
All backend routes under `/api/v1`:
|
|
- **Auth**: `/auth/login`, `/auth/register/candidate`, `/auth/register/company`, `/auth/forgot-password`, `/auth/reset-password`
|
|
- **Jobs**: CRUD at `/jobs`, moderation at `/jobs/moderation`
|
|
- **Companies**: CRUD at `/companies`, status management
|
|
- **Users**: `/users/me` (profile), admin CRUD at `/users`
|
|
- **Applications**: `/applications` with status updates
|
|
- **Storage**: `/storage/upload-url` (presigned S3/R2 URLs)
|
|
- **Admin**: `/admin/companies`, `/admin/email-templates`, `/admin/email-settings`
|
|
- **Notifications**: `/notifications`, `/tokens` (FCM)
|
|
- **Chat**: `/conversations`, `/conversations/{id}/messages`
|
|
|
|
---
|
|
|
|
## External Services
|
|
|
|
| Service | Purpose |
|
|
|---------|---------|
|
|
| Stripe | Payment processing & subscriptions |
|
|
| Firebase (FCM) | Push notifications |
|
|
| Appwrite | Real-time chat/messaging |
|
|
| LavinMQ (AMQP) | Message queue for background jobs |
|
|
| Cloudflare R2 / S3 | File/image storage |
|
|
| Resend | Transactional email |
|
|
|
|
---
|
|
|
|
## Deployment
|
|
|
|
- **Environments**: `dev` (branch: dev), `hml` (branch: hml), `prd` (branch: main)
|
|
- **CI/CD**: Forgejo workflows (`.forgejo/workflows/`) + Drone (`.drone.yml`)
|
|
- **Container runtime**: Podman (Apolo), Coolify/Docker (Redbull), Kubernetes (production)
|
|
- **Registry**: Forgejo (`forgejo-gru.rede5.com.br/rede5/`)
|
|
- **Coolify UI**: https://redbull.rede5.com.br (Redbull VPS DEV environment)
|
|
|
|
### DEV Environments
|
|
|
|
| Server | Type | URLs |
|
|
|--------|------|------|
|
|
| **Redbull** (Coolify) | Auto-deploy via Git | `local.gohorsejobs.com`, `api-local.gohorsejobs.com` |
|
|
| **Apolo** (Podman/Quadlet) | Manual deploy | `dev.gohorsejobs.com`, `api-tmp.gohorsejobs.com` |
|
|
|
|
---
|
|
|
|
## Git Workflow
|
|
|
|
### Remotes
|
|
|
|
| Remote | URL | Function |
|
|
|--------|-----|----------|
|
|
| **origin** | git@github.com:rede5/gohorsejobs.git | GitHub - main development |
|
|
| **pipe** | https://pipe.gohorsejobs.com/bohessefm/gohorsejobs.git | Forgejo - mirror/CI |
|
|
|
|
### Branches
|
|
|
|
| Branch | Environment | Description |
|
|
|--------|-------------|-------------|
|
|
| **dev** | Development | Main working branch |
|
|
| **hml** | Staging | Pre-production testing |
|
|
| **main** | Production | Stable release |
|
|
|
|
### Sync Flow
|
|
|
|
```bash
|
|
# 1. Pull from GitHub
|
|
git pull origin dev
|
|
|
|
# 2. Push to Forgejo (pipe)
|
|
git push pipe dev
|
|
```
|
|
|
|
---
|
|
|
|
## Key Things to Know
|
|
|
|
1. Backend uses Clean Architecture + DDD; respect layer boundaries (handlers -> usecases -> ports/repositories)
|
|
2. Frontend uses Next.js App Router; pages in `src/app/`, components in `src/components/`
|
|
3. Backoffice shares the same PostgreSQL database as the backend
|
|
4. Migrations are plain SQL files, not managed by an ORM
|
|
5. Project supports 4 languages (PT, EN, ES, JA) via i18n
|
|
6. Environment variables in `.env` files (gitignored)
|
|
7. Use `start.sh` for local development
|
|
|
|
---
|
|
|
|
## ⚠️ Known Gotchas
|
|
|
|
### 1. PASSWORD_PEPPER must be `gohorse-pepper` everywhere
|
|
|
|
All migration seeds (`010_seed_super_admin.sql`) and the seeder-api use `gohorse-pepper` as the bcrypt pepper.
|
|
The Coolify/production env var `PASSWORD_PEPPER` **must match** or every login returns `AUTH_INVALID_CREDENTIALS`.
|
|
|
|
| Location | Value |
|
|
|----------|-------|
|
|
| `backend/.env` (local) | `gohorse-pepper` |
|
|
| `seeder-api/.env` | `gohorse-pepper` |
|
|
| Coolify DEV (`iw4sow8s0kkg4cccsk08gsoo`) | `gohorse-pepper` |
|
|
| Migration `010_seed_super_admin.sql` hash | computed with `gohorse-pepper` |
|
|
|
|
If you suspect a mismatch, see the full fix procedure in [DEVOPS.md](DEVOPS.md#troubleshooting-login-retorna-invalid-credentials).
|
|
|
|
### 2. Login API field: `email`, not `identifier`
|
|
|
|
The frontend login form sends `{ "email": "<username_or_email>", "password": "..." }`.
|
|
The backend core DTO (`internal/core/dto/user_auth.go`) has field `Email`, **not** `Identifier`.
|
|
The repository resolves it via `WHERE email = $1 OR identifier = $1`, so both username and email work.
|
|
|
|
Do **not** send `{ "identifier": "..." }` directly to `/api/v1/auth/login` — the field will be ignored and login will fail silently.
|
|
|
|
### 3. Bcrypt hashes in SQL — always use a file, never `-c`
|
|
|
|
Shell interprets `$` in bcrypt hashes as variable expansions. Example of **broken** approach:
|
|
```bash
|
|
# ❌ WRONG — $2b gets expanded by shell, hash gets corrupted
|
|
docker exec postgres psql -U user -d db -c "UPDATE users SET password_hash='$2b$10$abc...'"
|
|
```
|
|
Correct approach — write to file first, then use `-f`:
|
|
```bash
|
|
cat > /tmp/fix.sql <<'EOF'
|
|
UPDATE users SET password_hash = '$2b$10$4759wJhnXnBpcwSnVZm9Eu.wTqGYVCHkxAU5a2NxhsFHU42nV3tzW' WHERE identifier = 'lol';
|
|
EOF
|
|
docker cp /tmp/fix.sql <postgres_container>:/tmp/fix.sql
|
|
docker exec <postgres_container> psql -U gohorsejobs -d gohorsejobs -f /tmp/fix.sql
|
|
```
|
|
|
|
### 4. Test credentials (DEV/local.gohorsejobs.com)
|
|
|
|
| Role | Identifier | Password | Email |
|
|
|------|-----------|----------|-------|
|
|
| superadmin | `lol` | `Admin@2025!` | lol@gohorsejobs.com |
|
|
| superadmin | `superadmin` | `Admin@2025!` | admin@gohorsejobs.com |
|
|
|
|
---
|
|
|
|
## Documentation Index
|
|
|
|
| Document | Location | Description |
|
|
|----------|----------|-------------|
|
|
| API Reference | [API.md](API.md) | Endpoints, contracts, examples |
|
|
| API Security | [API_SECURITY.md](API_SECURITY.md) | Auth, RBAC, permissions |
|
|
| Database Schema | [DATABASE.md](DATABASE.md) | Tables, ERD, migrations |
|
|
| DevOps | [DEVOPS.md](DEVOPS.md) | Infrastructure, deployment, diagrams |
|
|
| Test Users | [TEST_USERS.md](TEST_USERS.md) | Credenciais de teste por role |
|
|
| Roadmap | [ROADMAP.md](ROADMAP.md) | Product direction |
|
|
| Tasks | [TASKS.md](TASKS.md) | Task tracking |
|
|
| Workflows | [WORKFLOWS.md](WORKFLOWS.md) | Deployment workflows |
|
|
| Backend | [../backend/BACKEND.md](../backend/BACKEND.md) | Go API details |
|
|
| Frontend | [../frontend/FRONTEND.md](../frontend/FRONTEND.md) | Next.js details |
|
|
| Backoffice | [../backoffice/BACKOFFICE.md](../backoffice/BACKOFFICE.md) | NestJS details |
|
|
| Seeder | [../seeder-api/SEEDER-API.md](../seeder-api/SEEDER-API.md) | Database seeding & test data |
|