feat(workspace): refine career workflows

Make job/CV comparisons language-aware and filter recruitment noise. Improve responsive career navigation, shared spacing, dashboard priorities, settings, localized workspace controls, and portable browser tests.
This commit is contained in:
cesnimda
2026-08-29 16:44:44 +02:00
parent 4d4af47651
commit 9edcbfc5de
29 changed files with 827 additions and 236 deletions
@@ -51,7 +51,11 @@ public sealed record CareerMatchDto(
IReadOnlyList<string> Suggestions,
int AiSuggestionCount,
bool HasSelectedCv = false,
string? SelectedCvName = null);
string? SelectedCvName = null,
string JobLanguage = "en",
string? CvLanguage = null,
bool LanguageMismatch = false,
bool UsedTranslatedJobDescription = false);
public interface IApplicationIntelligenceService
{
@@ -259,7 +263,24 @@ public sealed class ApplicationIntelligenceService : IApplicationIntelligenceSer
["Skills"] = skillsText,
};
var result = _match.Evaluate(job.JobTitle, job.Description ?? string.Empty, sections);
var cvCorpus = string.Join("\n", sections.Values);
var jobLanguage = NormalizeMatchLanguage(job.DescriptionLanguage, job.Description);
var cvLanguage = NormalizeMatchLanguage(settings.Language, cvCorpus);
var languageMismatch = !string.Equals(jobLanguage, cvLanguage, StringComparison.OrdinalIgnoreCase);
// Imported Norwegian adverts may already carry a trusted English translation. When the
// explicitly linked CV is English, compare against that saved translation instead of
// penalising equivalent wording in different languages. This endpoint remains read-only:
// it never starts a translation request or mutates either source document.
var useTranslatedJobDescription = languageMismatch
&& jobLanguage == "nb"
&& cvLanguage == "en"
&& !string.IsNullOrWhiteSpace(job.TranslatedDescription);
var matchDescription = useTranslatedJobDescription
? job.TranslatedDescription!
: job.Description ?? string.Empty;
var result = _match.Evaluate(job.JobTitle, matchDescription, sections);
var relevantExperience = experiences
.Select(e => new { Entry = e, Override = Override(settings, e.ItemKey) })
@@ -297,7 +318,11 @@ public sealed class ApplicationIntelligenceService : IApplicationIntelligenceSer
Suggestions: Suggestions(result, relevantExperience.Count),
AiSuggestionCount: aiCount,
HasSelectedCv: true,
SelectedCvName: attached.Name);
SelectedCvName: attached.Name,
JobLanguage: jobLanguage,
CvLanguage: cvLanguage,
LanguageMismatch: languageMismatch,
UsedTranslatedJobDescription: useTranslatedJobDescription);
}
// Suggestions describe what the USER could change. They never edit anything themselves.
@@ -411,4 +436,16 @@ public sealed class ApplicationIntelligenceService : IApplicationIntelligenceSer
private static string? Blank(string? value) =>
string.IsNullOrWhiteSpace(value) ? null : value.Trim();
private static string NormalizeMatchLanguage(string? declaredLanguage, string? text)
{
var language = string.IsNullOrWhiteSpace(declaredLanguage)
? LanguageDetector.Detect(text)
: declaredLanguage.Trim().ToLowerInvariant();
return language.StartsWith("nb", StringComparison.Ordinal)
|| language.StartsWith("no", StringComparison.Ordinal)
|| language.StartsWith("nn", StringComparison.Ordinal)
? "nb"
: "en";
}
}
+3 -1
View File
@@ -80,7 +80,9 @@ namespace JobTrackerApi.Services
"mot", "uten", "hvordan", "ingen", "din", "ditt", "blir", "samme", "hvilken", "hvilke",
"erfaring", "erfaringer", "kvalifikasjoner", "arbeidsoppgaver", "stilling", "stillingen",
"søker", "ser", "ønsker", "mulighet", "spennende", "arbeidsmiljø", "selskap", "bedrift", "kandidat",
"relevant", "fordel", "gode", "dyktig", "sammen",
"relevant", "fordel", "gode", "god", "godt", "dyktig", "sammen", "både", "del", "dnbs",
"faglig", "faglige", "får", "få", "hos", "utvikling", "ansvar", "ansvarlig", "bidra",
"tilbyr", "kollega", "kollegaer", "løsning", "løsninger",
// Common source-page chrome and consent text must never become tailoring advice.
"cookie", "cookies", "privacy", "terms", "conditions", "menu", "home", "login", "contact",
"website", "settings", "navigation", "jobs", "apply", "application", "share", "save", "accept",