CodeIssuesPull RequestsActionsSecurityInsights
✨ AI
More
Settings

fix: sidebar re-expand, silent token refresh, working Gmail/Outlook connect + gap audit #4061

Merged⚡ AI-generatedXSccantynz wants to mergeclaude/dreamy-wozniak-hlrxofmainopened Jun 13, 2026
ccantynzcommented Jun 13, 2026

Originally written by @ccantynz-alt on GitHub.
Imported from https://github.com/ccantynz-alt/AlecRae.com/pull/70


Addresses three issues Craig reported and the request to scan for gaps (docs were out of date).

Bugs fixed

1. Sidebar collapse was a dead end — pressing the toggle ("left arrow") collapsed the nav to 64px, but the overflow-hidden sidebar still rendered the full "AlecRae" wordmark, pushing the expand button off the visible edge. No way back. Now the wordmark is hidden when collapsed (toggle stays visible/centered) and ⌘\ / Ctrl\ toggles the sidebar as a guaranteed keyboard path.

2. "Invalid or expired bearer token" mid-session — access tokens last 15 min; the API issues a 7-day refresh token alongside them, but the web client discarded the refresh token and never refreshed, so after 15 min idle every request 401'd and the user was silently logged out. New apps/web/lib/auth-token.ts stores the refresh token and, on any 401, silently calls /v1/auth/refresh (single-flight) and retries once before giving up. Wired into both fetch wrappers, all login flows, and the Google callback (which now forwards the refresh token in its fragment).

⚠️ Infra caveat: a stable JWT_SECRET (≥32 chars) must be set on the box, or every API restart regenerates an ephemeral signing key and invalidates everyone's tokens at once — a second, infra-side cause of the same error that the client refresh can't fix.

3. Gmail/Outlook connect was completely broken (the path to importing inboxes) — three stacked bugs: relative /v1/connect/gmail hit the web host not the API; a top-level browser redirect carried no Bearer header (401); and the route required the unsatisfiable accounts:write scope (403 regardless). Now GET /v1/connect/gmail|outlook return the OAuth consent URL as JSON via an authenticated fetch (the signed state still carries identity to the public callback, so no token lands in any URL) and use the satisfiable account:manage scope. Onboarding fetches the URL, then navigates.

Gap audit

Adds PRODUCT_GAP_AUDIT.md (code-verified): the backend is genuinely deep (~96 mounted route groups, 300+ endpoints, DB-backed), but the web app exposes only a fraction. There is no working admin console (the one /admin page is unlinked, ungated, wired to nothing), and mailbox provisioning, Google-Workspace bulk import, org/team/invite/SSO, and import jobs are all backend-only with no UI (import workers are also stubs). Craig is an owner and the sidebar shows the role badge, but cannot administer or run the business/workspace flows from the product. The gap is frontend wiring + a few stub workers, not missing backend.

Verification

  • Web + API typecheck clean
  • Web + API lint: 0 errors
  • Tests: 143 API + 11 web + 6 JWT pass
  • Web production build succeeds (49 pages, 102 kB shared baseline)
  • docs:check green

Note: these are repo-side fixes. Production is the box at 149.28.119.158, which may still serve a pre-2026-06-11 build (CLAUDE.md #35). Nothing is live until the box runs its pull/build ritual.

https://claude.ai/code/session_01VNLKrNfL6Z87AjCnht8DrF


Generated by Claude Code

ccantynzcommented Jun 13, 2026

Originally written by @vercel[bot] on GitHub.


Deployment failed with the following error:

There is no GitHub account connected to this Vercel account.
ccantynzcommented Jun 13, 2026

Originally written by @vercel[bot] on GitHub.


The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
alec-rae-com-admin Ready Ready Preview, Comment Jun 13, 2026 2:50am

Cross-repo impact

See what breaks downstream if this PR merges.

Analyze →
⮌ Merged

This pull request was merged into main.

c comment · e edit title · m merge · a approve · r request changes · ? shortcuts