ProcessCVCheckJob:
- Recognize "contract", "contract work", "contract role" as freelance
- Add "various", "various clients" for multiple short-term contracts
- Prevents false matching of contract work to dissolved companies
Report.razor:
- Fix stat blocks centering (icon, number, label now centered)
- Fix employment table column alignment with fixed widths
- Add inline styles to header for consistent centering
- Improve GetPointsForCompany to show -10 for unverified companies
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add universal cursor inherit rule for consistent cursor behavior
- Add user-select: none to prevent text selection on UI elements
- Expand element coverage to include modals, tooltips, and inline elements
- Preserve text cursor and selection for form inputs with !important
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- deploy.sh: Publish and deploy from dev machine
- server-setup.sh: One-time Ubuntu server setup (Nginx, Docker, SQL Server)
- README.md: Deployment documentation and troubleshooting guide
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace hero section PNG logo with clean SVG document illustration
- Add comprehensive cursor styling to prevent text cursor on non-editable elements
- Cover all SVG elements, Bootstrap components, and custom classes
- Ensure checkboxes and interactive elements have pointer cursor
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add CandidateName property to VeracityReport and display on report page
- Simplify employment verification layout with compact row-based design
- Add UK employment history notice to Home and Check pages
- Improve hero section text readability with text shadow
- Update Login and Register page styling
- Remove Companies House references from UI text
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move admin credentials from hardcoded values to configuration
- Add rate limiting (5/min) to login endpoint for brute force protection
- Extract CleanJsonResponse to shared JsonResponseHelper class
- Add DateHelpers.MonthsBetween utility and consolidate date calculations
- Update PdfReportService to use ScoreThresholds constants
- Remove 5 unused shared components (EmploymentTable, FlagsList, etc.)
- Clean up unused CSS from MainLayout.razor.css
- Create IPdfReportService interface for better testability
- Add authentication requirement to Hangfire dashboard in development
- Seal EducationVerifierService class
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add checkbox column with Select All in header
- Show selection count badge and Delete Selected button
- Enhanced confirmation modal for bulk operations
- Row highlighting for selected items
- Fixed button spacing (gap between View and Delete)
- Scrollable list in modal for many selected items
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add "partnership" detection to charity/voluntary check (excluding LLPs).
Most UK "X Partnership" organisations are registered charities or CICs,
e.g., North Halifax Partnership Limited (charity 1169746).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update flag assertions to filter by specific flag types
(job now creates additional informational flags)
- Update overlap tests: now "Concurrent Employment" with Info severity
- Update overlap score tests: no penalty for overlaps
(legitimate for part-time, consulting, job transitions)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Enhance text contrast (darker grey #2d2b27)
- Soften footer with warmer dark (#3a3833)
- Use warmer primary blue (#3d5a80)
- Add subtle background gradient for depth
- Strengthen table header styling
- Increase logo size to 95px for better visibility
- Fix AI matcher to handle acronyms in parentheses (e.g., NHP)
- Improve matching rules for CIC/LLP legal suffixes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace bright white backgrounds with warmer off-white tones to reduce
eye strain while maintaining good contrast and professional appearance.
Changes:
- Update CSS variables with warmer neutral palette (#f5f3f0 page bg,
#faf9f7 surfaces, #f0ede8 muted sections)
- Soften primary blue from #2563eb to #3b6fd4
- Update navbar, cards, tables to use new surface colours
- Update upload area, file lists, and icon backgrounds
- Update flag item backgrounds with softer tints
- Update shared components (VeracityScoreCard, FlagsList)
The new colour scheme uses warm off-white/cream tones that are easier
on the eyes than pure white while maintaining professionalism.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace fuzzy string matching with semantic AI matching to fix false
positives where similar-sounding but different companies were matched
(e.g., "Families First CiC" incorrectly matching "FAMILIES AGAINST
CONFORMITY LTD").
Changes:
- Add ICompanyNameMatcherService interface and AICompanyNameMatcherService
implementation using Claude Sonnet 4 for semantic company name comparison
- Add SemanticMatchResult and related models for AI match results
- Update CompanyVerifierService to use AI matching with fuzzy fallback
- Add detection for public sector employers, charities, and self-employed
entries that cannot be verified via Companies House
- Update tests to work with new AI matcher integration
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Red ring for low/zero scores
- Amber ring for medium scores
- Green ring for high scores
- Background ring now visible and coloured appropriately
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add explicit circumference calculation for clarity
- Apply rotate(-90deg) to start progress from 12 o'clock
- Add transform-origin: center for consistent rotation
- Clean up duplicate CSS rules
- Fix mobile responsive styles for score-roundel
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change header background to neutral blue gradient
- Add score roundel with coloured ring based on score
- Ring colour indicates score level (green/amber/red)
- Keeps header consistent regardless of score
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Filter out empty, "Unknown", and "Unknown Institution" values
from generating verification flags since there's nothing to verify.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove score rating labels (Excellent, Good, Fair, Poor, Very Poor)
- Display "TrueCV Score" instead of rating text
- Remove Rating column from batch PDF report
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add custom CSS design system with brand colours and variables
- Enhance Report page with SVG score ring and improved flag styling
- Improve Dashboard with better table design and score badges
- Enhance Check page upload area with animated icon and file styling
- Update spellings to UK English (analysing, recognised)
- Add user-select: none to prevent text cursor on clickable elements
- All date formats already use UK-friendly dd MMM yyyy format
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When the institution name is empty, "Unknown", or "Unknown Institution",
don't show the "not found in UK database" message since it's not useful.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Informational flags are context-only and don't affect the score,
so displaying "0 pts" was redundant and confusing.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The SIC code mismatch check was flagging tech roles at companies not
registered as technology businesses. This is not a reliable measure
since many companies employ tech staff regardless of their SIC code.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
New info flags (no penalty - provide context):
- Career Span: Total years of experience with label (Early Career to Extensive)
- Current Status: Currently employed at X / Available since Y
- Long Tenure: Highlight 5+ year roles positively
- Management Experience: X of Y roles with management titles
- Individual Contributor: When no management titles detected
- Company Size Pattern: Startup/SME/Corporate experience breakdown
- Career Trajectory: Upward/Lateral/Step-down progression analysis
- PLC Experience: Roles at publicly listed companies
- Director Experience: Director/officer roles without red flags
All flags have ScoreImpact = 0 (informational only)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add CheckFrequentJobChanges() to detect short tenure patterns
- Flag when 3+ employers have <18 month tenure (no penalty, info only)
- Group multiple roles at same company/group together
- Calculate and display average tenure across all employers
- Add NormalizeCompanyForGrouping() to handle company name variations
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add GenerateSingleReport() method to PdfReportService for individual CV reports
- PDF includes: score header, employment verification table, timeline analysis,
gaps/overlaps sections, and color-coded flags (critical/warning/info)
- Update Report.razor to use PdfReportService instead of JSON serialization
- Add TrueCV.Web.Services to _Imports.razor
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When matching brand names like "ASDA", prefer the main employer company
(ASDA STORES LIMITED) over subsidiaries (ASDA DELIVERY LIMITED).
- Add SubsidiaryIndicators set (delivery, distribution, holdings, property, etc.)
- Add MainCompanyIndicators set (stores, retail, manufacturing, etc.)
- Add CalculateCompanyPriorityScore() method for ranking matches
- Sort matches by priority score first, then by fuzzy score
- Subsidiaries get -10 priority unless explicitly searched for
- Main trading companies get +5 priority, PLCs get +3
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add NonEmploymentEntityPatterns dictionary with 10 categories of non-employer entities
(clubs, associations, trusts, charities, investment, property, religious, sports, educational, professional)
- Expand SkipWords from ~30 to 120+ words for better core identifier extraction
- Add GetSearchEntityTypes() and IsValidEmploymentEntity() helper methods
- Refactor FindBestMatch() to use pattern-based filtering instead of hardcoded checks
- Fix UI showing duplicate points for same company appearing multiple times
(now only shows points on first occurrence, subsequent rows show 0)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Require ALL core identifier words to be present in match
(e.g., "Lloyds Bowmaker" needs both "LLOYDS" and "BOWMAKER")
- Filter out club/association/society type entities
(prevents "BMW" -> "BMW CAR CLUB LIMITED")
- Filter out benefit/trust/pension type entities
(prevents "BMW Group" -> "BMW GROUP BENEFIT TRUST LIMITED")
- Core word extraction now returns all significant words, not just first
Fixes false matches like:
- "BMW Group Canada" -> "CANADA LIFE GROUP" (missing BMW)
- "Bank of Scotland" -> "BANK AND CLIENTS PLC" (missing Scotland)
- "Lloyds Bowmaker" -> "LLOYDS ALARMS" (missing Bowmaker)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a company appears multiple times in employment history (e.g.,
multiple roles at same company), penalties are now applied only once
per unique company, not per employment entry.
- Unverified company: -10 pts once per company (not per role)
- Company flags (incorporation date, etc.): once per (company, flag type)
Description now shows "(X roles)" when multiple instances exist.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
For company names like "UNILEVER BESTFOOD", now also tries searching
for just the first word ("UNILEVER") as it may be the registered
parent company name. Adds PLC/Limited variations for major corps.
Skips common prefixes like "The", "UK", "British", etc.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Ensures fresh API lookups each time the app starts, avoiding stale
cached results that may have been stored before matching improvements.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Company Matching:
- Extract parent company from "Brand (Parent Company)" format
- Handle slash-separated names like "ASDA/WALMART"
- Match against both original name and search query for flexibility
- Add PLC/Plc case variations
Report UI:
- Remove separate Score Breakdown section
- Add Points column to Employment Verification table
- Calculate points per company from matching flags
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The previous search only tried a single query which often returned newer
companies with similar names. Now generates all combinations of name
variations (UK/U.K. + Ltd/Limited) to find the correct company.
For "Mattel UK Ltd", now searches:
- Mattel UK Ltd
- Mattel U.K. Ltd
- Mattel UK Limited
- Mattel U.K. Limited (finds MATTEL U.K. LIMITED from 1980)
- Plus core name variations
This ensures companies like "MATTEL U.K. LIMITED" (incorporated 1980)
are found instead of incorrectly matching "UK MATTEL LTD" (2025).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When searching Companies House, now generates multiple query variations
to find companies registered with different naming conventions (e.g.,
"U.K." vs "UK", "Limited" vs "Ltd"). This helps match older companies
like "MATTEL U.K. LIMITED" when CVs list "Mattel UK Ltd".
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When no company in search results existed at the claimed employment
start date, return no match instead of falling back to wrong company.
This prevents matching "UK MATTEL LTD" (2025) when the CV claims
employment in 2006-2013 and the real "MATTEL U.K. LIMITED" (1980)
isn't in the search results.
Result: Company shows as "Unverified" instead of wrongly verified
with multiple "Employment Before Company Existed" flags.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Cache lookup now validates company existed at claimed start date
- If cached company was incorporated after employment date, search for alternatives
- Fixes matching wrong company when cached data points to newer company
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
File upload fix:
- Buffer file data immediately on selection to prevent stale IBrowserFile references
- Add BufferedFile record to hold file data in memory
- Add loading indicator while files are being buffered
- Fixes "Cannot read properties of null (reading '_blazorFilesById')" error
Company matching improvement:
- Prefer companies that existed at the claimed employment start date
- Fixes matching wrong company when newer company has similar name
- Example: "UK MATTEL LTD" (2025) vs "MATTEL U.K. LIMITED" (1980)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Rename "Employment Overlap" to "Concurrent Employment"
- Remove score penalty for overlaps (often legitimate: part-time, consulting, transitions)
- Change severity from Warning/Critical to Info
- Update scoring explanation to note overlaps are not penalised
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Score Breakdown section showing how score is calculated
- Convert variable-style flag names to readable titles (e.g. UnverifiedDirectorClaim -> Unverified Director Claim)
- Deduplicate flags in report display for existing reports
- Make verification notes more user-friendly
- Add "How Scoring Works" explanation panel
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add audit logging system for tracking CV uploads, processing, deletion,
report views, and PDF exports for billing/reference purposes
- Add processing stage display on dashboard instead of generic "Processing"
- Add delete button for CV checks on dashboard
- Fix duplicate primary key error in CompanyCache (race condition)
- Fix DbContext concurrency in Dashboard (concurrent delete/load operations)
- Fix ProcessCVCheckJob to handle deleted records gracefully
- Fix duplicate flags in verification report by deduplicating on Title+Description
- Remove internal cache notes from verification results
- Add EF migrations for ProcessingStage and AuditLog table
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add dashboard auto-refresh polling to update when processing completes
- Skip verification for freelance employers (but not contractors)
- Add incorporation date check (flags employment before company existed)
- Add dissolution date check (flags employment at dissolved companies)
- Add dormant company check (flags non-director roles at dormant companies)
- Add company size vs role check (flags senior roles at micro-entities)
- Add SIC code mismatch check (flags tech roles at non-tech companies)
- Add director verification against Companies House officers
- Add rapid career progression detection (3+ seniority jumps in <2 years)
- Add early career senior role detection (<2 years after education)
- Extend CompanyVerificationResult with flags and company data
- Add officers endpoint to Companies House client
- Fix null reference warning in Report.razor
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add QuestPDF library for professional PDF generation
- Create PdfReportService with formatted table layout
- Export includes score (color-coded), verified employers, gaps, and flags
- Report has header, footer with page numbers, and alternating row colors
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Allow recruiters to upload multiple CVs at once with batch processing
- Add auto-refresh polling on Report page during CV processing
- Add CSV export button on Dashboard for completed check summaries
- Update logo and reset to Bootstrap default styling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add logo to navbar, home hero, login and register pages
- Update color scheme to match logo blue (#2B5F9E)
- Add CSS variables for consistent brand colors
- Improve card hover transitions with shadow effects
- Add responsive content padding
- Add focus-visible states for accessibility
- Add active state styling for navigation links
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>