Add internet job search feature (cv-search-job)
Build and Push Docker Images / build (push) Failing after 1m36s
Build and Push Docker Images / build (push) Failing after 1m36s
- New cv-search-models shared library: EF entities + CvSearchDbContext for cvSearch schema (JobSearchTokens, JobSearchSessions, JobSearchResults tables) - New cv-search-job worker service: polls DB for pending sessions, scrapes job boards via configurable HTML scraping, runs LLM scoring via cv-matcher-api, emails ranked results - cv-matcher-api: JobTokenService creates one-time tokens; JobSearchController handles link clicks and creates sessions - api: proxies job-search start endpoint, appends job search link to match result email - CI workflow updated to build and push myai-cv-search-job:staging image - CLAUDE.md documentation added for all affected services Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
using Api.Services.Contracts;
|
||||
using CvMatcher.Models.Requests;
|
||||
using CvMatcher.Models.Responses;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Shared.Models.Responses;
|
||||
|
||||
namespace Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/cv/job-search")]
|
||||
public sealed class JobSearchController : ControllerBase
|
||||
{
|
||||
private readonly IJobTokenService _tokenService;
|
||||
private readonly ILogger<JobSearchController> _logger;
|
||||
|
||||
public JobSearchController(IJobTokenService tokenService, ILogger<JobSearchController> logger)
|
||||
{
|
||||
_tokenService = tokenService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpPost("token")]
|
||||
public async Task<ActionResult<CreateJobSearchTokenResponse>> CreateToken(
|
||||
[FromBody] CreateJobSearchTokenRequest request,
|
||||
CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(request.CvDocumentId) || string.IsNullOrWhiteSpace(request.Email))
|
||||
return BadRequest(new ErrorResponse { Error = "CvDocumentId and Email are required.", Code = "invalid_request" });
|
||||
|
||||
var tokenId = await _tokenService.CreateTokenAsync(request.CvDocumentId, request.Email, ct);
|
||||
return Ok(new CreateJobSearchTokenResponse { TokenId = tokenId });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to create job search token.");
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, new ErrorResponse { Error = "Failed to create token.", Code = "token_create_failed" });
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("token/{tokenId}/start")]
|
||||
public async Task<ActionResult<StartJobSearchResponse>> Start(string tokenId, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
var status = await _tokenService.TriggerStartAsync(tokenId, ct);
|
||||
return Ok(new StartJobSearchResponse { Status = status });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to start job search for token {TokenId}.", tokenId);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, new ErrorResponse { Error = "Failed to start search.", Code = "start_failed" });
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user