Generalizes the COMPANY-only 3-step wizard into RoleWizard, a component
driven entirely by the role's active onboarding_configs schema (fetched
via fetchOnboardingSchemaForRole) rather than hardcoded field/step
lists. Which roles get the wizard, and when, is now a runtime toggle
(enableWizardFlow) set through the new admin schema editor:
- ProfilePage shows the wizard while unverified/sent-back-for-fixes,
falls back to the existing free-form tabs once approved, and greys
out (both client- and server-side) any field the schema marks
lockAfterApproval once approved — previously isLocked() only covered
the in-review window and unlocked everything again at APPROVED.
- dashboard.tsx hides My Profile/My Portfolio from the sidebar
pre-approval only for roles that have the wizard enabled (roles not
yet rolled out keep direct access, so they aren't left with no way to
complete their profile), and shows a checkmark on the Verification
nav item once approved.
Rolling out to more roles is now purely an admin-panel config change —
no further code needed, since RoleWizard has no role-specific branches.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The disabled-button hint just said "Complete all required fields to
submit" with no indication of which section was incomplete. For job
seekers, portfolio completion (headline, summary, education, work
experience, skills — filled in via My Portfolio, a separate page from
this one) is required alongside Basic Info and Documents, so seeing
both visible tabs fully checked while submit stays disabled looked
like a bug. Now names the actual missing items.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Two issues in the job seeker (and shared profile) dashboard:
- The uploaded document's full Backblaze URL was rendered as visible text
and linked directly; view-document now resolves a short-lived signed
URL on demand instead of exposing the permanent storage link.
- "Submit for Verification" always showed a generic "Network error"
message on any failure because request() throws on non-2xx responses,
making the destructured status/data unreachable in the catch-free path
(e.g. a 409 "verification already in progress" looked identical to a
network failure). Now surfaces the real backend error message.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The backend emails a plain 6-digit reset code (crates/email/templates/
password-reset.html just renders {{reset_code}}, no link) and expects
POST /api/auth/reset-password with {code, new_password}. This page was
built for a different, unused link-based flow instead: it only read a
`token` from the URL query string and posted it as `token`, a field
name the backend's ResetPasswordPayload doesn't even have. Users had
no way to type the code in at all, so submitting a request just left
them stuck back on the request screen.
Now: requesting a reset code moves straight to a "set new password"
step with a 6-digit code input, and the code is submitted under the
correct `code` field name.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The captcha on login and all four signup forms was generated and
checked entirely in the browser (answer readable via window global),
so it provided no real bot/brute-force protection. Wire up the new
server-side captcha endpoint instead: fetch a challenge on mount,
submit captcha_id + captcha_answer with login/register, and refresh
the challenge on CAPTCHA_FAILED.
Also bump patchable dependency vulnerabilities via npm audit fix
(all criticals resolved; remainder needs an upstream SolidStart/vinxi
bump not yet available).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The dashboard's Submit for Verification widget checked profile_data for
a documents/documents_data field that GET /api/jobseeker/profile/me never
returns, so the Submit button stayed permanently disabled. Even bypassing
that, it POSTed {document_urls: []}, a field the backend doesn't
recognize, instead of the profile_data shape submit-for-verification
actually expects.
Now fetches the job seeker's real uploaded documents via
GET /api/jobseeker/profile/documents, checks the correct document_type
field, and submits profile_data merged with the uploaded document URLs.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
An entire route/component cluster was built on a legacy sibling of
DashboardShell (DashboardLayout.tsx) and called APIs via the bare
api.get/post/patch/delete helper, which never prefixes /api/ — so
every call 404s against the real ingress (which only routes /api/*
to the backend). Confirmed orphaned: nothing in the live dashboard
shell (DashboardShell.tsx / dashboard.tsx) links to any of it; the
only cross-references are within the cluster itself. Some of it also
targeted the apps/leads backend service removed in the companion
backend commit.
Removed:
- src/routes/dashboard/wallet/ (buy.tsx, payu-return.tsx, invoices/*)
- src/routes/dashboard/requests.tsx
- src/routes/dashboard/leads/accepted/*
- src/routes/dashboard/marketplace/*
- src/components/dashboard/AcceptedLeadsView.tsx
- src/components/DashboardLayout.tsx (only consumer was the above)
- the unused `api` object in src/lib/api.ts (the unprefixed-path
footgun itself — `request()`, which it wrapped, stays; it's used
correctly elsewhere with explicit /api/ paths)
Fixed rather than deleted: src/components/NotificationBell.tsx uses
the same broken convention but IS live (rendered on every dashboard
page via DashboardShell). Switched it to apiFetch with correct
/api/me/notifications/* paths, matching the routes that actually exist
in apps/users/src/handlers/notifications.rs.
`tsc --noEmit` shows no errors under src/ after these changes (pre-
existing node_modules/type-declaration noise unrelated to this change
remains, as it did before).
Replaces raw/truncated UUID labels with the backend's new reference_number
field across verification, application, and lead request views. Verification
status page now renders actual uploaded documents (previously invisible
after submission since the API never returned them).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
All dashboard pages and widgets had one of three bugs:
- const API = "/api" combined with paths already starting /api → double prefix
- const API = '/api/gateway' → nonexistent gateway path prefix
- cleanPath stripping /api off paths when API was set to ""
Fix: set const API = "" uniformly and remove cleanPath rewrite in all 30+
affected files (CompanyJobsPage, CompanyApplicationsPage, CreditsPage,
JobSeekerJobsPage, CustomerRequirementsPage, all widgets, etc.).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
AiChatWidget.tsx's local API constant was still "/api/gateway", a path
that only exists via the dev-only vite proxy and has no equivalent in
production (the gateway's resolve_upstream() has no "/api/gateway"
prefix). The usage-summary fetch had been patched to add auth headers
but this constant was left broken, and the two chat-send calls
(/chat/ask, /chat/message - the widget's core send-message path) were
untouched and doubly broken (wrong prefix plus a duplicated "/api").
Every send would 404 in production. Changed API to "/api" and dropped
the duplicated segment from both chat-send calls.
Also corrected a comment in CompanyJobsPage.tsx that incorrectly
described its own local API constant as "/api/gateway" (it's "/api");
no behavior change there, that fetch was already correct.
help-center.ts's uncommitted change (adding an "/api/gateway" prefix to
already-correct direct "/api/kb" calls) was reverted separately since it
introduced the same class of bug rather than fixing anything - it now
matches HEAD with no diff.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The K8s ingress for this domain routes any /api/* path directly to the
Rust gateway service — there is no rewrite/proxy layer in production that
collapses /api/gateway/* down to /api/*. That rewrite only exists as a
dev-only vite proxy, so lib/api.ts's request()/apiFetch() (used by Save
Changes, Submit for Verification, document upload, wallet, jobs,
marketplace, portfolio, and more) were 404ing on every call in production
with "Route not found in gateway". ProfilePage.tsx and
VerificationStatusPage.tsx each had their own local apiFetch with the same
assumption, doubly broken (paths already included /api/, prefixed again).
All three now hit the already-fully-qualified /api/... path directly,
matching how the working signup/login calls have always done it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The register() request body sent both profession and role_key with the
same value. The backend's registration DTO aliases role_key onto the same
field as profession, so serde_json rejected the payload outright with a
"duplicate field" deserialization error — professional signup was
returning 422 for every role in production.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Uploaded document URLs lived only in a client-side signal and were never
included in the Save or Submit-for-Verification payloads (the latter sent
a document_urls field the backend silently ignored), so every submitted
verification case ended up with no attached documents for every role
except COMPANY. Now merges doc URLs into profile_data on save/submit and
repopulates them from the saved profile on reload.
Also adds the missing DOC_FIELDS entries for Developer, Video Editor,
Graphic Designer, Social Media Manager, and UGC Content Creator, and makes
the verification-status Documents tab role-aware instead of showing 3
hardcoded generic labels.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- DashboardLayout sidebar: Leads/Credits/Settings/Logout pointed to
routes with no matching file (404). Leads now routes to the real
accepted-leads page; Credits/Settings/Logout reuse the working
/dashboard?nav= deep-link into the main dashboard's tab switcher
(fixes Logout leaving users authenticated on a 404).
- wallet/buy.tsx, wallet/payu-return.tsx: post-purchase, cancel, and
payment-verification redirects targeted non-existent /dashboard/wallet;
now redirect to the existing credits/wallet tab.
- leads/accepted.tsx already contained a detail view gated on
useParams().id, but was only registered as a flat route with no :id
segment, so the detail view was dead code. Split into
leads/accepted/index.tsx + leads/accepted/[id].tsx backed by a shared
AcceptedLeadsView component.
- Added marketplace/[id].tsx: "View Requirement" buttons navigated to
a route that never existed.
- Changed all buttons with orange background (#fd6116) and white text
to navy blue background (#050026) with white text
- Maintains 12.5:1 contrast ratio (exceeds WCAG AA 4.5:1 requirement)
- Keeps brand orange (#fd6116) for decorative elements and accents
- Preserves all hover states and transitions
Fixes accessibility violations for chip buttons, nav buttons, auth buttons,
submit buttons, and primary action buttons.
- Change background from dark #07051a to light #F4F2EC
- Update dashboard background to white #ffffff
- Update text color to #0F1729 (dark navy)
- Add light theme CSS variables
- Keep brand orange #fd6116
- Keep original brand orange #fd6116 for buttons
- Use brand navy #050026 as text color on orange background
- Ensures WCAG AA compliance (6.67:1 contrast ratio)
- Maintains brand consistency
- Fix Storybook path alias resolution for ~ imports
- Fix Playwright runtime error by using production build
- Fix accessibility color contrast issues (WCAG AA compliant)
- Fix test route from /jobs to /professionals
- Update chip-btn.active and .btn.primary colors to #a33500
- Add AiCreditsAdmin component for managing AI credits
- View user balance with detailed credit breakdown
- Transaction history (ledger) viewer with pagination
- Manual credit adjustment (ADD/DEDUCT) with audit reasons
- Reconcile tab for generating reports
- Integrate with backend /admin/ai-credits endpoints
Three related bugs made signup pages appear blank/'Not found':
1. /signup/index.tsx redirected to /signup/job-seeker (hyphen) but the
actual file was signup/jobseeker.tsx (no hyphen). Result: every
/signup visit (no intent) 404'd.
2. signup/company.tsx had the same broken link in the 'Register as
Job Seeker instead' link.
3. Landing page CTAs link to /signup?intent=professional&role=DEVELOPER
which the index correctly redirects to /signup/professional - but
/signup/developer, /signup/photographer etc. were 404 because there
were no route files for them. Added signup/[role].tsx catch-all
that maps all professional role slugs (developer, photographer,
tutor, makeup-artist, video-editor, graphic-designer,
social-media-manager, fitness-trainer, catering-services,
ugc-content-creator) to /signup/professional?role=<ROLE>.
Verified via Playwright: all role-specific signup paths now load the
full signup form instead of 'Not found'.
- Update homepage CTAs to point to new signup URLs
- Fix company signup to not validate lastName
- Add customer signup page
- Fix professionals page CTA
- /signup/company - dedicated company registration page
- /signup/job-seeker - dedicated job seeker registration page
- /signup/professional - dedicated professional registration page
- /signup - redirects to appropriate role-specific page
- Removed tabs, each role has its own clean registration flow
Fixes role assignment issues by having dedicated pages per role type.
- Hide role selector tabs when intent is provided via URL
- Show role badge for professional/customer roles
- Add profession field to API call for backend role assignment
- Fixes issue where roles weren't properly assigned after signup
This form (card number/expiry/CVV/name) was never wired to anything -
PayU collects card details on its own hosted page. Now that AI credit
purchases actually open a real PayU checkout instead of faking a
payment_id/signature, this leftover UI was just misleading.
- NotificationsPage: full paginated notification list with unread filter, mark read, load more
- SettingsPage: AI auto-apply section for job seekers (toggle, preferences, skills/titles/locations, salary range)
- CustomerResponsesPage: enriched professional response cards with avatar, bio, skills, location
- CompanyJobsPage: show rejection reason banner and pending-approval notice on job cards
- NotificationBell: fix "View all" link to /dashboard?nav=notifications (deep-link support)
- dashboard.tsx: ?nav= param reads sidebar page on mount; Notifications added to all role sidebars
- PayU integration: payu.ts lib, payu-return route, wallet buy/invoice pages, marketplace route
- Razorpay removed, replaced by PayU across payments flow
- ProfilePage: photo upload UI with avatar preview for all roles
- PortfolioPage: showcase image upload with file picker and preview
- CompanyApplicationsPage: applicant profile snapshot with avatar, headline, skills, resume download
- profile-fields-config: removed resume_doc from job seeker (resume is now AI-generated)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add AiUsageWidget showing:
- Current plan
- Monthly usage vs limit
- Daily usage vs limit
- Addon balance
- Renewal date
- Widget added to all role dashboards
- Add AI cover letter generation button on JobSeekerJobsPage
- Generate cover letters via /api/ai/generate-cover-letter
- Show generated cover letter preview before applying
- Update AI Chat Widget quick actions to focus on support & KB search
- Update welcome message to explain Ask Ash capabilities
- Fixed canvas dimensions to 176x52 pixels (no DPR scaling)
- All drawing operations now use fixed pixel values
- Prevents captcha from appearing zoomed in on high-DPI displays
- Characters, lines, and circles are now properly positioned within bounds
Vinxi 0.5.7 + @solidjs/start 1.3.2 has a build bug where file-based API
routes (src/routes/api/*) are registered in the page router tree but never
mounted as Nitro handlers in the production build, so every /api/* request
returns a framework 404.
Fix: register a SolidStart middleware (src/middleware.ts) via the
middleware config field. The middleware intercepts all /api/* paths and
proxies them to the Rust gateway, bypassing the broken page router.
Covers:
- /api/gateway/* (catch-all proxy to gateway)
- /api/kb/categories
- /api/kb/articles
- /api/kb/articles/:slug
Also tightens the dev-server vite proxy from /api to /api/kb so it
doesn't shadow the new middleware in dev.
Removes the dead src/routes/api/ tree (no longer used).