feat: Add legal compliance changes

- Replace 'diploma mill' language with objective 'unaccredited institution' terminology
- Rename DiplomaMills.cs to UnaccreditedInstitutions.cs with neutral language
- Update EducationVerificationResult.IsUnaccredited property
- Update flag titles to 'Unaccredited Institution' and 'Institution Requires Verification'
- Add legal disclaimer to verification report page
- Add Privacy Policy page (/privacy) with UK GDPR compliance info
- Add Terms of Service page (/terms) with candidate notice requirements
- Add footer links to Privacy and Terms pages
- Update all tests to use new terminology

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-25 04:52:12 +00:00
parent 49e4f74768
commit 0c42842655
9 changed files with 401 additions and 57 deletions

View File

@@ -30,7 +30,7 @@ public sealed class ProcessCVCheckJob
private const int GapMonthPenalty = 1;
private const int MaxGapPenalty = 10;
private const int OverlapMonthPenalty = 2;
private const int DiplomaMillPenalty = 25;
private const int UnaccreditedInstitutionPenalty = 25;
private const int SuspiciousInstitutionPenalty = 15;
private const int UnverifiedEducationPenalty = 5;
private const int EducationDatePenalty = 10;
@@ -185,11 +185,11 @@ public sealed class ProcessCVCheckJob
cvData.Employment);
_logger.LogDebug(
"Education verification for check {CheckId}: {Count} entries verified ({Recognised} recognised, {DiplomaMill} diploma mills)",
"Education verification for check {CheckId}: {Count} entries verified ({Recognised} recognised, {Unaccredited} unaccredited)",
cvCheckId,
educationResults.Count,
educationResults.Count(e => e.IsVerified),
educationResults.Count(e => e.IsDiplomaMill));
educationResults.Count(e => e.IsUnaccredited));
// Step 7: Analyse timeline
cvCheck.ProcessingStage = "Analysing Timeline";
@@ -406,23 +406,23 @@ public sealed class ProcessCVCheckJob
AddPLCExperienceFlag(verifications, flags);
AddVerifiedDirectorFlag(verifications, flags);
// Penalty for diploma mills (critical)
foreach (var edu in educationResults.Where(e => e.IsDiplomaMill))
// Penalty for unaccredited institutions (critical)
foreach (var edu in educationResults.Where(e => e.IsUnaccredited))
{
score -= DiplomaMillPenalty;
score -= UnaccreditedInstitutionPenalty;
flags.Add(new FlagResult
{
Category = FlagCategory.Education.ToString(),
Severity = FlagSeverity.Critical.ToString(),
Title = "Diploma Mill Detected",
Description = $"'{edu.ClaimedInstitution}' is a known diploma mill. {edu.VerificationNotes}",
ScoreImpact = -DiplomaMillPenalty
Title = "Unaccredited Institution",
Description = $"'{edu.ClaimedInstitution}' is not found in the register of recognised institutions. {edu.VerificationNotes}",
ScoreImpact = -UnaccreditedInstitutionPenalty
});
}
// Penalty for suspicious institutions
foreach (var edu in educationResults.Where(e => e.IsSuspicious && !e.IsDiplomaMill))
foreach (var edu in educationResults.Where(e => e.IsSuspicious && !e.IsUnaccredited))
{
score -= SuspiciousInstitutionPenalty;
@@ -430,15 +430,15 @@ public sealed class ProcessCVCheckJob
{
Category = FlagCategory.Education.ToString(),
Severity = FlagSeverity.Warning.ToString(),
Title = "Suspicious Institution",
Description = $"'{edu.ClaimedInstitution}' has suspicious characteristics. {edu.VerificationNotes}",
Title = "Institution Requires Verification",
Description = $"'{edu.ClaimedInstitution}' has characteristics that warrant additional verification. {edu.VerificationNotes}",
ScoreImpact = -SuspiciousInstitutionPenalty
});
}
// Penalty for unverified education (not recognised, but not flagged as fake)
// Penalty for unverified education (not recognised, but not flagged as unaccredited)
// Skip unknown/empty institutions as there's nothing to verify
foreach (var edu in educationResults.Where(e => !e.IsVerified && !e.IsDiplomaMill && !e.IsSuspicious && e.Status == "Unknown"
foreach (var edu in educationResults.Where(e => !e.IsVerified && !e.IsUnaccredited && !e.IsSuspicious && e.Status == "Unknown"
&& !string.IsNullOrWhiteSpace(e.ClaimedInstitution)
&& !e.ClaimedInstitution.Equals("Unknown Institution", StringComparison.OrdinalIgnoreCase)
&& !e.ClaimedInstitution.Equals("Unknown", StringComparison.OrdinalIgnoreCase)))

View File

@@ -14,17 +14,17 @@ public sealed class EducationVerifierService : IEducationVerifierService
{
var institution = education.Institution;
// Check for diploma mill first (highest priority flag)
if (DiplomaMills.IsDiplomaMill(institution))
// Check for unaccredited institution first (highest priority flag)
if (UnaccreditedInstitutions.IsUnaccredited(institution))
{
return new EducationVerificationResult
{
ClaimedInstitution = institution,
Status = "DiplomaMill",
Status = "Unaccredited",
IsVerified = false,
IsDiplomaMill = true,
IsUnaccredited = true,
IsSuspicious = true,
VerificationNotes = "Institution is on the diploma mill blacklist",
VerificationNotes = "Institution not found in QAA/HESA register of recognised institutions",
ClaimedStartDate = education.StartDate,
ClaimedEndDate = education.EndDate,
DatesArePlausible = true,
@@ -34,16 +34,16 @@ public sealed class EducationVerifierService : IEducationVerifierService
}
// Check for suspicious patterns
if (DiplomaMills.HasSuspiciousPattern(institution))
if (UnaccreditedInstitutions.HasSuspiciousPattern(institution))
{
return new EducationVerificationResult
{
ClaimedInstitution = institution,
Status = "Suspicious",
IsVerified = false,
IsDiplomaMill = false,
IsUnaccredited = false,
IsSuspicious = true,
VerificationNotes = "Institution name contains suspicious patterns common in diploma mills",
VerificationNotes = "Institution name contains patterns that may indicate unaccredited status",
ClaimedStartDate = education.StartDate,
ClaimedEndDate = education.EndDate,
DatesArePlausible = true,
@@ -64,7 +64,7 @@ public sealed class EducationVerifierService : IEducationVerifierService
MatchedInstitution = officialName,
Status = "Recognised",
IsVerified = true,
IsDiplomaMill = false,
IsUnaccredited = false,
IsSuspicious = false,
VerificationNotes = institution.Equals(officialName, StringComparison.OrdinalIgnoreCase)
? "Verified UK higher education institution"
@@ -88,7 +88,7 @@ public sealed class EducationVerifierService : IEducationVerifierService
ClaimedInstitution = institution,
Status = "Unknown",
IsVerified = false,
IsDiplomaMill = false,
IsUnaccredited = false,
IsSuspicious = false,
VerificationNotes = isUnknownInstitution ? null : "Institution not found in UK recognised institutions database. May be an international institution.",
ClaimedStartDate = education.StartDate,