Skip to main content

Launch Bug Fixes — 15 Issues Resolved

· 7 min read

15 bugs identified during the launch testing session (2026-02-26) have been fixed across the aiqlick-backend and background-tasks repositories. This covers AI scoring accuracy, messaging reliability, email templates, interview scheduling, and notification delivery.

AI Scoring Fixes (background-tasks)

BUG-11: Scoring inflated — default 100% for missing requirements (CRITICAL)

Problem: When job requirements were missing (no salary, no location, no language requirement), the system assigned 100% score for those components. A candidate with only 40% skill match could score 65+ overall.

Fix: Added weight redistribution logic in score_calculator.py. Components with no real requirement data are now excluded from the weighted average entirely. Weights are proportionally redistributed among components that have actual data.

Files changed:

  • app/services/matching/unified_scoring/score_calculator.py — new _redistribute_weights_for_missing_data method

BUG-12: Skills weight too low at 40% (HIGH)

Problem: Base weight for skills was 40%. A candidate could score 60+ without any skill match from other components (experience 25%, salary 15%, location 10%).

Fix: Increased skills base weight to 55%. Reduced experience to 15%, salary to 10%, location to 8%. Updated all 10 weighting profiles (technical_role, senior_role, entry_level, etc.).

Files changed:

  • app/services/matching/unified_scoring/dynamic_weighting.py — all weight profile constants
  • app/services/matching/unified_scoring/score_calculator.py — base weight defaults

BUG-13: No-skills penalty too generous — capped at 50% (HIGH)

Problem: When a user had zero skills, penalty was capped at 50%. Someone with no technical skills could score 50+ on a technical job.

Fix: Removed the 50% cap. If a candidate has zero required skills, skill score is now 0–10% (small margin for semantic transferable skills only). Must-have skills missing caps at 8%.

Files changed:

  • app/services/matching/unified_scoring/skill_analyzer.py_calculate_no_skills_penalty method

BUG-14: Bonus system inflates scores by up to +11% (MEDIUM)

Problem: Skill diversity bonus (+5%), semantic confidence bonus (+3%), experience quality bonus (+3%) could add 11% to scores artificially.

Fix: Reduced total bonus cap to 5% max. Diversity bonus capped at 2%, semantic at 2%, experience at 1%.

Files changed:

  • app/services/matching/unified_scoring/skill_analyzer.py_apply_skill_quality_bonuses method

BUG-15: Semantic matching threshold too low (MEDIUM)

Problem: Semantic match threshold was 0.7 confidence. Partial matches at 0.5 treated as "transferable". This created false positives (e.g., "Docker" matching "Kubernetes" at 0.6+).

Fix: Raised semantic match threshold to 0.85. Transferable match threshold raised from 0.50 to 0.70. SIMILAR match transferability penalty increased from 0.8 to 0.5 multiplier.

Files changed:

  • app/services/matching/unified_scoring/skill_analyzer.py — threshold constants and match scoring

Backend Fixes (aiqlick-backend)

BUG-1: Unknown user in messaging (CRITICAL)

Problem: Users with null firstName/lastName in the database appeared as "unknown" in messaging conversations and message sender names.

Fix: Added getDisplayName helper method in messaging.service.ts that falls back to email prefix when name is null. Applied to all participant mapping and message sender resolution. Added email field to all User select queries in messaging.

Files changed:

  • src/messaging/services/messaging.service.ts — new getDisplayName helper, updated all participant/sender mappings

BUG-2: Message sync not immediate for sender (MEDIUM)

Problem: Real-time subscription filter excluded the sender (senderId !== userId). The sender's own message wasn't echoed back via WebSocket, requiring a page refresh to see it.

Fix: Removed sender exclusion filter from messageReceived subscription. Messages now publish to all conversation participants including the sender, with an isSelf: true flag so the frontend can handle deduplication.

Files changed:

  • src/messaging/resolvers/messaging.resolver.ts — subscription filter
  • src/messaging/services/messaging.service.ts — pub/sub publish to all participants
  • src/messaging/entities/message.entity.ts — added isSelf field

BUG-3: Missing messaging mutations — archive, flag, mark as unread (MEDIUM)

Problem: Backend was missing archive, flag, and mark-as-unread functionality for conversations.

Fix: Added isArchived, isFlagged, isMarkedUnread fields to ConversationParticipant model. Added three new mutations: archiveConversation, flagConversation, markConversationAsUnread. Updated markAsRead to also reset isMarkedUnread.

Files changed:

  • prisma/schema.prisma — new fields on ConversationParticipant
  • src/messaging/resolvers/messaging.resolver.ts — 3 new mutations
  • src/messaging/services/messaging.service.ts — 3 new service methods

BUG-4: Collaboration invite uses generic email template (HIGH)

Problem: company.service.ts called generic sendInvitationEmail() for team member invitations instead of a branded company invitation.

Fix: Created sendTeamMemberInvitationEmail() in mail.service.ts with proper branded template showing inviter name, company name, and role. Updated company.service.ts to use it.

Files changed:

  • src/common/mail/mail.service.ts — new sendTeamMemberInvitationEmail method
  • src/company-management/company/company.service.ts — updated to use branded template

BUG-5: Blue button with no visible text in email (MEDIUM)

Problem: Collaboration invitation email button used CSS class styling which some email clients strip, making button text invisible.

Fix: Replaced class-based styling with full inline styles directly on the anchor element: display:inline-block; padding:12px 24px; background-color:#007bff; color:#ffffff; text-decoration:none; border-radius:5px; font-weight:bold;.

Files changed:

  • src/connections/collaboration-management/services/collaboration-invitation.service.ts — inline styles on email button

BUG-6: Talent onboarding invite uses wrong email template (MEDIUM)

Problem: When a talent was invited for onboarding, they received a generic "Complete Your Account Setup" email that looked like a password reset.

Fix: Created sendTalentOnboardingEmail() in mail.service.ts with a proper welcome template showing who invited them and which company. Updated users.service.ts to route to the talent onboarding template when companyId is provided.

Files changed:

  • src/common/mail/mail.service.ts — new sendTalentOnboardingEmail method
  • src/user-management/users/users.service.ts — routing logic for company-context invitations

BUG-7: Message notification email template missing (HIGH)

Problem: No sendMessageNotificationEmail() method existed. When messaging notifications attempted EMAIL channel delivery, there was no template.

Fix: Created sendMessageNotificationEmail() in mail.service.ts with a template showing sender name, message preview (truncated at 200 chars), and link to conversation.

Files changed:

  • src/common/mail/mail.service.ts — new sendMessageNotificationEmail method

BUG-8: Notification digest frequency selector missing (MEDIUM)

Problem: Users could only toggle notification categories on/off. No per-category email frequency setting (immediately/daily/weekly/monthly) existed.

Fix: Added NotificationFrequency enum (IMMEDIATE, DAILY, WEEKLY, MONTHLY) to Prisma schema. Added per-category frequency fields to UserNotificationPreference: recruitment, collaboration, billing, matching, messaging, and system — all defaulting to IMMEDIATE.

Files changed:

  • prisma/schema.prisma — new enum and 6 frequency fields on UserNotificationPreference

BUG-9: Google Calendar busy times not implemented (CRITICAL)

Problem: getFreeBusy() method always returned an empty array. All interview slots showed as available regardless of existing bookings.

Fix: Rewrote getFreeBusy() to query the InterviewBooking table for existing bookings where the user is an attendee or interviewer (status: PENDING, CONFIRMED, or RESCHEDULED). Returns actual busy time ranges from the database. Injected PrismaService into GoogleCalendarService.

Files changed:

  • src/interview-scheduling/services/google-calendar.service.ts — database-backed busy time detection

BUG-10: Notifications not showing in bell icon (MEDIUM)

Problem: getUnreadCount with a companyId filter only counted company-scoped notifications, missing global (null companyId) notifications.

Fix: Updated getUnreadCount to include both company-specific AND global notifications when filtering by company. Enhanced logging in createNotification to trace notification creation with full context (type, category, userId, companyId, channels).

Files changed:

  • src/notification-system/services/notification.service.ts — unread count query fix and enhanced logging

Verification

All changes verified:

  • npx prisma generate — Prisma client regenerated successfully with schema changes
  • npx tsc --noEmit — TypeScript compilation passes with zero errors

Testing commands

# Backend
cd aiqlick-backend
npm run test:safe

# Background tasks
cd background-tasks
pytest -m unit -v

Manual verification checklist

  • Send message to user without firstName — verify email fallback displayed
  • Send message and verify sender sees it immediately (no page refresh)
  • Archive, flag, mark-as-unread a conversation
  • Trigger collaboration invite — verify branded email with visible button
  • Invite talent for onboarding — verify welcome email (not password reset)
  • Book interview — verify conflict with existing booking detected
  • Check notification bell shows all notifications (company + global)
  • Create job with 5 skills, match candidate with 2/5 — verify score < 40%
  • Match candidate with zero skills — verify score < 10%