# 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": "", "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 :/tmp/fix.sql docker exec 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 |