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>
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).
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>
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>
- 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.
- 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
- 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>
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).
- Add SessionTimer component with 13min warning / 15min idle auto-logout
- Move VerificationSubmissionGuide from ProfilePage to MyDashboardPage
- Remove duplicate VerificationSubmissionGuide from ProfilePage
- Fix 'Go to My Portfolio' button to navigate properly
- Change error messages to 'Service unavailable' for failed widget loads
- Brand color updates for VerificationSubmissionGuide
- RequireAuth: use setTimeout to defer clientReady=true until after hydration completes, preventing SSR/client mismatch
- dashboard.tsx: add SSR guard to return empty div on server
- playwright tests for dashboard role verification
The loading spinner in RequireAuth caused a hydration error: on SSR the session was available so children rendered, but during client hydration session.loading was true so the spinner rendered instead, causing DOM mismatch (null nextSibling).
Also includes role resolution priority fixes from previous session:
- prefer preferredRole when backendRole is JOB_SEEKER but preferredRole is not
- pass role via URL param to dashboard
- urlRoleLocked signal prevents auth effects from overriding URL role
- login.tsx: pass role via URL param to dashboard instead of relying on localStorage
- dashboard.tsx: add urlRoleLocked signal to prevent auth effects from overriding URL-passed role
- auth.tsx: trust passed-in role over re-reading from localStorage in saveUser
- Change from /api/gateway/api/auth/resend-otp to /api/auth/resend-otp
- Fix in signup.tsx and login.tsx
- Gateway already proxies /api/auth/* to users service
All job seeker pages are already connected to real APIs:
- Jobs: /api/jobseeker/jobs (real company job postings)
- Applications: /api/jobseeker/applications (my applied jobs)
- Saved Jobs: Custom data storage for bookmarked jobs
- Apply: POST /api/jobseeker/jobs/{id}/apply
Dashboard shows real data from backend, not mock preview.
- Updated Help Center with dark hero and light content sections
- Added ArticleContent component for rendering structured content blocks
- Updated seed data with detailed articles matching admin KB categories
- Fixed article alignment and spacing issues
- Uses ContentBlock[] instead of HTML strings for type-safe content
- Update solid-markdown from ^0.5.0 to ^2.1.1 (old version no longer exists)
- Replace Markdown component with innerHTML rendering for help center articles
- Build now succeeds without errors
- DashboardShell: sticky sidebar + header wrapper with shared style tokens
- ProfilePage: 3-tab form (Basic, Documents, Settings) per role, save/submit-for-verification
- PortfolioPage: full CRUD wired to /api/:prefix/portfolio/me endpoints
- VerificationStatusPage: 7-state status display with progress timeline and resubmit flow
- dashboard.tsx: REAL_PAGES routing intercepts these three sidebar items and renders
real components instead of DashboardDesignPreview mock
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add AuthProvider context and RequireAuth route guard
- Create API client with all endpoint helpers
- Add forgot-password route wired to backend reset endpoints
- Remove dummy login button from login page
- Wire dashboard to auth context for user data
- Enhance profile save to send all fields
- Wire profile submit-for-verification to backend API
- dashboard.tsx: fetch session for real user name/ID/role, fallback to
localStorage; show dashboard with role defaults when runtime config unavailable
- DashboardDesignPreview: add liveData prop; createResource for credits,
marketplace, lead requests, customer requirements, jobs, and profile
- Profile form: inputs now track state via profileFormData signal; pre-filled
from GET /api/${prefix}/profile/me; Save Changes PATCHes real endpoint
- Lead actions: Send Request POSTs to /api/${prefix}/leads/request; Cancel
DELETEs /api/${prefix}/leads/requests/{id}; both refetch after completion
- Requirement submit: POSTs to /api/customers/requirements then submits for approval
- Replace hardcoded "Alex" with real session name; credits from wallet balance API
- Fix launch.json PATH so npm is found in sh shell
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- wallet/invoices.tsx: table of invoices with download link; uses role-specific API prefix; handles loading/empty states
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>