- Remove duplicate setLoading calls in loadBackoffice
- Add proper error handling with catch for all API calls
- Wrap useEffect initialization in try/catch/finally
- Move backoffice functionality into settings page as new tab
- Remove standalone backoffice page and sidebar link
- Add edit/delete buttons for credentials management
- Update credentials service to allow overwriting existing credentials
- Add API documentation for system credentials endpoints
jobs/page.tsx:
- Edit dialog now exposes all UpdateJobRequest fields: employmentType,
workMode, salaryMin/max/type/currency, salaryNegotiable, languageLevel,
visaSupport, location, status, isFeatured, description
- Fix AdminJob type to include all JobWithCompany fields returned by API
- Fix jobRows mapping that was hardcoding location/type/workMode/isFeatured
- Add isFeatured to CreateJobPayload type
applications/page.tsx:
- Fix status mismatch: reviewing→reviewed, interview→shortlisted, accepted→hired
- Align statusConfig labels/keys with backend constraint (pending/reviewed/
shortlisted/rejected/hired)
- Update stats counters to use corrected status keys
companies/page.tsx:
- Add logoUrl and yearsInMarket to create and edit forms
- Populate editFormData from company object on edit open
- Send logoUrl/yearsInMarket in update payload
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The countQuery was missing LEFT JOIN companies c, causing a PostgreSQL
error when the search filter referenced c.name ILIKE. This made every
keyword search return a 500 error instead of results.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add workMode, languageLevel, visaSupport, salaryNegotiable to form
- Add all 10 currency options and all 8 employment types (including dispatch/voluntary)
- Add status selector (draft/review/open/paused/closed)
- Add location autocomplete with country dropdown and city/region search
- Add application channel (email/url/phone) with conditional inputs
- Add resumeRequirement selector and requirements map in payload
- Load companies via adminCompaniesApi (no registration — user is already logged in)
- Extend CreateJobPayload type with workMode, cityId, regionId, languageLevel,
visaSupport, requirements, expanded currency and status options
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both routes are fully replaced by /jobs/new. Deleted directories entirely
instead of keeping redirects.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Consolidates the two public job posting routes into the single canonical
flow at /jobs/new. The /publicar-vaga route already redirected there.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Frontend (jobs/new):
- Replace isValidCNPJ (checksum algorithm) with isValidDocument: accepts
any tax document with 5–30 alphanumeric chars (CNPJ, EIN, VAT, etc.)
- Add cleanPhone(): strips formatting chars (dashes, spaces, parens) and
keeps only digits + optional leading '+'; replaces cleanDigits+prepend
- Phone sent as '+5511999998888' if user typed '+55...', or '11999998888'
if no country code was provided — no '+' blindly prepended anymore
- Company document sent stripped of all non-alphanumeric before API call
- Update label placeholder from '00.000.000/0000-00' to 'CNPJ, EIN, VAT...'
- Rename error key invalidCnpj → invalidDocument in all 3 locales (pt, en, es)
Backend (create_company use case):
- Add SanitizePhone() to utils/sanitizer.go: strips all non-digit chars
except a leading '+'; '(11) 99999-8888' → '11999998888'
- Apply SanitizePhone to input.Phone before persisting to DB
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace free-text location input with debounced autocomplete
- On country select, fetch its numeric ID from /api/v1/locations/countries
and use it to scope the search results to that country
- Typing ≥2 chars in location field triggers GET /api/v1/locations/search
with 350ms debounce; results show city (blue) and state (green) badges
- On result selection, stores cityId + regionId and sets the display label
to "Name, Region" format; IDs are included in the job creation payload
- Spinner shown while searching; dropdown closes on outside click / select
- CEP search button preserved alongside the autocomplete
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add password + confirm-password fields to billing step (Step 3) so the
recruiter creates their account credentials during the job posting flow
- Validate password length (≥8) and confirmation match before proceeding
- Extract company `id` from POST /auth/register/company response and send
it as `companyId` in the job creation payload (was missing — caused 400)
- Pass `contact` (full name) to company registration endpoint
- Remove hardcoded "Temp@123456" password; use the user-provided one
- Remove hardcoded "+55" phone prefix; send raw digits with "+" prefix
- Add translations (pt-BR, en, es) for password fields and error messages
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add validateCreateJobRequest() checking required fields (companyId,
title ≥5 chars, description ≥20 chars) and enum values
(employmentType, workMode, status) before hitting the DB
- Catch *pq.Error in handler: check_violation (23514) and
foreign_key_violation (23503) now return 400; unique_violation (23505)
returns 409; other DB errors return 500 without leaking raw pq messages
- Fix test fixtures: description and companyId now meet validation
requirements
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Antes: 010_seed_super_admin.sql tinha hash bcrypt fixo amarrado a um pepper
específico. Qualquer mudança no PASSWORD_PEPPER quebrava todos os logins
silenciosamente após reset do banco.
Agora:
- migration 010: insere superadmin com placeholder inválido + force_change_password.
ON CONFLICT DO NOTHING preserva o hash se o seeder já rodou.
- seeder users.js: faz upsert de 'lol' com bcrypt(senha + env.PASSWORD_PEPPER)
em runtime. Mudar o pepper e re-rodar o seeder é suficiente para atualizar
as credenciais sem tocar em nenhuma migration.
- docs/AGENTS.md: atualiza gotcha #1 explicando o novo fluxo migrate → seed
- docs/DEVOPS.md: fix opção 1 do troubleshooting inclui re-deploy do seeder
Fluxo correto após reset do banco (coberto pelo start.sh opções 2, 6, 8):
npm run migrate → superadmin criado, hash = placeholder
npm run seed → hash recalculado com PEPPER do ambiente, status = active
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
- Fix nullable location in my-jobs search filter (job.location ?? '')
- Fix Locale type assertion in jobs/new description language select
- Fix nullable location in api.ts transformApiJobToFrontend
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add full infrastructure Mermaid diagrams (Redbull + Apolo + CI/CD flow)
- Create TEST_USERS.md with all seeder credentials organized by role
- Fix Coolify URL from IP to https://redbull.rede5.com.br
- Update Coolify resources with current domains and status
- Add TEST_USERS.md reference to AGENTS.md, README.md, and doc index
- Update deployment section with both DEV environments
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace all hardcoded Portuguese strings with locale-aware translations
using contentByLocale object. All 4 steps (job details, preview,
billing, payment), labels, placeholders, options, error messages,
and button texts now adapt to the user's selected language.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Initialize useState with getInitialLocale() instead of hardcoded 'en',
so the correct locale is used from the very first render
- Default to 'pt-BR' instead of 'en' for SSR and fallback
- Add fallback chain in t(): tries current locale -> pt-BR -> en
- Extract resolveKey() helper for cleaner key resolution
- Cast dictionaries as Record<string, unknown> to avoid type issues
- Wrap localStorage access in try-catch for blocked storage scenarios
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove `export const runtime = "edge"` which could interfere with i18n
JSON imports causing translation keys to render as literal text. Also
add fallback text when job description is empty.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Removed leftover <<<<<<< Updated upstream conflict markers that were breaking TypeScript compilation,
preventing the job detail page (/jobs/[id]) from loading real data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>