Root cause of "Google authentication failed": appsettings.Development.json
had Auth:GoogleClientId set to the literal placeholder
"CHANGE_ME_GOOGLE_CLIENT_ID" while the frontend's .env.development had a
real (already-public, already-committed) client ID -- every Google ID
token's audience check failed against the backend's placeholder. Fixed
by setting the same real client ID on both sides (a client ID is a
public identifier, not a secret, safe to commit -- unlike a client
secret). Also enabled Auth:AllowRegistration in dev so the existing
Google-first self-serve-signup path (auto-create on unmatched verified
email, auto-link on matching verified email -- built during Wave 7) is
actually exercisable locally.
Wired the previously-missing Auth__MicrosoftClientId /
NEXT_PUBLIC_MICROSOFT_CLIENT_ID into docker-compose.yml/.env.example
(distinct from the existing MICROSOFT_CLIENT_ID used for Outlook mail
linking) -- Microsoft sign-in was never deployable, a leftover gap from
when it was built. Fixed a stale env-var name in the Microsoft setup
hint copy (still said REACT_APP_*, predates the Next.js migration).
Removed the per-user accent color picker entirely: it was purely
client-side (localStorage + theme.ts), never touched the backend/DB.
theme.ts now hardcodes a single ACCENT constant; themePrefs.ts drops
get/set/clearAccentColor; App.tsx and SettingsView.tsx drop the
accentColor prop threading. Dead accent-related i18n keys removed from
both locales.
Consolidated Settings' "Account" tab (duplicated GoogleAuthCard, which
already lives on the Profile page) into Profile: moved AuthStatusCard
and EmailProviderConnections there alongside the existing Google/
Microsoft auth cards, so identity/account-linking lives in one place.
Settings drops from 5 tabs to 4 and its General tab uses a consistent
SectionCard layout instead of ad-hoc per-card styling.
Verified: dotnet build/test (177/177) and npm build/test (57/57) both
green; confirmed live against a running dev server that /auth/config
now reports googleEnabled with the corrected client ID, Settings has
no accent controls, and Profile shows the consolidated auth section.
b5 of the multi-provider email roadmap (frontend). Adds EmailProviderConnections
-- one card per provider (Gmail, Outlook/Microsoft 365, generic IMAP) showing
connect status and connect/disconnect actions, mounted in SettingsView's
Account tab alongside the existing app-login GoogleAuthCard (a separate
concern: that card is sign-in identity, this is mailbox linking).
Gmail and Microsoft reuse the OAuth-popup + postMessage handshake already
built server-side (mirrors Correspondence.tsx's existing Gmail-connect flow).
IMAP has no OAuth step, so it's a plain host/port/ssl/username/password form
posting to /api/imap/connect, which verifies the connection server-side
before storing it.
Deliberately NOT touched: the Gmail-specific job-candidate-matching/review UI
in Correspondence.tsx and GmailReviewPage.tsx. That backend pipeline
(ListJobCandidateMessagesAsync, GmailReviewDecisions) is still Gmail-only by
design -- generalising it now would mean building fake UI for capabilities
Microsoft/IMAP don't have yet. This is scoped to the piece that's actually
provider-neutral: connect/disconnect status.
Verified live (backend + frontend dev servers): logged in, confirmed all
three /status calls return 200, Gmail connect-url fetch succeeds, IMAP form
submit hits /api/imap/connect and surfaces the expected 400 on a bad host.
Frontend suite: 25 suites / 57 tests green (2 new).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resolve conflicts from main's Wave 0 (PR #1) landing after this branch was cut:
- useViewResource.ts: main's e352aae already fixes the render loop the same way
(load in a ref, dropped from deps) — took main's canonical version. My
independent fix is superseded (my branch predated e352aae, which is why the
loop reproduced live).
- JobApplicationsController.cs: keep BOTH main's IJobCvMatchService and my
AnalyticsService (ctor gets both optional params). GetAnalyticsOverview stays
delegated to AnalyticsService.
- Fold main's H3 additions into the extracted AnalyticsService: pipeline-driven
funnel (JobPipeline.Normalize/Stages) + time-in-stage (StageAnalytics) and add
StageDurationDto + TimeInStage to Models/AnalyticsDtos.cs, preserving the API
contract the frontend expects.
Build clean; backend suite 135/135 green.
First UI slice toward the product mockups. Shifts the shared MUI theme to match
the mockup identity without restructuring components:
- Default accent -> indigo #6366f1 (drives primary buttons, active nav, and the
Applied/Interview status colours). Users with a custom accent keep theirs.
- Light app background -> #F4F6FB with white paper, giving the layered dashboard
look (cards/inputs sit above a soft grey canvas).
- Global corner radius 8 -> 10 to match the mockups' rounder cards.
- Accent picker: offer indigo/cyan/violet presets first (kept #15803d).
Behaviour-only theme change. Frontend suite: 38/39 pass; the 1 failure
(end-to-end-trust-loop tailored-CV) is pre-existing on this branch (verified by
running it on the clean tree) and unrelated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
One-click job capture from any posting, reusing the existing
jobimport/preview parser.
- AddJobModal accepts initialUrl and auto-imports once on open
- App reads a /?add=<encoded url> param, opens Add Job pre-filled, and
strips the param from the address bar
- QuickCaptureCard in Settings offers a draggable bookmarklet (href set
via ref since React blocks javascript: URLs) plus copyable code
- EN/NB translations; README feature note
- 2 frontend tests; full suite green (22 suites / 50 tests)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>