Launch Bug Fixes — 15 Issues Resolved
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_datamethod
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 constantsapp/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_penaltymethod
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_bonusesmethod
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— newgetDisplayNamehelper, 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 filtersrc/messaging/services/messaging.service.ts— pub/sub publish to all participantssrc/messaging/entities/message.entity.ts— addedisSelffield
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 ConversationParticipantsrc/messaging/resolvers/messaging.resolver.ts— 3 new mutationssrc/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— newsendTeamMemberInvitationEmailmethodsrc/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— newsendTalentOnboardingEmailmethodsrc/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— newsendMessageNotificationEmailmethod
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 changesnpx 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%