Frontend Critical Fixes — 2026-03-04
Audit date: March 4, 2026 Scope: Critical severity issues from the frontend audit covering GraphQL schema alignment, auth bugs, and broken features. Total fixes: 9 critical issues resolved
C1. SUBSCRIPTION_FIELDS fragment — wrong GraphQL type
File: graphql/operations/schema/payment/fragments.ts
Severity: Critical — all payment/subscription queries returned empty data
Problem:
The SubscriptionFields fragment targeted Subscription (the reserved GraphQL root type for WebSocket subscriptions) instead of BillingSubscription (the actual backend type). The fragment never matched, so all payment queries using it silently received empty subscription data. Additionally, the fragment queried userId which is deprecated on BillingSubscription.
Fix:
- Changed fragment target from
on Subscriptiontoon BillingSubscription - Replaced deprecated
userIdfield withcompanyId
C2. UPDATE_USER_THEME — missing required argument + wrong field name
Files:
graphql/operations/user/mutations.tscontexts/ThemeContext.tsxlib/types/user.ts
Severity: Critical — theme saving completely broken
Problem: Three separate issues:
- Missing required
$id: ID!argument — backend signature isupdateUser(id: ID!, input: UpdateUserInput!) - Mutation returned
themeIdwhich doesn't exist onUsertype (correct field:theme) UpdateUserInputacceptstheme: String, notthemeId
The ThemeContext read user?.themeId (non-existent field) and sent { themeId: newThemeId } (wrong input key).
Fix:
- Added
$id: ID!argument to mutation and passuser.id - Changed return field from
themeIdtotheme - Updated
ThemeContextto readuser?.themeand send{ theme: newThemeId } - Updated
UserTypeScript interface:themeId→theme
C3. UPDATE_TEAM_MEMBER — invalid GraphQL syntax
File: graphql/operations/user/mutations.ts
Severity: Critical — GraphQL validation error at runtime
Problem: The mutation mixed TypeScript type annotations into a GraphQL document:
inviteToCompany(input: $input) {
email: string # NOT valid GraphQL
companyId: string # NOT valid GraphQL
}
Additionally, the input type inviteUserToCompanyInput (lowercase) didn't match the backend type InviteToCompanyInput.
Fix:
- Rewrote with valid GraphQL returning
successandmessage(matches backendSuccessResponse!) - Fixed input type to
InviteToCompanyInput - Fixed operation name casing to
InviteUserToCompany
C4. addTalentToPool — mutation does not exist in backend
File: graphql/operations/talents/mutations.ts
Severity: Critical — runtime GraphQL error if called
Problem:
The addTalentToPool mutation does not exist in the backend schema. Talent pool membership is managed via the Talent entity (createTalentInput.talentPoolId). The mutation was completely unused in the codebase.
Fix:
- Removed the entire
ADD_TALENT_TO_POOLmutation definition (lines 47-79) - Updated
SYSTEM_ARCHITECTURE.mdto remove references
C5. createCandidateWithProfile — mutation does not exist in backend
File: graphql/operations/candidate/mutations.ts
Severity: Critical — runtime GraphQL error if called
Problem:
The mutation createCandidateWithProfile, its input type CreateCandidateWithProfileInput, and its return fields (resumeUrl, experiences, certificates, etc.) do not exist in the backend schema. This was a planned feature that was never implemented. The mutation was completely unused in the codebase.
Fix:
- Removed the entire
CREATE_CANDIDATE_WITH_PROFILEmutation definition (lines 62-119) - Updated
SYSTEM_ARCHITECTURE.mdto remove references
C6. parseCv — mutation does not exist in backend
Files:
graphql/operations/cv/mutations.tslib/hooks/useCvManager.tslib/hooks/useCvUploadAndParse.ts
Severity: Critical — runtime GraphQL error if called
Problem:
The backend has no parseCv mutation. CV parsing is handled by the background-tasks service via the cvExtraction GraphQL subscription. The PARSE_CV mutation was only referenced by two hooks (useCvManager, useCvUploadAndParse).
Fix (Reverted 2026-03-04):
PARSE_CVmutation,useCvManager.ts, anduseCvUploadAndParse.tshave been restored — they are needed for the CV upload and parse flow- These hooks are marked as deprecated in docs; new code should prefer
useCvProcessor - Updated
DOCS/CV_REFACTORING_SUMMARY.mdandDOCS/CV_UNIFIED_WEBSOCKET_SERVICE.md— status set to "deprecated"
C7. TalentSource = INTERNAL — enum value does not exist
File: graphql/operations/talents/mutations.ts (line 51)
Severity: Critical — GraphQL validation error
Problem:
The default value TalentSource = INTERNAL used in the ADD_TALENT_TO_POOL mutation does not exist in the backend TalentSource enum. Valid values include: MANUAL_ENTRY, INTERNAL_TRANSFER, CV_UPLOAD, LINKEDIN_IMPORT, etc.
Fix:
- Resolved automatically by removing the
ADD_TALENT_TO_POOLmutation in C4 (the only location using this invalid enum value)
C8. Jobseeker contacts page — entirely mock data
Files:
app/jobseeker/connections/contacts/page.tsx(rewritten)app/jobseeker/connections/_mockData.ts(deleted)
Severity: Critical — production page shows static fake data
Problem:
The entire jobseeker contacts page was populated from MOCK_CONTACTS hardcoded data. All CRUD operations had TODO comments and only called console.log. In production, job seekers saw static fake data that couldn't be interacted with. The backend has no jobseeker-specific contacts query (contacts are company-scoped).
Fix:
- Replaced the 478-line mock page with a clean "Coming Soon" placeholder
- Deleted the
_mockData.tsfile containingMOCK_CONTACTSandMockContacttype - Page now shows a clear message that the feature is under development
C9. Stale closure — session idle timer never calls logout
File: contexts/UserAuthProvider.tsx
Severity: Critical — auto-logout after inactivity silently fails
Problem:
startIdleTimer and checkSessionExpiry were wrapped in useCallback(fn, []) (empty deps) but both referenced logout() which is defined later in the file. The closures captured the initial undefined value of logout, so when the timer fired, it called undefined() and crashed silently. Users were never logged out after 5 hours of inactivity.
Additionally, line 75 had a stale comment saying "3 hours" when MAX_SESSION_AGE is 5 hours.
Fix:
- Added a
logoutRef = useRef<() => void>(() => {})that always points to the currentlogoutfunction - Changed all timer callbacks to call
logoutRef.current()instead oflogout()directly logoutRef.currentis updated afterlogoutis defined, so the ref always has the correct function- Fixed stale comment from "3 hours" to "5 hours"
Files Changed Summary
| File | Action |
|---|---|
graphql/operations/schema/payment/fragments.ts | Fixed fragment type + field |
graphql/operations/user/mutations.ts | Fixed 2 mutations (C2, C3) |
graphql/operations/talents/mutations.ts | Removed dead mutation (C4/C7) |
graphql/operations/candidate/mutations.ts | Removed dead mutation (C5) |
graphql/operations/cv/mutations.ts | Removed dead mutation (C6) |
contexts/ThemeContext.tsx | Fixed theme field references + added user.id |
contexts/UserAuthProvider.tsx | Fixed stale closure with logoutRef |
lib/types/user.ts | Renamed themeId → theme |
app/jobseeker/connections/contacts/page.tsx | Replaced mock page with Coming Soon |
app/jobseeker/connections/_mockData.ts | Deleted |
lib/hooks/useCvManager.ts | Restored (deprecated) |
lib/hooks/useCvUploadAndParse.ts | Restored (deprecated) |
DOCS/CV_REFACTORING_SUMMARY.md | Updated deprecation status |
DOCS/CV_UNIFIED_WEBSOCKET_SERVICE.md | Updated deprecation status |
SYSTEM_ARCHITECTURE.md | Removed references to deleted mutations |
High Severity Fixes
H1. CREATE_PLAN — wrong argument name + non-existent return fields
File: graphql/operations/payment/mutations.ts
Fix: Changed createPlan(createPlanInput: $input) to createPlan(input: $input). Removed stripePriceId and stripeProductId (don't exist on Plan), replaced with active.
H2. REMOVE_PLAN — wrong return type
File: graphql/operations/payment/mutations.ts
Fix: Backend returns SuccessResponse!, not { id }. Changed return fields to success and message.
H3. REMOVE_CANDIDATE_NOTE — wrong return type
File: graphql/operations/candidate/mutations.ts
Fix: Backend returns SuccessResponse!, not individual note fields. Changed return to success and message.
H4. GET_USER_ROLES — wrong field names on Company
File: graphql/operations/user/queries.ts
Fix: Changed company { name, logo } to company { companyName, avatar } — the correct field names on the Company type.
H5. GET_ADMIN_AI_OPERATION_LOGS — wrong argument + return shape
File: graphql/operations/credit/queries.ts
Fix: Changed argument from filter: AIOperationLogFilterInput (optional) to input: AdminAIOperationLogsInput! (required). Changed return shape to paginated format: { items: [...], totalCount, pageInfo: { hasNextPage, hasPreviousPage } }.
H6. adminAssignSubscription — non-existent isActive field
File: graphql/operations/credit/mutations.ts
Fix: Removed isActive from return selection — BillingSubscription has no isActive field.
H7. GET_TALENT — wrong field casing + non-existent field
File: graphql/operations/talents/queries.ts
Fix: Changed TalentPool { id name } (uppercase T) to talentPool { id name } (lowercase). Removed isActive which doesn't exist on the Talent type.
H8. Duplicate AllJobs operation name
File: graphql/operations/job/queries.ts
Fix: Renamed GET_ALL_JOBS_FOR_JOBSEEKER operation from query AllJobs to query AllJobsForJobseeker to avoid cache conflicts with GET_ALL_JOBS_PUBLIC which also used AllJobs.
H9. redirectToSignin leaves stale localStorage keys
File: graphql/apollo/apolloClient.ts
Fix: Added removal of selectedCompanyId, role, and createdAt in redirectToSignin() to match the full cleanup done by logout(). Prevents next session from inheriting the previous user's company context.
H10. Plan usage queries permanently disabled
File: app/jobseeker/credits/page.tsx
Fix: Removed hardcoded skip: true from GET_AI_OPERATION_USAGE_SUMMARY and GET_PLAN_USAGE_SUMMARY queries so they actually execute.
H11. useSubscriptionStatus — status-blind active detection
Files: lib/hooks/useSubscriptionStatus.ts, graphql/operations/payment/queries.ts, lib/types/payment.ts
Fix: Added status field to GET_USER_SUBSCRIPTIONS query. Updated the subscription finder to only consider ACTIVE and TRIALING statuses as active (rejecting PENDING_APPROVAL, UNPAID, etc.). Also replaced deprecated userId with companyId in the query. Added PENDING_APPROVAL to the SubscriptionStatus type.
H12. billingMode completely absent from frontend
Files: graphql/operations/schema/payment/fragments.ts, lib/types/payment.ts
Fix: Added billingMode field to the PLAN_FIELDS fragment and billingMode?: "PREPAID" | "POSTPAID" to the Plan TypeScript interface. This allows the frontend to distinguish enterprise POSTPAID plans from regular PREPAID plans.
H13. Inconsistent authorization header casing
Files: lib/hooks/useAIAgentChat.ts, lib/hooks/useAgentDocuments.ts
Fix: Changed authorization (lowercase) to Authorization (uppercase, standard) in WebSocket connectionParams to match all other hooks in the codebase.
H14. Voice/AI WebSocket URLs default to DEV in production
Files: lib/hooks/useVoiceChat.ts, lib/hooks/useAIAgentChat.ts, lib/hooks/useAgentDocuments.ts
Fix: Changed all fallback URLs from ai-dev.aiqlick.com to ai.aiqlick.com so that if env vars are unset in production, traffic routes to the production service rather than dev.
H15. Admin user list fetches ALL users without pagination
Status: Deferred — requires backend changes. The users query doesn't accept limit/offset arguments. Filed for backend team coordination.
H16. Pipeline member ID collision on same-name users
Files: lib/utils/pipeline.ts, lib/types/jobs.ts
Fix: Changed mapJobsToMembers and mapJobsToCards to use responsibleUser.id (database UUID) instead of firstName-lastName for member ID construction. Added id?: string to the responsibleUser type on Opportunity. Falls back to name-based ID if id is unavailable.
H17. Apollo upload split misses nested File objects
File: graphql/apollo/apolloClient.ts
Fix: Replaced flat Object.values(variables).some(...) check with a recursive hasFileInVariables() helper that traverses nested objects. Now correctly detects { input: { file: someFile } } patterns.
H18. Timezone free-text input accepts invalid values
File: components/meetings/CreateMeetingModal.tsx
Fix: Replaced TWInput (free-text) with TWSelect using a curated list of IANA timezone options (UTC, US timezones, European, Asian, Australian, NZ).
High Severity — Additional Files Changed
| File | Action |
|---|---|
graphql/operations/payment/mutations.ts | Fixed CREATE_PLAN + REMOVE_PLAN (H1, H2) |
graphql/operations/candidate/mutations.ts | Fixed REMOVE_CANDIDATE_NOTE (H3) |
graphql/operations/user/queries.ts | Fixed GET_USER_ROLES company fields (H4) |
graphql/operations/credit/queries.ts | Fixed GET_ADMIN_AI_OPERATION_LOGS (H5) |
graphql/operations/credit/mutations.ts | Fixed adminAssignSubscription (H6) |
graphql/operations/talents/queries.ts | Fixed GET_TALENTS casing + field (H7) |
graphql/operations/job/queries.ts | Fixed duplicate AllJobs name (H8) |
graphql/apollo/apolloClient.ts | Fixed redirectToSignin cleanup + upload split (H9, H17) |
app/jobseeker/credits/page.tsx | Enabled usage queries (H10) |
lib/hooks/useSubscriptionStatus.ts | Fixed status-blind detection (H11) |
graphql/operations/payment/queries.ts | Added status to subscriptions query (H11) |
graphql/operations/schema/payment/fragments.ts | Added billingMode to PLAN_FIELDS (H12) |
lib/types/payment.ts | Added billingMode + PENDING_APPROVAL (H11, H12) |
lib/hooks/useAIAgentChat.ts | Fixed auth header casing + prod URL (H13, H14) |
lib/hooks/useAgentDocuments.ts | Fixed auth header casing + prod URL (H13, H14) |
lib/hooks/useVoiceChat.ts | Fixed prod URL default (H14) |
lib/utils/pipeline.ts | Fixed member ID collision (H16) |
lib/types/jobs.ts | Added id to responsibleUser type (H16) |
components/meetings/CreateMeetingModal.tsx | Replaced timezone input with select (H18) |
Medium Severity Fixes
M2. PENDING_APPROVAL missing from SubscriptionsTab UI
File: app/(shared)/userprofile/payment/components/SubscriptionsTab.tsx
Fix: Added PENDING_APPROVAL: { bg: "bg-amber-600", text: "PENDING APPROVAL" } to the statusColors map so subscriptions with this status display correctly.
M3. TalentSource type missing INVITED and SHARED values
File: lib/hooks/talents/useCompanyTalents.ts
Fix: Added "INVITED" and "SHARED" to the TalentSource union type to match backend enum.
M4. JWT token exposed in WebSocket URL query string
File: lib/hooks/useVoiceChat.ts
Fix: Added security comment. Full fix requires backend voice service to accept auth via first WS message instead of URL query string. Deferred for backend coordination.
M5. Deprecated userId still queried on BillingSubscription
File: graphql/operations/payment/queries.ts
Fix: Replaced all userId fields with companyId in GET_SUBSCRIPTION_HISTORY, GET_ACTIVE_SUBSCRIPTION, GET_USER_WITH_SUBSCRIPTIONS, and GET_SUBSCRIPTION queries. Invoice queries retain userId as it is still valid on the Invoice type.
M6. Deprecated updateCvSchema mutation
File: graphql/operations/cv/mutations.ts
Fix: Added @deprecated comment directing new code to use structured CV mutations. Mutation is still in active use by 5 components and cannot be removed yet.
M7. sendEmail checkbox not passed to mutations
File: app/company/resume/candidates/_components/modals/BookInterviewModal.tsx
Fix: Added sendEmail to the createSlotOffer mutation variables so the checkbox state is actually sent to the backend.
M8. CreateMeetingModal defaults timezone to "UTC"
File: components/meetings/CreateMeetingModal.tsx
Fix: Changed default timezone from hardcoded "UTC" to user's detected timezone via Intl.DateTimeFormat().resolvedOptions().timeZone. Also updated handleClose reset to detect timezone.
M9. BookInterviewModal hardcoded duration
File: app/company/resume/candidates/_components/modals/BookInterviewModal.tsx
Fix: Added interviewDuration state with a duration selector dropdown (15/30/45/60/90/120 minutes). Replaced hardcoded duration: 60 in both the availability query and create slot offer mutation.
M10. Reschedule allows multiple slots but only uses first
File: app/company/resume/candidates/_components/modals/BookInterviewModal.tsx
Fix: Added maxSlots variable — set to 1 in reschedule mode, 3 in normal mode. Updated slot limit in add button, validation, and display label.
M11. Calendar already disables past dates
Status: Already handled — isDatePast() check at line 553 disables past date buttons.
M12. Pipeline status change error toast
Status: Already handled — handleCandidateStatusChange in [jobId]/page.tsx has try-catch with addTWToast on failure (line 380).
M17. First poll triggers spurious notification toast
File: contexts/NotificationContext.tsx
Fix: Added isInitialLoadRef to skip toast on initial data load. The cache-and-network policy fires the effect multiple times on mount; the ref ensures the first settled value is recorded as baseline without triggering a toast.
M19. Synthetic notification hardcoded SYSTEM_UPDATE type
File: contexts/NotificationContext.tsx
Fix: Changed synthetic notification type from "SYSTEM_UPDATE" to "FEATURE_ANNOUNCEMENT" which is more appropriate for generic polling-detected notifications.
M20. Non-functional Kanban Assign/Share buttons
File: components/ux/KanbanJobCardAdapter.tsx
Fix: Replaced console.log TODO stubs with "Coming Soon" toast notifications so users get feedback instead of silent no-ops.
M21. Dead help links in sidebars
Files: components/navigation/CompanySidebar.tsx, components/navigation/JobSeekerSidebar.tsx
Fix: Changed href="#" to href="mailto:support@aiqlick.com" so the help link does something useful.
M22. Auth guard isOnboarding === false logic
File: components/auth/authGuard.tsx
Fix: Added clarifying comment. The strict === false check is intentional — it only redirects to onboarding when isOnboarding is explicitly false, allowing null/undefined to fall through to the role check.
M23. mousemove fires localStorage writes ~60 times/sec
File: contexts/UserAuthProvider.tsx
Fix: Added 5-second throttle to the activity handler using a lastActivityWriteRef. The resetIdleTimer() call (which writes to localStorage and resets the timeout) now fires at most once every 5 seconds instead of on every mouse movement.
M24-M27. Code quality cleanup
Files changed:
components/connections/SendConnectionRequestDialog.tsx— Removed 6 debug console.logsapp/onboarding/jobseeker/steps/Qualifications.tsx— Removed 5 drag debug console.logs with emojisapp/(shared)/userprofile/addCompanyPage.tsx— Removed 5 debug console.logsapp/(shared)/userprofile/hooks/useProfileForm.ts— Removed 2 debug console.logsapp/(shared)/userprofile/components/AvatarSection.tsx— Removed 1 debug console.logcomponents/ux/TWResponsiveCard/hooks/useFieldVisibility.ts— Removed 10 debug console.logsapp/(shared)/userprofile/payment/components/SubscriptionsTab.tsx— Removed 1 debug console.logapp/company/connections/collaboratingpartner/_components/CollaboratorsGrid.tsx— Replaced console.log with TODO commentapp/(shared)/userprofile/accountPage.tsx— Replaced console.log with "Coming Soon" toast- Mock flags (M27): All
USE_MOCK_*flags already set tofalse— no changes needed
Medium Severity — Files Changed Summary
| File | Action |
|---|---|
app/(shared)/userprofile/payment/components/SubscriptionsTab.tsx | Added PENDING_APPROVAL status + removed console.log (M2, M25) |
lib/hooks/talents/useCompanyTalents.ts | Added INVITED, SHARED to TalentSource (M3) |
lib/hooks/useVoiceChat.ts | Added security comment for JWT in URL (M4) |
graphql/operations/payment/queries.ts | Replaced userId with companyId in 5 queries (M5) |
graphql/operations/cv/mutations.ts | Added deprecation comment (M6) |
app/company/resume/candidates/_components/modals/BookInterviewModal.tsx | Added sendEmail, duration control, reschedule slot limit (M7, M9, M10) |
components/meetings/CreateMeetingModal.tsx | Auto-detect timezone instead of UTC default (M8) |
contexts/NotificationContext.tsx | Fixed first-poll toast + synthetic notification type (M17, M19) |
components/ux/KanbanJobCardAdapter.tsx | Coming Soon toast for Assign/Share (M20) |
components/navigation/CompanySidebar.tsx | Fixed dead help link (M21) |
components/navigation/JobSeekerSidebar.tsx | Fixed dead help link (M21) |
components/auth/authGuard.tsx | Added clarifying comment (M22) |
contexts/UserAuthProvider.tsx | Throttled mousemove activity tracking (M23) |
components/connections/SendConnectionRequestDialog.tsx | Removed debug logs (M25) |
app/onboarding/jobseeker/steps/Qualifications.tsx | Removed drag debug logs (M25) |
app/(shared)/userprofile/addCompanyPage.tsx | Removed debug logs (M25) |
app/(shared)/userprofile/hooks/useProfileForm.ts | Removed debug logs (M25) |
app/(shared)/userprofile/components/AvatarSection.tsx | Removed debug log (M25) |
components/ux/TWResponsiveCard/hooks/useFieldVisibility.ts | Removed 10 debug logs (M25) |
app/company/connections/collaboratingpartner/_components/CollaboratorsGrid.tsx | Removed debug log (M25) |
app/(shared)/userprofile/accountPage.tsx | Replaced console.log with toast (M25) |
Deferred Items
| Issue | Reason |
|---|---|
| M4 (JWT in URL) | Requires backend voice service changes |
| M6 (updateCvSchema removal) | Still in active use by 5 components |
| H15 (Admin user pagination) | Requires backend limit/offset support |
| M26 (window.confirm → modals) | 7 instances; requires designing a reusable confirm modal component |