Skip to main content

Job Seeker Pages

The app/jobseeker/ route group contains all job seeker-facing pages. These are accessible when selectedCompanyId is null (job seeker mode).

Route Sections

Dashboard (/jobseeker/dashboard)

The main job seeker dashboard with 13 cards:

CardData
KPICardsKey performance indicators
MonthlyStatsMonthly activity statistics
TrendChartsApplication trend visualization
ProfileCompletionProfile completion % tracker
ProfileProgressCardProgress toward profile goals
QualityMetricsProfile quality score
RecommendedJobs / RecommendedGridAI-recommended jobs
UpcomingDeadlinesApplication deadline tracker
JobseekerSummaryProfile summary card
SnapshotProfile overview snapshot
GroupsSectionGroups/communities

Compact variant: JobSeekerDashboardSlim.

Applications (/jobseeker/application)

Track submitted job applications, their status, and responses.

Connections (/jobseeker/connections/)

RoutePurpose
collaboratingpartner/Collaborating partner management
contacts/Personal contact directory

Credits (/jobseeker/credits)

Personal credit balance and purchase history.

Interviews (/jobseeker/interviews)

Interview schedule and details. Dynamic route [interviewId] for individual interview details with meeting link.

Jobs (/jobseeker/jobs)

Browse job listings. Dynamic route [jobId] for job details and application submission.

Messages (/jobseeker/messages)

Messaging inbox. Dynamic route [conversationId] for conversation threads.

Pricing (/jobseeker/pricing)

Subscription plan selection and comparison.

Resume (/jobseeker/resume/)

CV/resume management:

RoutePurpose
create/Build a new resume from scratch or upload
edit/[cvId]/Edit an existing resume

See CV Processing for the underlying extraction and builder features.

Search Job (/jobseeker/searchjob)

Advanced job search with filters (location, skills, salary, job type, work site).

Welcome (/jobseeker/welcome)

Onboarding welcome page for new job seeker accounts.

Onboarding Flow (/onboarding/jobseeker)

The job-seeker onboarding flow lives under app/onboarding/jobseeker/ and is a multi-step form that populates the user's profile, CV, and CvJobPreference row before landing them on the dashboard. The final SummaryStep calls updateUser({ isOnboarding: true }) and seeds a default AI agent via createDefaultAgent — this is where the "Job Search Assistant" (type: JOB_MATCHING) gets created for the user. See AI Agent — default-agent auto-create.

Preferences Step — salary sanity check

app/onboarding/jobseeker/steps/PreferencesStep.tsx collects the user's job preferences including expectedSalary, salaryCurrency (default SEK), and salaryFrequency (default MONTHLY). The default-MONTHLY is a footgun for users in EUR/USD/GBP/CHF markets who routinely enter a yearly figure without thinking to change the frequency — a user typing 150000 and leaving the defaults would silently persist €150,000 per month (€1.8M/year) into CvJobPreference.

The step guards against this with a three-part sanity check. The guard fires when all of these hold:

  • rateType === "MONTHLY"
  • salaryCurrency is one of EUR, USD, GBP, CHF (high-value currencies where 50k/month is implausible — SEK/NOK/DKK are excluded because 50k/month is a plausible Scandinavian senior salary)
  • expectedSalary >= 50,000

When triggered:

  1. Inline warning panel appears below the SalaryFrequencyField with the computed yearly amount ("${currency} X per month is ${currency} X×12 per year") and a "Switch to Yearly" button that flips rateType to YEARLY in one click.
  2. First Continue press is blocked by a warning TWToast reminding the user of the implied yearly amount and pointing them at the Switch to Yearly button. An acknowledgement flag is set on the component state.
  3. Second Continue press proceeds — the user has been warned and has chosen to save the monthly figure as-is.
  4. Editing any salary / currency / frequency field resets the acknowledgement flag so a fresh bad value re-triggers the guard instead of sliding through on the existing ack.
Root cause

This is the guard for the expectedSalary: 150000, salaryFrequency: MONTHLY data-quality bug seen on real onboarding records. The CV LLM extractor never touches salary fields — they're populated only here, by this form. Without the guard, any high-value-currency user who left the MONTHLY default would silently ship a bogus yearly-as-monthly figure into their CvJobPreference.