Recrutamento (Candidato, Vaga, Candidatura)
O núcleo do sistema — candidatos, vagas e o fluxo de candidatura entre eles.
Três módulos formam o pipeline de recrutamento: candidate, vacancy e application. Uma Vaga
recebe Candidaturas de Candidatos; a candidatura é quem carrega o status do processo seletivo.
Candidato (candidate)
Entidade: CandidateEntity — estende BaseEntity (soft delete).
Campos principais: name, email (único), cpf (único), phoneNumber, position, birthDate,
hasExperience, hasDriverLicense + driverLicenseType (A–E), hasChildren + childrenCount,
maritalStatus (SOLTEIRO/CASADO/DIVORCIADO/VIUVO), gender (M/F), educationLevel (FUNDAMENTAL /
ENSINO_MEDIO_INCOMPLETO / ENSINO_MEDIO_COMPLETO / SUPERIOR), status, inTalentPool, restricted,
restrictionObservation (motivo obrigatório quando restricted = true) e address (value object embutido).
Máquina de estados (status)
AVAILABLE ──enteredProcess()──▶ IN_PROCESS ──allocate()──▶ ALLOCATED
▲ │
└───────backToAvailable()───────┘
qualquer estado ──restrict()──▶ RESTRICTED ──unrestrict()──▶ AVAILABLE- Só é possível
allocate()se o candidato não estiverRESTRICTED. restrict()marcarestricted = truee muda o status paraRESTRICTED.- Ao restringir um candidato,
restrictionObservationdeve informar o motivo da restrição; ao remover a restrição, esse campo é limpo. - Candidatos restritos ainda podem ser vinculados a vagas, mas o frontend deve exibir tag/alerta e pedir confirmação antes de criar a candidatura.
unrestrict()remove a restrição e retorna o candidato paraAVAILABLE.
Endpoints (/gnoqcore/v1/candidate)
| Método | Rota | Permissão |
|---|---|---|
| POST | / | candidate:create |
| GET | /{id}, /email/{email}, /cpf/{cpf}, / (lista) | candidate:read |
| PUT | /{id} | candidate:update |
| PATCH | /{id}/restore | candidate:update |
| DELETE | /{id}/trash, /{id}/force | candidate:delete |
Vaga (vacancy)
Entidades: VacancyEntity (estende BaseEntity) + VacancyDetailsEntity (um-para-um, dados
específicos por motivo de abertura).
Campos principais: motive (ACCOUNT_EXPANSION / ABSENCE / BREAK / SUBSTITUTION / TEMPORARY),
client / clientUnit (opcionais — uma vaga pode estar ligada a um cliente direto ou a uma unidade),
state, city, openingDate, startDate, workload, position, hiringType, serviceType,
vehicleType, approvalStatus (PENDING/APPROVED/REJECTED), status
(OPEN/BEHIND_SCHEDULE/FILLED/CLOSED), salary e campos de benefício (feedingType/feedingValue,
fuelValue, rentalValue, communicationValue, hazardPay, medicalPlan, dentalPlan),
roadmapImageUrl (imagem enviada ao Supabase Storage, ver abaixo).
VacancyDetailsEntity guarda coveragePeriod (obrigatório para ABSENCE/BREAK) e
substituteCompleteName / substituteRegistration (obrigatórios para SUBSTITUTION) — validado em
validate() de acordo com o motive.
Máquina de estados (status + approvalStatus)
- Vagas com
motive = ACCOUNT_EXPANSIONnascem comapprovalStatus = PENDINGe precisam serapprove()adas oureject()adas (permissãovacancy:approval— é o fluxo da tela Aprovação de Vagas no frontend). Essa decisão é permitida enquanto a vaga estiverOPENouBEHIND_SCHEDULE. Qualquer outro motivo já nasceAPPROVED. markAsBehindSchedule():OPEN → BEHIND_SCHEDULE, disparado automaticamente ~3 dias antes dostartDate.fill():OPEN/BEHIND_SCHEDULE+APPROVED→FILLED.close():OPEN/BEHIND_SCHEDULE→CLOSED(idempotente).reopen():CLOSED → OPEN, só é permitido em até 12 dias após o fechamento — depois disso lançaVacancyReopenPeriodExpiredException.
Endpoints (/gnoqcore/v1/vacancy)
| Método | Rota | Permissão |
|---|---|---|
| POST | / | vacancy:create |
| GET | /{id}, / (lista/filtros) | vacancy:read |
| PUT | /{id} | vacancy:update |
| PATCH | /{id}/approve, /{id}/reject | vacancy:approval |
| PATCH | /{id}/roadmap-image (multipart) | vacancy:update |
| PATCH | /{id}/close, /{id}/reopen, /{id}/restore | vacancy:update |
| DELETE | /{id}/trash | vacancy:delete — bloqueado se houver candidaturas associadas |
| DELETE | /{id}/force | vacancy:delete |
Candidatura (application)
Entidade: ApplicationEntity — chave composta (vacancyId + candidateId, sem id próprio).
É a entidade que conecta Candidato ↔ Vaga e carrega o andamento do processo seletivo.
Máquina de estados (status)
APPLIED ──approve()──▶ APPROVED ──hire()──▶ HIRED
│ │
└─────reject()──────────┴─────reject()───▶ REJECTED
│ │
└─────withdraw()────────┴─────withdraw()──▶ WITHDRAWN
│
└──approve()──▶ APPROVEDHIRED e REJECTED são estados finais. WITHDRAWN permite reaprovação via approve(), para o caso em
que o candidato desistiu e depois voltou ao processo. Cada transição publica um domain event (ApplicationCreatedEvent,
ApplicationApprovedEvent, ApplicationHiredEvent, ApplicationRejectedEvent,
ApplicationWithdrawnEvent).
Endpoints (/gnoqcore/v1/application)
| Método | Rota | Permissão |
|---|---|---|
| POST | / | application:create |
| GET | /vacancy/{vacancyId}/candidate/{candidateId}, / (lista paginada) | application:read |
| PATCH | .../approve, .../hire, .../reject, .../withdrawn | application:update |
| DELETE | /vacancy/{vacancyId}/candidate/{candidateId} | application:delete |
Observação: ao contrário dos outros módulos, Application não tem endpoint /force (hard delete) nem
suporte a filtro deleted na listagem — ainda não segue o padrão completo de soft delete descrito em
Soft Delete.