- feat(025): favoritos locais com FavoritesContext, HeartButton, PublicFavoritesPage
- feat(026): central de contatos admin (leads/contatos unificados)
- feat(027): configuração da página de contato via admin
- feat(028): trabalhe conosco - candidaturas com upload e admin
- feat(029): UX área do cliente - visitas, comparação, perfil
- feat(030): navbar UX - menu mobile, ThemeToggle, useFavorites
- feat(031): hero light/dark - imagens separadas por tema, upload, preview, seed
- feat(032): performance homepage - Promise.all parallel fetches, sessionStorage cache,
preload hero image, loading=lazy nos cards, useInView hook, will-change carrossel,
keyframes em index.css, AgentsCarousel e HomeScrollScene via props
- fix: light mode HomeScrollScene - gradiente, cores de texto, scroll hint
migrations: g1h2i3j4k5l6 (source em leads), h1i2j3k4l5m6 (contact_config),
i1j2k3l4m5n6 (job_applications), j2k3l4m5n6o7 (hero theme images)
13 KiB
Feature Specification: Página "Trabalhe Conosco"
Feature Branch: 028-trabalhe-conosco
Created: 2026-04-21
Status: Draft
Contexto
O site imobiliário atualmente não oferece um canal formal para que candidatos manifestem interesse em trabalhar na empresa. Esse contato ocorre de maneira informal — por telefone, e-mail avulso ou presencialmente — sem rastreabilidade e sem uma experiência consistente para o candidato.
Esta spec cobre a criação de uma página pública "/trabalhe-conosco" com formulário de candidatura, armazenamento das submissões em banco de dados e listagem das candidaturas no painel administrativo. A página também deve ser acessível via links no footer e na página de equipe, tornando o recrutamento um ponto de contato organizado e profissional.
User Scenarios & Testing
User Story 1 — Candidato Envia Formulário de Candidatura (Priority: P1)
Um candidato interessado em trabalhar na imobiliária acessa a página "/trabalhe-conosco", preenche o formulário com seus dados e envia sua candidatura.
Why this priority: É o núcleo da feature. Toda a proposta de valor gira em torno dessa ação — sem ela, a página é apenas um conteúdo estático sem utilidade.
Independent Test: Acessar /trabalhe-conosco sem autenticação, preencher todos os campos obrigatórios (nome, e-mail, telefone, cargo de interesse, mensagem) e submeter. Verificar que uma mensagem de sucesso é exibida e que a candidatura aparece na listagem do painel admin em GET /api/v1/admin/jobs.
Acceptance Scenarios:
- Given um visitante não autenticado na página
/trabalhe-conosco, When ele preenche todos os campos obrigatórios e clica em "Enviar Candidatura", Then a candidatura é registrada no sistema e uma mensagem de confirmação é exibida ao candidato. - Given o formulário preenchido corretamente, When o campo de cargo de interesse é "Corretor(a)", Then o valor enviado e armazenado reflete exatamente a opção selecionada.
- Given o formulário preenchido corretamente com um arquivo PDF informado, When o candidato submete, Then o nome do arquivo é registrado junto com a candidatura, mesmo que o conteúdo do arquivo não seja armazenado nesta versão.
- Given o formulário submetido com sucesso, When o candidato tenta submeter novamente sem recarregar a página, Then o formulário é limpo/resetado após o sucesso, prevenindo envios duplicados acidentais.
- Given falha de rede durante o envio, When a requisição não é completada, Then uma mensagem de erro informativa é exibida e o candidato pode tentar novamente sem perder os dados preenchidos.
User Story 2 — Visitante Descobre a Oportunidade Pelo Site (Priority: P1)
Um visitante que navega pelo footer ou pela página de equipe (/corretores) encontra o link "Trabalhe Conosco" e acessa a página de candidatura.
Why this priority: Sem pontos de entrada adequados, a página não é encontrada organicamente dentro do site, tornando o canal de recrutamento inacessível na prática.
Independent Test: Acessar o footer do site e verificar a presença do link "Trabalhe Conosco" na coluna "A Imobiliária". Acessar /corretores e verificar a presença do link/botão "Trabalhe Conosco". Clicar em cada link e confirmar que navega para /trabalhe-conosco.
Acceptance Scenarios:
- Given um visitante em qualquer página do site, When ele visualiza o footer, Then o link "Trabalhe Conosco" está visível na coluna "A Imobiliária".
- Given um visitante na página
/corretores, When ele visualiza a página de equipe, Then existe um elemento (link ou botão) com o texto "Trabalhe Conosco" que leva a/trabalhe-conosco. - Given um visitante clicando no link "Trabalhe Conosco" a partir do footer, When a navegação ocorre, Then ele é direcionado para
/trabalhe-conoscocom a página completa carregada. - Given um visitante em dispositivo móvel, When ele visualiza o footer ou a página
/corretores, Then o link "Trabalhe Conosco" é igualmente acessível e funcional.
User Story 3 — Administrador Visualiza as Candidaturas Recebidas (Priority: P2)
O administrador da imobiliária acessa o painel admin e visualiza uma listagem paginada de todas as candidaturas enviadas pelos candidatos.
Why this priority: Sem visibilidade das candidaturas, o canal de recrutamento não entrega valor operacional. A listagem é o produto final que o administrador consume para iniciar o processo seletivo.
Independent Test: Com candidaturas já enviadas via formulário público, autenticar como administrador e consultar GET /api/v1/admin/jobs. Verificar que a resposta inclui os dados dos candidatos (nome, e-mail, cargo, data de envio) com paginação funcional.
Acceptance Scenarios:
- Given um administrador autenticado, When ele acessa o endpoint de listagem de candidaturas, Then a resposta inclui uma lista paginada com nome, e-mail, telefone, cargo de interesse, data de envio e nome do arquivo informado para cada candidatura.
- Given mais de 20 candidaturas no sistema, When o administrador consulta a segunda página, Then os resultados são diferentes da primeira página e o total de candidaturas é informado na resposta.
- Given um usuário não autenticado tentando acessar o endpoint de listagem, When a requisição é enviada, Then o sistema retorna erro de acesso não autorizado (HTTP 401).
- Given um token de usuário comum (não administrador), When ele tenta acessar o endpoint de listagem, Then o sistema retorna erro de permissão insuficiente (HTTP 403).
- Given nenhuma candidatura registrada, When o administrador consulta a listagem, Then o sistema retorna uma lista vazia com o total zerado, sem erro.
User Story 4 — Candidato Vê a Página com Conteúdo Institucional (Priority: P3)
Um candidato acessa /trabalhe-conosco e, além do formulário, encontra uma apresentação institucional da imobiliária como empregadora, com destaque para benefícios de trabalhar na empresa.
Why this priority: Enriquece a experiência do candidato e posiciona a imobiliária como empregadora, mas não bloqueia o funcionamento do recrutamento em si.
Independent Test: Acessar /trabalhe-conosco e verificar que a página contém: uma hero section com título e subtítulo, uma seção "Por que trabalhar conosco?" com exatamente 3 cards de benefícios, e o formulário de candidatura.
Acceptance Scenarios:
- Given qualquer visitante acessando
/trabalhe-conosco, When a página carrega, Then uma hero section com título principal e subtítulo descritivo é exibida no topo. - Given a página carregada, When o visitante rola a tela, Then uma seção "Por que trabalhar conosco?" com 3 cards de benefícios é visível antes do formulário.
- Given a página carregada, When o visitante acessa em dispositivo móvel, Then hero section, cards de benefícios e formulário se adaptam ao layout vertical sem perda de conteúdo ou sobreposição visual.
Edge Cases
- O que acontece se o candidato enviar o formulário com um e-mail em formato inválido? A validação deve ocorrer no frontend antes do envio, e o backend deve rejeitar com HTTP 422 e mensagem descritiva.
- O que acontece se o campo de mensagem ultrapassar o limite de caracteres? O sistema deve validar e informar o candidato antes de enviar.
- O que acontece se o candidato tentar enviar o mesmo e-mail múltiplas vezes? Por padrão, múltiplas candidaturas do mesmo e-mail são permitidas (sem deduplicação nesta versão).
- O que acontece se o candidato selecionar um arquivo que não seja PDF ou que exceda 2 MB? O frontend deve bloquear o envio e exibir mensagem de erro clara. Nesta versão, apenas o nome do arquivo é registrado — não há upload real de arquivo.
- O que acontece se o backend retornar erro 500 durante o envio? O frontend deve exibir mensagem genérica de erro sem expor detalhes técnicos.
- Como o endpoint público
POST /api/v1/jobs/applyse comporta em caso de sobrecarga? Por padrão, o endpoint não possui rate limiting nesta versão — isso pode ser adicionado futuramente.
Requirements
Functional Requirements
- FR-001: O sistema DEVE disponibilizar a rota pública
/trabalhe-conoscono frontend, acessível sem autenticação. - FR-002: A página DEVE conter uma hero section com título e subtítulo configurados estaticamente.
- FR-003: A página DEVE conter uma seção "Por que trabalhar conosco?" com 3 cards de benefícios (conteúdo estático).
- FR-004: A página DEVE conter um formulário de candidatura com os campos: nome completo, e-mail, telefone, cargo de interesse (select), mensagem/apresentação e seleção de arquivo de currículo.
- FR-005: O campo de cargo de interesse DEVE oferecer as opções: Corretor(a), Assistente Administrativo, Estagiário(a), Outro.
- FR-006: O formulário DEVE validar campos obrigatórios (nome, e-mail, cargo, mensagem) antes do envio, exibindo mensagens de erro por campo.
- FR-007: O campo de e-mail DEVE validar formato de e-mail válido no frontend antes do envio.
- FR-008: O campo de arquivo DEVE aceitar apenas arquivos PDF e rejeitar arquivos acima de 2 MB, com mensagem de erro clara — a validação ocorre no frontend; nesta versão, apenas o nome do arquivo é enviado ao backend.
- FR-009: Após envio bem-sucedido, o formulário DEVE exibir uma mensagem de confirmação ao candidato e limpar os campos.
- FR-010: O sistema DEVE disponibilizar o endpoint público
POST /api/v1/jobs/applyque receba e persista os dados textuais da candidatura (sem autenticação). - FR-011: O backend DEVE validar os dados recebidos no endpoint de candidatura e retornar HTTP 422 com detalhes para dados inválidos.
- FR-012: O sistema DEVE armazenar as candidaturas em uma tabela
job_applicationscom os campos: nome completo, e-mail, telefone, cargo de interesse, mensagem, nome do arquivo informado e data/hora do envio. - FR-013: O sistema DEVE disponibilizar o endpoint protegido
GET /api/v1/admin/jobsque retorne uma listagem paginada das candidaturas, acessível apenas por administradores autenticados. - FR-014: O endpoint de listagem DEVE retornar para cada candidatura: nome, e-mail, telefone, cargo de interesse, mensagem, nome do arquivo e data de envio.
- FR-015: O endpoint de listagem DEVE suportar paginação com parâmetros
pageeper_page, retornando o total de registros. - FR-016: O footer do site DEVE conter o link "Trabalhe Conosco" na coluna "A Imobiliária", navegando para
/trabalhe-conosco. - FR-017: A página
/corretoresDEVE conter um link ou botão "Trabalhe Conosco" navegando para/trabalhe-conosco. - FR-018: O design da página DEVE seguir os design tokens existentes do projeto (cores, tipografia Inter, estilo de cards limpos).
Key Entities
- JobApplication: Registro de candidatura enviada por um candidato. Atributos principais: identificador único, nome completo do candidato, e-mail, telefone, cargo de interesse selecionado, texto de apresentação/mensagem, nome do arquivo de currículo informado (opcional), data e hora do envio. Sem relacionamento com outras entidades nesta versão.
Success Criteria
Measurable Outcomes
- SC-001: Um candidato consegue localizar e acessar a página "Trabalhe Conosco" a partir do footer ou da página de equipe em no máximo 2 cliques.
- SC-002: Um candidato consegue preencher e enviar o formulário de candidatura completo em menos de 3 minutos.
- SC-003: 100% das candidaturas enviadas com dados válidos são armazenadas e recuperáveis pelo administrador via painel admin.
- SC-004: Tentativas de acesso não autorizado ao endpoint de listagem de candidaturas são bloqueadas em 100% dos casos.
- SC-005: O formulário exibe mensagem de erro específica para cada campo inválido sem necessidade de recarregar a página.
- SC-006: A página carrega e exibe todo o conteúdo estático (hero, benefícios, formulário) em menos de 2 segundos em conexões de banda larga padrão.
Assumptions
- O upload real do arquivo de currículo (armazenamento binário no servidor ou serviço de storage) está fora do escopo desta versão; apenas o nome do arquivo informado pelo candidato é salvo como texto.
- Não há deduplicação de candidaturas por e-mail nesta versão — múltiplas submissões do mesmo endereço são permitidas.
- Os 3 benefícios exibidos na seção "Por que trabalhar conosco?" são conteúdo estático definido em tempo de desenvolvimento; não há interface de gerenciamento para esse conteúdo.
- Não há envio de e-mail de confirmação ao candidato nem notificação por e-mail ao administrador nesta versão.
- O endpoint público de candidatura não possui rate limiting nesta versão.
- A listagem de candidaturas no painel admin é acessível via API; a interface visual no painel admin (página React de
/admin/jobs) pode ser entregue em iteração futura, não sendo requisito desta spec. - O padrão de autenticação de administrador já implementado no projeto (
require_admin) é suficiente e será reutilizado para proteger o endpoint de listagem. - O campo de telefone é opcional para o candidato, mas recomendado — a validação de formato não é obrigatória nesta versão.