Commit Graph

189 Commits

Author SHA1 Message Date
claude 9b0d7fb907 chore: upgrade jQuery from 3.6.1 to 4.0.0
The vendor file was misnamed jquery-1.12.4.min.js but contained v3.6.1.
Replaced with the correctly-named jquery-4.0.0.min.js (78 KB, up from 89 KB).

Compatibility check: none of the removed jQuery 4.0 APIs are used in
main.js — no $.isArray, $.isFunction, $.trim, $.type, $.parseJSON, etc.
All ajax/deferred/DOM methods in use ($.ajax, $.when, .done/.fail/.always,
.on, .prop, .css, .addClass etc.) remain in the full 4.0 build.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 09:58:02 +03:00
gelu 323e41e024 Merge pull request 'Fix error propagation: surface API validation messages in the UI' (#29) from fix/error-propagation-28 into main
Fix error propagation: surface API validation messages in the UI
2026-05-28 06:43:25 +00:00
claude 7908dad181 Fix error propagation: surface API validation messages in the UI
- UseJsonExceptionHandler now maps InvalidOperationException to 400 (was 500),
  so upstream business-rule rejections reach the browser as actionable messages.
- CvMatcherController forwards Refit 4xx bodies from cv-matcher-api instead
  of swallowing them in a generic 502.
- ErrorResponse.Score removed; CaptchaController puts the score in Detail.
- Frontend extractApiError helper reads the server Error/error/title field for
  4xx responses and falls back to a generic i18n string for 5xx / missing body.
- All four failure handlers (CV upload, CV match, contact form, subscribe form)
  updated to use extractApiError with the correct rate-limit i18n key.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 09:41:24 +03:00
gelu 2e1efc598b Merge pull request 'Improve comments and Swagger docs across services' (#27) from feature/improve-comments-swagger-26 into main
Merge pull request #27: Improve comments and Swagger docs across services
2026-05-28 06:26:56 +00:00
claude 16bb195cb5 Add XML doc to all service interfaces and implementations (#26)
- Update CLAUDE.md: replace incorrect 'no XML doc on internal code' rule
  with the correct convention (XML doc on all public methods and
  non-trivial private/protected helpers)
- Restore /// <summary> on FileDownloadController private helpers
  (HandleRangeRequest, StreamRangeAsync)
- Add full XML doc to all service contracts:
  ICaptchaVerifier, IEmailSender, ICvMatcherService, IJobTextExtractor,
  IJobTokenService, IDocumentClassifier, IRagService, ITextChunker,
  ITextExtractor, IEmailTemplateService, ITemplateService
- Add /// <summary> and /// <inheritdoc /> to all concrete service classes
  and their methods: RecaptchaVerifier, EmailApiEmailSender,
  SmtpEmailDispatcher, CvMatcherService, JobTextExtractor, JobTokenService,
  RagService, DocumentClassifier, TextChunker, TextExtractor,
  HtmlJobSearcher, CvSearchEmailSender, CvSearchJobTask,
  EmailTemplateService, DbTemplateService

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 09:17:42 +03:00
claude 4ee4a59b5e Improve comments and Swagger annotations across services (#26)
- EmailController: add class summary, full SwaggerResponse/ProducesResponseType
  for 400 and 500, and Description on SwaggerOperation
- ContactController: fix terse "Failed." error message to
  "Could not process subscription."
- FileDownloadController: remove redundant XML <response code> tags from
  the public action doc block; convert private-method /// <summary> to //
  (project convention: no XML doc on internal code)
- CvMatcherService: remove two dead commented-out blocks (old email send
  and BuildEmailBody helper)
- JobTokenService: comment the phone/contact-line regex filter in
  ExtractKeywords
- DocumentClassifier: comment the keyword-frequency scoring approach and
  the confidence formula
- TextChunker: comment the sliding-window step (chunkSize - overlap)
- CvSearchJobTask: comment the GdprConsent = true rationale and the
  BuildCvFileName sanitisation logic
- HtmlJobSearcher: comment GetLeftPart(UriPartial.Path) query-strip dedup

Closes #26

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 09:07:23 +03:00
gelu 7d92f2f8d9 Merge pull request 'Split templates table into emailApi, cvMatcher, and myAi schemas' (#25) from feature/split-templates into main
feat: split templates table into emailApi, cvMatcher, and myAi schemas (#25)
2026-05-28 05:57:15 +00:00
claude de7a3a3a2d feat(myai-data): cleanup migration removes email.* and ai.* templates; update CLAUDE.md
- Add DeleteMigratedTemplates migration: removes all email.* and ai.*
  rows from myAi.Templates (now owned by emailApi.EmailTemplates and
  cvMatcher.AiPrompts respectively)
- CLAUDE.md: add email-api-data to solution layout; add emailApi schema
  to database schemas table; add email-api-data EF CLI migration command;
  note cv-matcher-api no longer runs MyAi migrations

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 08:50:19 +03:00
claude a1c145e861 feat(cv-matcher): add AiPrompts table; remove MyAiDbContext dependency
cv-matcher-data:
- Add AiPromptEntity (Key, Language, Value, Description, UpdatedAt)
- Add AiPrompts DbSet to CvMatcherDbContext with composite PK
- Migration AddAiPrompts: create cvMatcher.AiPrompts table and seed
  ai.cv-match.system-prompt (language "*") with the current prompt value

cv-matcher-api:
- Add IAiPromptsRepository / EfAiPromptsRepository under Data/Repositories/
- CvMatcherService: inject IAiPromptsRepository; replace _templates.Render(...)
  with async DB lookup + simple string replacement
- Program.cs: register IAiPromptsRepository (scoped); remove MyAiDbContext,
  ITemplateService/DbTemplateService registrations and MyAiDbContext migration call
- Remove myai-data ProjectReference

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 08:48:39 +03:00
claude e17f17b566 feat(cv-search-job): replace MyAiDbContext+ITemplateService with IEmailTemplateService
- 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>
2026-05-28 08:45:18 +03:00
claude e7ca6043b7 feat(api): wire IEmailTemplateService; replace Contact:ToEmail with OperatorCopy
- Add ProjectReference to email-api-data
- Register EmailApiDbContext (no migrate — email-api owns migrations)
- Register IEmailTemplateRepository (scoped) and IEmailTemplateService (singleton)
- EmailApiEmailSender: replace ITemplateService with IEmailTemplateService for
  all email.* template rendering (match body/subject/footer)
- SendMatchAsync: replace _contact.ToEmail operator copy with
  GetOperatorCopy("email.match.subject", "en") from DB template

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 08:43:07 +03:00
claude c415ab3957 feat(email-api): wire email-api-data; load html shell templates from DB
- Add ProjectReference to email-api-data
- Register EmailApiDbContext + run migrations on startup
- Register IEmailTemplateRepository (scoped) and IEmailTemplateService (singleton)
- SmtpEmailDispatcher: inject IEmailTemplateService; replace hardcoded
  HtmlShellStart/HtmlShellEnd string constants with DB template lookups
  (email.html-shell.start / email.html-shell.end, language "*")

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 08:40:40 +03:00
claude 19e73aca17 feat: add email-api-data project with EmailTemplates repository and service
New data project owning the emailApi schema:
- EmailTemplateEntity with Key, Language, Value, Description, UpdatedAt, OperatorCopy
- EmailApiDbContext (schema: emailApi, custom migration table _EmailApiMigrations)
- IEmailTemplateRepository / EfEmailTemplateRepository (scoped)
- IEmailTemplateService / EmailTemplateService (singleton, 10-min cache)
  - GetOperatorCopy falls back to first non-empty OperatorCopy across all rows
- Initial migration CreateEmailTemplates: creates table + seeds all email.*
  templates (match + search-results in en/ro) and html-shell fragments
  with OperatorCopy = "contact@myai.ro" for addressable rows

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 08:39:15 +03:00
gelu e260982a91 Merge pull request 'feat: extract email sending into dedicated email-api service' (#23) from feature/email-api into main
feat: extract email sending into dedicated email-api service (#23)
2026-05-27 13:34:03 +00:00
claude ba92c9f793 feat: wire email-api into docker-compose, .sln and CLAUDE.md
- 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>
2026-05-27 16:26:56 +03:00
claude 8878efe184 feat: add UpdateEmailTemplatesToHtml migration
Upgrades 8 email body templates from plain text to styled HTML.
Templates: email.match.body, email.match.job-search-footer,
email.search-results.body, email.search-results.empty (en + ro each).
All use inline CSS only (Gmail-compatible). Branded #2c5282 accent.

Closes #22

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 16:24:23 +03:00
claude 6fad147650 feat: replace direct MailKit in cv-search-job with IEmailApiClient Refit call
- CvSearchEmailSender now injects IEmailApiClient instead of IConfiguration+MailKit
- BuildBody updated to produce styled HTML job cards
- CvSearchJobTask passes only filename (not full path) to email sender
- IEmailApiClient registered in Program.cs with EmailApi:BaseUrl + InternalApiKey
- MailKit removed from cv-search-job.csproj

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 16:19:49 +03:00
claude 8126e7c112 feat: replace SmtpEmailSender with EmailApiEmailSender in api
- EmailApiEmailSender calls email-api via IEmailApiClient Refit client
- HTML bodies built inline for contact/subscribe/file-download emails
- match and job-search emails use DB templates (rendered in caller)
- SmtpSettings moved from api-models to email-api (kept in Models.Settings namespace)
- MailKit removed from api.csproj
- SmtpEmailSender deleted; IEmailSender interface unchanged

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 16:18:11 +03:00
claude 26b13f6dbf feat: add email-api service and email-api-models contract project
New internal service that centralises SMTP email sending.
- email-api-models: SendEmailRequest DTO, IEmailApiClient Refit interface, EmailApiSettings
- email-api: SmtpEmailDispatcher (MailKit), EmailController (POST /api/email/send),
  branded HTML shell wrapper, shared-Files-volume attachment support
- Protected by X-Internal-Api-Key via UseInternalApiKeyProtection()
- No exposed Docker port — internal network only (http://email-api:8080)

Closes #22

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 16:15:59 +03:00
claude 45d991ab5b Small changes 2026-05-27 15:53:00 +03:00
claude b6d01e39b6 Merge pull request 'refactor: reorganise models and data-layer structure across the solution' (#21) from refactor/models-data-layer-structure into main
refactor: reorganise models and data-layer structure across the solution (#21)
2026-05-27 12:46:27 +00:00
claude d43a1ca3e6 chore: add sample CV.pdf for local testing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 15:45:35 +03:00
claude cb6178c90d docs: add YAML frontmatter to general-dev-workflow skill
Required by the Claude skill upload dialog for name/description discovery.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 15:43:58 +03:00
claude b4d050a3cf docs: add general-dev-workflow skill to repo for version control
Stores the canonical general-dev-workflow skill definition alongside the
codebase so it travels with the project and can be evolved via normal PRs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 15:41:26 +03:00
claude e95ed36647 refactor: restructure solution into -models/-data/-api project taxonomy
Phases 1-10 of the planned refactoring:

Phase 1: rename shared-models -> common
  - namespace Shared.Models -> Common throughout
  - remove stale AspNetCore.Http.Features 5.0 reference

Phase 2: create shared-data with abstract BaseEntity
  - BaseEntity: required string Id { get; init; } + DateTime CreatedAt { get; init; }

Phase 3: rename myai-models -> myai-data
  - namespace MyAi.Models -> MyAi.Data
  - MigrationsAssembly("myai-data")

Phase 4: rename cv-search-models -> cv-search-data
  - namespace CvSearch.Models -> CvSearch.Data
  - move JobSearchSettings to cv-matcher-api-models
  - JobSearch*Entity now inherits BaseEntity

Phase 5: extract rag-data from rag-api
  - new project: Apis/rag-data with RagDbContext + entities + migrations
  - RagDocumentEntity inherits BaseEntity; cache entities use CacheKey PK
  - fix duplicate AddHttpClient<RagAiClient>/AddScoped registrations in rag-api
  - MigrationsAssembly("rag-data")

Phase 6: extract cv-matcher-data from cv-matcher-api
  - new project: Apis/cv-matcher-data with CvMatcherDbContext + entities + migrations
  - CvMatchResultEntity inherits BaseEntity; CvMatcherChatCacheEntity uses CacheKey PK
  - MigrationsAssembly("cv-matcher-data")

Phase 7: create empty cv-cleanup-job-models and cv-search-job-models

Phase 8: update all 5 Dockerfiles for renamed/new projects

Phase 9: reorganise .sln virtual folders (Apis/Jobs/Models/Data/Helpers)
  - update root CLAUDE.md with new project taxonomy and migration commands
  - update cv-matcher-api/CLAUDE.md and cv-search-job/CLAUDE.md

Phase 10: add Directory.Packages.props for centralised NuGet versions
  - remove Version= from all PackageReference elements in active .csproj files

No database changes. No runtime behaviour changes.
All MigrationId strings in __EFMigrationsHistory are unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 15:26:03 +03:00
Claude Dev Environment 9d8db59825 fix: update web project port from 5000 to 5140 for Caddy reverse proxy alignment
- 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
2026-05-27 13:05:40 +03:00
claude d08eb5d1dc fix: restore published port for myai-web + watchtower label
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>
2026-05-24 18:40:24 +03:00
claude 3cb6a8d702 fix: add Database env vars to api service in docker-compose
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>
2026-05-24 18:16:34 +03:00
claude fc6fe7a78b feat: DB-backed localized templates + language-aware emails
- New Apis/myai-models project: MyAiDbContext (schema myAi), TemplateEntity,
  ITemplateService, DbTemplateService with 10-min in-memory cache
- Seeds EN+RO variants for all user-facing templates (match email, job search
  results email, HTML status pages, AI system prompt)
- Match result email now sent in user's UI language (en/ro)
- Job search results email now respects session language
- Language propagates: MatchJobRequest -> token -> session -> email
- Add Language column to JobSearchTokens and JobSearchSessions (default 'en')
- All three Dockerfiles updated to include myai-models in build context

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 18:06:44 +03:00
claude 2cada13fe3 Fix footer vertical misalignment — zero p margin inside footer-wrap
The <p> wrapping the copyright line had default browser margins (1em top/bottom)
which offset it above the sibling flex items despite align-items: center.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 17:11:54 +03:00
claude b6878e3b45 Respect UI language in match result — LLM responds in user's selected language
The frontend sends the active language code (currentLang()) with every match
request. CvMatcherService injects a language instruction into the system prompt
so the LLM returns summary, strengths, gaps, recommendations, and evidence in
the correct language. The match result cache (CvMatchResults) now includes
Language as part of the lookup key so Romanian and English results are stored
and retrieved independently. Existing cached rows default to 'en'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 17:04:21 +03:00
claude e394dad5fb Merge remote-tracking branch 'origin/staging' 2026-05-22 20:49:34 +03:00
claude 1fcf1e1470 Add complete XML doc and Swagger annotations to all controller endpoints
Every public action now has <summary>, <param>, and <returns> XML docs
plus matching SwaggerOperation/SwaggerResponse attributes with typed response
descriptions. Class-level summaries added to CvController, JobSearchController,
and RagController. Explanatory inline comments removed from FileDownloadController
per project conventions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 20:47:47 +03:00
claude 6deb8dd4c8 Move version display to GET /api/health/version in HealthController
Uses GetApplicationVersion(Assembly.GetExecutingAssembly()) — the same
timestamp-based version already logged at startup and baked into the
assembly via the csproj <Version> property. Removes the minimal-API
/version endpoint from web/Program.cs and reverts the web Dockerfile
APP_VERSION build-arg (no longer needed).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 20:25:07 +03:00
claude 7441eb8cda Remove APP_VERSION from docker-compose — version is baked into image by CI
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>
2026-05-22 20:20:56 +03:00
claude 0154b56881 Add auto-incrementing version display to web UI footer
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>
2026-05-22 20:18:31 +03:00
gelu bf0f46e77c Merge pull request 'Main build' (#10) from main into staging
Build and Push Docker Images Staging / build (push) Successful in 10s
Reviewed-on: #10
2026-05-22 17:05:10 +00:00
claude eced9531bc Merge 2026-05-22 20:04:12 +03:00
gelu 6f8923e8f6 Add cv-search-job to staging build pipeline
Build and Push Docker Images Staging / build (push) Successful in 10s
2026-05-22 16:08:57 +00:00
claude 7bed001d8b Add .claude/ to .gitignore
Build and Push Docker Images / build (push) Successful in 9s
Claude Code stores session files under .claude/ — these are local tooling
artifacts and should not be tracked in the repository.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 19:03:47 +03:00
claude cf064531c5 Refactor docker-compose: single deployable file + local override
Build and Push Docker Images / build (push) Successful in 11s
- 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>
2026-05-22 18:52:39 +03:00
claude a4c128fdf4 Fix cv-matcher-api Dockerfile: add cv-search-models to build context
Build and Push Docker Images / build (push) Successful in 3m42s
dotnet restore failed in CI because cv-search-models.csproj was added as
a ProjectReference but not copied into the Docker build context.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:17:58 +03:00
claude 6293fa89e3 Add internet job search feature (cv-search-job)
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>
2026-05-22 17:56:23 +03:00
claude a0ae262afc Main build
Build and Push Docker Images / build (push) Successful in 7s
2026-05-20 21:16:34 +03:00
claude 95d05d8fc8 Staging build
Build and Push Docker Images Staging / build (push) Successful in 9s
2026-05-20 21:15:18 +03:00
claude 270deaaef6 Production build
Build and Push Docker Images Production / build (push) Successful in 9s
2026-05-20 21:14:47 +03:00
claude 2d9f05cf33 Production build 2026-05-20 21:13:16 +03:00
claude 0829eba2b1 Production build 2026-05-20 21:12:58 +03:00
claude 6e54b20a02 Staging build 2026-05-20 21:11:25 +03:00
claude aa79b422e4 Changes
Build and Push Docker Images / build (push) Successful in 31s
2026-05-20 14:25:07 +03:00