feat(lookout): nudge never-tracked users to Lookout on the /rng page#749
feat(lookout): nudge never-tracked users to Lookout on the /rng page#749dhamariT wants to merge 4 commits into
Conversation
The daily random number is a retention hook people come back to even when they aren't tracking any time — so it's a natural place to catch the folks who signed in but never logged hours and steer them to Lookout. - New _lookout_nudge partial, reusing the .idv-setup-card styling (no new CSS) - Rendered under the /rng hero when :lookout is on and the viewer hasn't linked Hackatime yet - Eligibility is a cheap identity-association check, never a live Hackatime sync (that would add an API call to a hot path); the CTA links Hackatime and returns them to their most recent project so recording is one click away Behind the same :lookout flag (off by default), so /rng is unchanged in prod.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 09abf17. Configure here.
| return if current_user.hackatime_identity.present? | ||
|
|
||
| recent_project = current_user.projects.order(created_at: :desc).first | ||
| recent_project ? project_path(recent_project) : rng_path |
There was a problem hiding this comment.
Wrong project recency ordering
Medium Severity
lookout_nudge_origin picks the Hackatime return destination with projects.order(created_at: :desc), but elsewhere the app treats the user’s active project as projects.order(updated_at: :desc) (home composer and project show). After linking, users with multiple projects can land on a stale or empty project instead of the one they actually use.
Reviewed by Cursor Bugbot for commit 09abf17. Configure here.
Swaps the .idv-setup-card treatment for the existing .guest-banner styling (the yellow bar shown when you don't have a Hack Club account), so the nudge matches a banner already in the app instead of introducing a new look. Renames the partial and its origin ivar from nudge -> banner. No new CSS.
Move the banner out of the leaderboard body and into the application layout (same spot as the guest banner), so it pins to the top of the screen like a real sticky banner instead of sitting inline. Still scoped to /rng via the @lookout_banner_origin ivar the controller only sets there. Partial moves to shared/ since the layout now owns the render.
Lead with the benefit (record in your browser, no install, no editor extension) instead of 'Link Hackatime & record'. CTA becomes 'Log hours with Lookout'. Still routes through /auth/hackatime — the account link happens on click, just no longer front-and-center — so nothing overpromises.


What
Adds a small "Make your time count" nudge on the daily random number page (
/rng) that steers people toward Lookout (record in your browser). It shows only for signed-in users who haven't linked Hackatime yet, and only when the:lookoutflag is on — so it's off in production and/rngis unchanged there.Stacked on top of #728 (base branch
feat/lookout-default-flow), since it reuses that PR's:lookoutflag and the same "Lookout is the default" premise. Merge #728 first.Why
The daily roll is a retention hook — people come back for their number every day even when they aren't tracking any coding time. That makes it a great place to catch the crowd this whole effort is about: signed in, engaged, but never logged an hour (the "44% Hackatime Wall"). We catch them at an already-engaged moment (right by their roll) and give them one clear next step: link Hackatime and record with Lookout.
How (reuse-only, tiny diff)
No new CSS, no new component, no migration.
_lookout_nudgepartial — reuses the existing.idv-setup-cardstyling and the/auth/hackatimebutton pattern from feat(lookout): make Lookout the default time-tracking path (behind :lookout flag) #728's_track_time_card./rnghero (leaderboard.html.erb) when the nudge origin is set.DailyRollsController#leaderboardsets@lookout_nudge_originvia a privatelookout_nudge_originhelper: shows the nudge when:lookoutis on and the viewer has no Hackatime identity; the CTA links Hackatime and sends them back to their most recent project (so the on-project record flow is one click away), falling back to/rngif they have no project yet.The one thing I was careful about — no Hackatime sync on the hot path
The "truest" signal for never logged any hours is
User#all_time_coding_seconds, but that callsHackatimeService.fetch_stats, which is a live, uncached HTTP request (cache-buster +no-cacheheaders). Putting that on/rng— a high-traffic daily page — would add an API round-trip per eligible visit.So eligibility here is the cheap
hackatime_identityassociation check, which is also the exact funnel leak we care about (never linked Hackatime → definitely never logged hours). Broadening the audience to linked-but-0-hours should wait for a cached hours signal (a synced column / background job) rather than a per-request sync.Flag-off safety
With
:lookoutdisabled,@lookout_nudge_originis alwaysnil, the partial never renders, and/rngis byte-for-byte unchanged. Flag is off by default.Test
Sign in as a user with no Hackatime linked and open
/rng. The nudge appears under your roll; the CTA links Hackatime and returns you to your most recent project. Link Hackatime (orFlipper.disable(:lookout)) and it disappears.Follow-ups (not in this PR)
seenrecord or cookie).Note
Low Risk
Changes are gated by
:lookout, use a cheap identity check on an already-flagged page, and only add UI plus a post-auth redirect origin—no auth or data-model changes.Overview
Signed-in viewers on
/rngcan see a top sticky Lookout re-engagement banner when the:lookoutFlipper flag is on and they have no linked Hackatime identity.DailyRollsController#leaderboardsets@lookout_banner_originthrough a newlookout_banner_originhelper that returnsnilwhen the flag is off or Hackatime is already linked, otherwise the most recent project path (orrng_pathif they have no projects) as theoriginforPOST /auth/hackatime. Eligibility uses only thehackatime_identityassociation—no live Hackatime API on this page.The application layout renders a new
shared/_lookout_bannerpartial when that origin is set. The partial reuses.guest-bannerstyling and a “Log hours with Lookout” CTA withturbo: false, matching the existing guest banner pattern.Reviewed by Cursor Bugbot for commit 00157c7. Bugbot is set up for automated code reviews on this repo. Configure here.