Commit Graph

42 Commits

Author SHA1 Message Date
c9ed3119cc Use more saturated red for score ring to avoid orange appearance on blue 2026-01-21 00:05:14 +01:00
911e3f99bb Make all score ring colours more visible against blue background 2026-01-21 00:04:33 +01:00
80ba03c627 Make red score ring more visible against blue background 2026-01-21 00:03:42 +01:00
150cb268bd Colour score ring background based on score level
- 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>
2026-01-21 00:02:06 +01:00
a15be6423a Improve score roundel CSS and fix rotation
- 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>
2026-01-20 23:59:13 +01:00
f840b9a55d Hide score ring progress when score is zero
Prevents red dot from appearing at top of ring when score is 0.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 23:56:52 +01:00
0e71097bbc Replace coloured score header with neutral blue and score roundel
- 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>
2026-01-20 23:45:30 +01:00
b3d45c12d1 Skip unverified institution flag for unknown institutions
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>
2026-01-20 23:42:10 +01:00
894b539002 Replace score labels with TrueCV Score branding
- 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>
2026-01-20 23:38:54 +01:00
5bfefdfd1d Enhance UI design and update to UK English
- 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>
2026-01-20 23:35:36 +01:00
14ee569617 Skip verification note for unknown institutions
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>
2026-01-20 23:14:52 +01:00
8106b86bcd Remove points display from informational flags
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>
2026-01-20 23:10:28 +01:00
c07254f93a Remove SIC code mismatch check from company verification
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>
2026-01-20 23:07:36 +01:00
1aeaba7fbb Add comprehensive informational flags for recruiters
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>
2026-01-20 23:02:58 +01:00
f711c9725e Add frequent job changes detection (informational flag)
- 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>
2026-01-20 23:00:07 +01:00
a6b24d2c64 Change report download from JSON to PDF
- 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>
2026-01-20 22:49:22 +01:00
1a53431757 Prefer main trading companies over subsidiaries in company matching
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>
2026-01-20 22:41:27 +01:00
55c0aebdaa Improve company verification filtering and fix duplicate points display
- 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>
2026-01-20 22:33:16 +01:00
4bd7f1cef1 Fix incorrect company matching with stricter validation
- 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>
2026-01-20 22:13:23 +01:00
be2f738e58 Deduplicate penalties for same company appearing multiple times
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>
2026-01-20 22:07:23 +01:00
7f4c2362f0 Add first-word parent company extraction
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>
2026-01-20 22:04:44 +01:00
02147d1221 Clear company cache on startup
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>
2026-01-20 21:57:53 +01:00
5d2ec4b98e Improve company matching and move points to employment table
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>
2026-01-20 21:49:26 +01:00
f4890b3049 Fix company name variation search to find older companies
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>
2026-01-20 21:39:22 +01:00
58c0e79a85 Add alternative search queries for company name variations
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>
2026-01-20 21:32:02 +01:00
12da40496e Don't match wrong company when no temporal match exists
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>
2026-01-20 21:26:36 +01:00
04557dd8c4 Add debug logging to company matching for diagnosis 2026-01-20 21:21:21 +01:00
7bb68b2567 Fix cache bypassing temporal company matching
- 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>
2026-01-20 21:17:11 +01:00
67a98405af Fix file upload stale reference and improve company matching
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>
2026-01-20 21:14:01 +01:00
3c8ee0a529 Change employment overlaps to informational only
- 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>
2026-01-20 21:06:06 +01:00
21c73ab1e2 Improve report readability and add score breakdown
- 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>
2026-01-20 21:04:30 +01:00
0eee5473e4 Add audit logging, processing stages, delete functionality, and bug fixes
- 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>
2026-01-20 20:58:12 +01:00
652aa2e612 Add comprehensive CV verification checks and dashboard auto-refresh
- 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>
2026-01-20 20:00:24 +01:00
acf4d96fae Replace CSV export with PDF report generation
- 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>
2026-01-20 19:28:22 +01:00
7d6d5f12ea Add multi-file upload, auto-refresh reports, and CSV export
- 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>
2026-01-20 19:15:33 +01:00
4de233f56d Add TrueCV logo and update site branding
- 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>
2026-01-20 17:19:06 +01:00
04a7c3628a Fix DbContext concurrency error in parallel company verification
Use IDbContextFactory pattern to create isolated DbContext instances
for each cache operation, making parallel verification thread-safe.

Changes:
- Add IDbContextFactory<ApplicationDbContext> registration
- Update CompanyVerifierService to use factory for cache operations
- Update tests with InMemoryDatabaseRoot for shared test data

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 16:54:58 +01:00
f1ccd217d8 Add UK education verification and security fixes
Features:
- Add UK institution recognition (170+ universities)
- Add diploma mill detection (100+ blacklisted institutions)
- Add education verification service with date plausibility checks
- Add local file storage option (no Azure required)
- Add default admin user seeding on startup
- Enhance Serilog logging with file output

Security fixes:
- Fix path traversal vulnerability in LocalFileStorageService
- Fix open redirect in login endpoint (use LocalRedirect)
- Fix password validation message (12 chars, not 6)
- Fix login to use HTTP POST endpoint (avoid Blazor cookie issues)

Code improvements:
- Add CancellationToken propagation to CV parser
- Add shared helpers (JsonDefaults, DateHelpers, ScoreThresholds)
- Add IUserContextService for user ID extraction
- Parallelized company verification in ProcessCVCheckJob
- Add 28 unit tests for education verification

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 16:45:43 +01:00
c6d52a38b2 Add Docker support
Docker configuration:
- Dockerfile: Multi-stage build with non-root user, health checks
- Dockerfile.migrations: Runs EF Core migrations on startup
- docker-compose.yml: Full stack with SQL Server, Azurite, app
- .dockerignore: Optimized build context
- .env.example: Template for API keys

Application changes:
- Added /health endpoint with EF Core database check
- Conditional HTTPS redirect (disabled in containers)
- DOTNET_RUNNING_IN_CONTAINER environment detection

Usage:
  cp .env.example .env  # Add your API keys
  docker-compose up -d  # Start all services

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 12:37:00 +01:00
89d1f7e33b Add comprehensive unit test suite
Test project with 143 tests covering:
- TimelineAnalyserService (27 tests): gap/overlap detection, edge cases
- CVParserService (35 tests): file parsing, extension handling, API calls
- CompanyVerifierService (23 tests): verification, caching, fuzzy matching
- CVCheckService (24 tests): CRUD operations, file upload, job queuing
- ProcessCVCheckJob (34 tests): full workflow, scoring algorithm, flags

Uses xUnit, Moq, FluentAssertions, EF Core InMemory

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 19:45:07 +01:00
e9c5be3954 Add EF Core initial migration
Creates database schema for:
- ASP.NET Core Identity (users, roles, claims, tokens)
- ApplicationUser with Plan, StripeCustomerId, ChecksUsedThisMonth
- CVChecks with status tracking and indexes
- CVFlags for verification flags
- CompanyCache for Companies House API caching

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 19:29:37 +01:00
6d514e01b2 Initial commit: TrueCV CV verification platform
Clean architecture solution with:
- Domain: Entities (User, CVCheck, CVFlag, CompanyCache) and Enums
- Application: Service interfaces, DTOs, and models
- Infrastructure: EF Core, Identity, Hangfire, external API clients, services
- Web: Blazor Server UI with pages and components

Features:
- CV upload and parsing (PDF/DOCX) using Claude API
- Employment verification against Companies House API
- Timeline analysis for gaps and overlaps
- Veracity scoring algorithm
- Background job processing with Hangfire
- Azure Blob Storage for file storage

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 19:20:50 +01:00