8000 feat(auth): POC E — ask once what someone came to huddlz for by MichaelDimmitt · Pull Request #673 · huddlz-hq/huddlz · GitHub
[go: up one dir, main page]

Skip to content

feat(auth): POC E — ask once what someone came to huddlz for - #673

Closed
MichaelDimmitt wants to merge 4 commits into
huddlz-hq:mainfrom
MichaelDimmitt:poc/670-intent-login-flow
Closed

MichaelDimmitt wants to merge 4 commits into
huddlz-hq:mainfrom
MichaelDimmitt:poc/670-intent-login-flow

Conversation

@MichaelDimmitt
@MichaelDimmitt MichaelDimmitt commented Oct 9, 2026 •
Copy link
Copy Markdown
Contributor

Summary

POC variant E. The app can't guess intent, so when it has nothing to go on it asks once.

AuthController.success/4
  return_to/1
    params["return_to"]        -> honored, question never shown
    session[:return_to]        -> honored, question never shown
    neither                    -> "/"  ← the only no-intent case
      intent_destination(user, "/")
        landing_choice :unasked      -> /welcome   (ask)
        landing_choice :my_huddlz    -> /agenda    (never ask again)
        landing_choice :find_a_huddl -> /discover  (never ask again)

The bypass is a pattern match on the literal "/" fallback, not a condition — so a carried
destination wins structurally and nothing is interposed on it.

lib/huddlz/accounts/landing_choice.ex      # :unasked | :my_huddlz | :find_a_huddl
lib/huddlz/accounts/user.ex                # attribute + :update_landing_choice + policy
lib/huddlz_web/controllers/auth_controller.ex  # the one interposing clause
lib/huddlz_web/live/welcome_live.ex        # the question, and the choice log line

Showing policy: asked exactly once, persisted. A question you re-answer every time is
worse than a default you set once, so the answer is stored on landing_choice and the second
sign-in routes straight to the chosen landing. Visiting /welcome after answering redirects
out rather than re-asking. "Not sure yet" leaves 8000 without recording an answer, so the question
stays open and nobody is cornered.

Why it's worth building despite the extra click: this is the only variant that measures
intent directly. Every answer emits one greppable line,
post_sign_in_intent choice=<my_huddlz|find_a_huddl> user_id=<id>, so the distribution of
choices can settle variant B's default argument with grep | sort | uniq -c and no analytics
plumbing.

Depends on variant A. Probing the global header's sign-in link from a huddl page, the
question does interpose — that link is still a bare ~p"/sign-in" on main and drops the
destination. Fixing it is A's deliverable, so I deliberately did not build it here; E would
then be scored partly on A's idea. The scenario pins E's side of the contract instead. If E
is chosen, A must ship with it — E alone would interrupt exactly the person #670 is about.

Evidence

Screenshot

Variant E

The intent question shown once after signing in, with both destinations and a way out.

Before — the question doesn't exist, so sign-in goes straight to the agenda:

Then the user is asked what they came for
  Expected path to be "/welcome" but got "/agenda"
     [passed] And the user submits the password sign in form
     [failed] Then the user is asked what they came for

The return_to bypass scenario passed before implementation and still passes after — that
journey is untouched by design.

After — mix test test/features_test.exs --only intent_login:

Scenario: Signing in offers a choice and Find a new one reaches Discover   .
Scenario: Signing in and choosing See my huddlz reaches the agenda         .
Scenario: Someone arriving from a huddl link is never asked                .
Scenario: Someone signing in from a huddl page's header link is never asked .
Scenario: The choice is not asked again on the next sign in                .
Scenario: The question can be skipped without answering it                 .

The choice log line can't be observed through a public UI, so it's pinned separately in
test/huddlz_web/live/welcome_live_test.exs (asserts the logged line, the persisted answer,
and that an answered person isn't asked again). mix compile --warnings-as-errors is clean.

Merge Danger

Door: two-way.

The interposing clause is one function in AuthController; deleting it restores today's
behavior exactly. landing_choice is additive with a default, so the migration is reversible
and nothing reads the attribute except this flow. Not exposed over GraphQL — a POC preference
has no business in the public schema, and graphql_user_exposure_test.exs pins that surface.

Blast Radius: sign-in.

Every authenticated journey passes through AuthController.success/4, which is why the
return_to bypass is a pattern match rather than a check, and why it has its own scenario.
The honest residual risk is the header gap above: until A ships, someone arriving from a huddl
link via the header meets the question instead of their huddl.

Part of #670

This is a POC for comparison, not intended to merge as-is. Verified by
scenario (failing -> passing) and a clean --warnings-as-errors compile
only; mix precommit is a deliberate follow-up after review.

Model: Claude Opus 5.5 (claude-opus-5-5)

🤖 Generated with Claude Code

Issue huddlz-hq#670 asks for several competing proofs of concept, each as its own
draft PR, so one can be chosen and the rest declined. This is the shared
brief those PRs are built from: the problem, what the code already does,
one section per variant with its own task list, and the rubric they are
all judged against.

Records three findings that shape the variants: the return_to plumbing is
already complete and safe but only the huddl page's RSVP button produces
such a link; the agenda already loads both scopes every render to feed its
chip counts; and the agenda has no query for huddlz outside a person's
groups.

Part of huddlz-hq#670
The POC variants are compared partly on whether people want to use them,
so a variant that looks unfinished loses Desirable and Delightful for
reasons unrelated to its idea. Ask each one to polish the surface it
changes, and keep the scope discipline pointed at everything else.

Part of huddlz-hq#670
POC variant E for the post-login landing comparison. The app cannot guess
intent, so when it has nothing to go on it asks: "See my huddlz" or "Find a
new one", routing to the agenda or Discover.

The question is interposed in AuthController.success/4 only on the literal
"/" fallback from return_to/1. That fallback happens exactly when neither
params nor session carried a valid destination, so a person arriving from a
huddl link sails straight through — the bypass is a pattern match rather than
a condition that could rot.

Asked once, not every time. The answer persists on a new landing_choice
attribute, modelled on theme_preference (atom enum, allow_nil? false, a
narrow :update_landing_choice action, and a policy allowing only
id == ^actor(:id)). From the second sign-in onward the app routes straight to
the chosen landing, and visiting /welcome again redirects an answered person
out instead of re-asking. "Not sure yet" leaves without recording an answer,
so the question stays open and nobody is cornered.

Every answer emits one greppable log line so the distribution of choices is
observable without analytics plumbing. That distribution is the reason this
variant is worth building: it is direct evidence for what the default should
be in variant B.

Part of huddlz-hq#670
Set variant E's row to the open PR, tick its completed tasks, and fill in its
Findings: the measured click counts, the showing policy and why a one-time
question is the only version that survives Krug's "memorable" criterion, the
dependency on variant A that testing the header link exposed, and an honest
note that the choice distribution so far is test fixtures rather than evidence
about people.

Part of huddlz-hq#670
@MichaelDimmitt
Copy link
Copy Markdown
Contributor Author

Closing: not pursued for #670. Asking at sign-in adds a click and interrupts the person #670 is about. The idea of measuring intent is deferred until production has somewhere to keep the data. The chosen approach is #678.

@MichaelDimmitt MichaelDimmitt reopened this 8000 Oct 10, 2026
@mwoods79 mwoods79 closed this Oct 10, 2026
Copy link
Copy Markdown
Contributor

Thanks for exploring this, Michael. I’m closing this option because the extra question repeats choices people can already make through the header navigation and search. It also saves a landing preference without a way to change it later. We’ll keep the sign-in flow simple and focus on returning people to the page they came from.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0