Deployed staging/prod envs now use Database__Host=mssql.easysoft.ro (LAN DNS -> the MSSQL
VM 10.0.0.240) instead of the raw IP, matching the infra DNS standardization. The
docker-compose default stays 'sqlserver' for local dev. (.env/.env.staging/.env.production
are gitignored; their deployed values were updated locally and apply on redeploy.)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Use http://page-fetcher-api:8080 (the Compose service key) for Docker DNS
resolution, consistent with all other internal service URLs (rag-api,
email-api, cv-matcher-api).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduces page-fetcher-api, a new internal ASP.NET Core service that
centralises all web-page fetching through a single Playwright (headless
Chromium) browser instance. All fetches are persisted to the pageFetcher
SQL schema for auditing.
New projects:
- Apis/page-fetcher-api-models: FetchPageRequest, FetchPageResponse, IPageFetcherApiClient
- Apis/page-fetcher-data: PageFetchDbContext, PageFetchEntity, InitialSchema migration (schema: pageFetcher)
- Apis/page-fetcher-api: PlaywrightBrowserService (singleton), PageFetcherService, PageController
Changes to existing services:
- cv-matcher-api: JobTextExtractor now calls IPageFetcherApiClient instead of HttpClient
- cv-search-job: HtmlJobSearcher uses IPageFetcherApiClient (removes inline Playwright);
CvSearchJobTask fetches individual job pages and applies keyword pre-filter before
LLM call; passes pre-fetched JobDescription to cv-matcher-api to skip re-fetch
- common: add PageFetcherApiSettings
- docker-compose.yml, build.yml: add new service + env vars for callers
Closes#43
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Serilog.Settings.Configuration cannot deserialize NetworkCredential or
MailKit's SecureSocketOptions from JSON, causing an InvalidOperationException
in the binder and preventing containers from starting.
Fix: remove Email from the WriteTo JSON array entirely and wire it in code
inside ConfigureJsonSerilog using a dedicated SerilogEmail:* config section.
The sink is skipped when From/To/Host are absent, so local dev is unaffected.
Also renames the docker-compose env vars from the verbose
Serilog__WriteTo__2__Args__* prefix to the clean SerilogEmail__* prefix.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Serilog.Sinks.Email v4 renamed all configuration parameters from their
v2 names. The old names were silently ignored, so no error alert emails
were ever sent.
Parameter renames applied across all 6 appsettings.json and docker-compose:
fromEmail → from
toEmail → to
mailServer → host
networkCredential → credentials
enableSsl: true → connectionSecurity: StartTls
emailSubject → subject
outputTemplate → body
batchPostingLimit / period removed (v4 batching uses a separate overload)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5 requests / 1 min per IP. docker-compose.yml wired with ${VAR:-default}.
Staging and production .env files updated locally (gitignored).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add ProjectReference to email-api-data; remove myai-data reference
- Program.cs: register EmailApiDbContext (no migrate), IEmailTemplateRepository
(scoped), IEmailTemplateService (singleton); remove MyAiDbContext +
ITemplateService registrations and their migration call
- CvSearchEmailSender: inject IEmailTemplateService; replace
_config["Contact:ToEmail"] with GetOperatorCopy("email.search-results.subject")
for operator copy logic; remove IConfiguration injection
- docker-compose: remove Contact__ToEmail from cv-search-job service block;
add Database__* env vars to email-api service (needed for EmailApiDbContext)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- docker-compose: add email-api service (internal, no ports)
with Smtp__* + FileStorage__Path + Files volume mount
- api + cv-search-job: remove Smtp__* vars, add EmailApi__BaseUrl
and EmailApi__InternalApiKey; add depends_on: email-api
- .sln: move email-api-models to Models virtual folder
- CLAUDE.md: add email-api/email-api-models to layout, update
service dependency diagram and internal API key table
Closes#22
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Changed CORS allowed origin from localhost:5000 to localhost:5140
- Updated docker-compose.override.yml port mapping from 5000:8080 to 5140:8080
- Aligns local development port with staging (myai.easysoft.ro) and production (myai.ro) Caddy reverse proxy configuration on port 5140
The docker-compose refactor moved port 5000:8080 to the override file.
Caddy on staging routes myai.easysoft.ro → localhost:5000, so the port
must be present in the deployment compose. Restoring it as WEB_PORT env var
(default 5000) and adding missing watchtower label.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
api now registers MyAiDbContext for template loading and needs
Database__* connection string vars like the other DB-connected services.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Setting APP_VERSION in docker-compose with a :-unknown fallback would override
the version baked into the image at build time. The CI already embeds it via
--build-arg APP_VERSION=1.0.<commit-count>, so compose should stay silent.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Exposes GET /version endpoint in the web container (reads APP_VERSION env var).
CI computes the version as 1.0.<git-commit-count> and passes it via --build-arg at build time.
Both index.html and cv-matcher/index.html show the version in the footer via a JS fetch.
docker-compose passes APP_VERSION through to the running container.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- docker-compose.yml is now the single file for Portainer (staging and prod).
Uses registry images with ${IMAGE_TAG:-staging}, ${LOGS_PATH:-/opt/myai/logs},
and ${FILES_PATH:-/opt/myai/files} so the same file works for all environments.
- docker-compose.override.yml adds build context, ports, and env_file for local dev
and is auto-merged by "docker compose up" (no extra flags needed).
- .env.template documents IMAGE_TAG, LOGS_PATH, FILES_PATH alongside existing vars.
- docker-compose.dcproj updated so override file nests under docker-compose.yml in
Solution Explorer.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>