镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

feat(identity): ask "Connect to your community" — sign in or bring a key — for a community no tenant hosts - #1808

Closed
matt2e wants to merge 1 commit into
onboarding/06-unlink-restore-create-my-keyfrom
onboarding/07-connect-choice
Closed

matt2e wants to merge 1 commit into
onboarding/06-unlink-restore-create-my-keyfrom
onboarding/07-connect-choice

Conversation

@matt2e

@matt2e matt2e commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Part 7 of 12 of the onboarding-flow stack (the first-run onboarding work reviewed on #1061, split into stacked PRs per the plan). Base: onboarding/06-unlink-restore-create-my-key. Each PR is a contiguous slice of the original branch's history, cherry-picked onto main; the combined tree of the whole stack equals onboarding-flow at 572d69398 rebased onto main (verified by diff, see the stack notes in the last PR). Built on main at df5180b4a (2026-10-28, the origin/main of the build); main has moved on since and the stack is not rebased onto the newer tip.

Stack

  1. feat(identity): first-run welcome screen with community lookup, Join Community and the invite page #1802 onboarding/01-welcome-find-join
  2. feat(identity): Set up your profile after the first join, and look up a community URL from the landing page before sign-in #1803 onboarding/02-profile-step-landing-url
  3. feat(identity): decide the Builderlab portal from the community URL with a build-time tenant table #1804 onboarding/03-builderlab-tenants
  4. feat(identity): Set up your key — managed, own-key reveal, import — and Welcome back for a linked account #1805 onboarding/04-key-choice-import-welcome-back
  5. feat(identity): link the first-run key to the account, and back it up through the observable native uploader #1806 onboarding/05-link-and-native-backup
  6. feat(identity): real unlink on Start over, Restore from backup, and the Create my key / I already have a key setup with Try again / Continue without backup #1807 onboarding/06-unlink-restore-create-my-key
    7. feat(identity): ask "Connect to your community" — sign in or bring a key — for a community no tenant hosts #1808 onboarding/07-connect-choice ← this PR
  7. feat(identity): invite links on first run, restore the account's saved communities, and hand a typed address to the join dialog #1809 onboarding/08-invite-links-known-communities
  8. feat(identity): render first run on Kenny's onboarding layouts, and say "Sign in with email" #1810 onboarding/09-onboarding-layouts-and-copy
  9. fix(navigation): run the visit deadline only while a presenter is attached #1811 onboarding/10-navigation-deadline
  10. fix(identity): address Carl's review of #1061 — signed-in account exit, focus handoff, consent copy, shared join owner, a11y names, design pass #1812 onboarding/11-review-fixes
  11. [DO NOT MERGE] onboarding: full stack + isolated debug Keychain slot for native testing #1813 onboarding/12-do-not-merge-keychain-slot

Scope

ConnectChoice.tsx, the connect-choice pause, the two-phase paused() in Welcome, and the builderlab-tenants.ts doc comment. Replaces PR 03's silent key-only lane with a Connect to {host} page offering sign-in or an existing key.

Squash vs the original branch: the two copy follow-ups (3f8efb2d3, 4946410d2) folded into ac665e492. The later title fix (572d69398) stays in PR 11, because it post-dates the layout / focus / alias rewrites of this page.

Checks at this level (worktree /tmp/onb-stack, head of onboarding/07-connect-choice)

  • bin/pnpm exec tsc --noEmit — 0 errors
  • bin/pnpm lint — 0 errors (21 pre-existing infos)
  • bin/pnpm design:check — all checks pass
  • git diff --check origin/main...HEAD — clean
  • bin/pnpm vitest run src/features/identity — 13 files, 352 tests passed, 0 failed

Native evidence — not claimed here

No per-level native run was performed for this PR. Native first-run testing happens on the tree of the final DO-NOT-MERGE PR of the stack (#1813), which carries the isolated debug Keychain slot; the human in-app check for this PR's behaviour is owed there, so this PR stays a draft without buzz-review-completed until Matt confirms it.

🤖 Generated with Claude Code

… for a community no tenant hosts

Implements plan note 83762c25 on top of 6762695. Nothing of it existed
before this commit: no ConnectChoice.tsx, no "connect-choice" pause,
committed or uncommitted, so the plan is implemented as written with the
four decisions taken: the button reads "Connect with Builderlab", the same
as the landing; a key created for a community Block does not host is still
linked to the Builderlab account and backed up there; Cancel sign-in after
Connect returns to the landing with the URL kept; the heading is "Connect
to {host}" and the footer button "Back".

When discovery finds a community that discoverAuthentication answers
`none` for (no tenant row by hostname or NIP-11 `self`, or a non-default
port), first run no longer runs "Creating keys…" on its own and lands on
Join Community with a key nobody chose. Setup pauses on a new page:

    Finding community ─► Connect to {host}
        Connect with Builderlab ─► the landing's own sign-in at
            BUZZ_BUILDERLAB_URL (Cancel sign-in, field disabled and held)
            ─► Checking your account… ─► Checking for a backed-up key…
            ─► Set up your key / Welcome back, every existing choice
            ─► Join Community for the found address
        I already have a key ─► Enter your private key ─► Importing your
            key… ─► Join Community (no link step, no backup offer)
            Back ─► Connect to {host}
        Back ─► landing, address kept, no second lookup

- ConnectChoice.tsx (new, stateless): heading, a body saying the relay
  cannot sign the user in but Buzz still needs a key, Connect with
  Builderlab (primary, lg), I already have a key (sm, the same contrast
  KeyChoice uses) and a Back footer. Shared owner reused: Button. No new
  tokens, components or variants.
- setup.ts: SetupPause gains "connect-choice"; createKey's comment no
  longer describes a key-only lane. No store change.
- Welcome.tsx: onFound pauses on "connect-choice" instead of starting
  createKey. paused() is now two-phase: the two pauses reachable before any
  sign-in (connect-choice, key-import) render before the `reads.current`
  guard, then the five post-sign-in pages as before. Connect is
  `setup.reset(); void signIn()`: reset is legal from paused and signIn
  publishes pending synchronously, so one render shows the landing's
  existing pending view, and from there every path is the Connect-without-
  URL lane (reads at the build portal, backup offered there, the dev seed
  applying). The key-import case derives "no account this run" from
  `reads.current === undefined`: Back then returns to the connect choice,
  and a successful import is `setup.start([])`, resting at done so the kept
  address renders Join Community. The linked and new-account import paths
  are unchanged; `link` is built inside that branch when an account exists.
  Every return to the landing still goes through backToLanding.
- builderlab-tenants.ts: the doc comment's "key-only" rationale now says
  no portal is chosen and the welcome screen asks; the matching rules and
  the `none` answer are unchanged. The tenants test row is renamed.

QR: a scanned non-hosted community reaches this page through the same
setFinding path as a typed URL, with no scanner-specific code.

Failures are the existing ones: a refused identity_import stays under the
import field with the key kept; after Connect, an account-check failure
before a key goes Back to the landing, and a link or backup failure after
"Creating keys…" offers Try again / Continue without linking or backup and
lands on Join Community for the address. Failure, SKIPPED, KeyChoice,
KeyImport and FindCommunity are untouched.

Tests (identity.test.tsx): the key-only journey is replaced by six on the
existing landingRelay fixture (relay.example.com:8443 misses the table by
port), through a shared connectChoicePage helper:
- the choice with no sign-in and no identity_create, Back keeping the
  address, invoke = restore + the two GETs;
- Connect from the choice: connect(signal, undefined), Cancel sign-in with
  the field disabled and held, account built at the build portal, Set up
  your key, Create my key with backUp(viewer), Join Community, Cancel to
  Join a community prefilled;
- Cancel sign-in after Connect: landing, address kept, signal aborted, no
  re-entry into discovery or the choice;
- I already have a key: any valid nsec accepted with its npub preview,
  Back to the choice (not Set up your key), reopened empty, Importing your
  key… behind a held identity_import, Join Community as the imported key,
  no Back up this key?, connect and account never called;
- a native import refusal staying under the field, Back to the choice;
- (beside the tenant sibling, where linkedTo lives) Connect from the choice
  as a linked account: Welcome back at the build portal, import, Not now,
  Join Community.
All six fail against HEAD's Welcome.tsx and setup.ts (checked by running a
copy of the test against HEAD's files under temporary names) and pass
here. No ConnectChoice unit test, as for KeyChoice and WelcomeBack;
setup.test.ts needs nothing.

Docs: docs/identity.md describes the page, both choices and where Back
lands, and no longer speaks of key-only setup (the import's blank profile
name and the consent paragraph say "without a Builderlab sign-in");
docs/configuration.md, .env.example and the Builderlab README say an
unmatched URL asks rather than setting up a key only.

Shared worktree: another session's uncommitted known-communities work
(the `known` ref and three-argument checkAccount in Welcome.tsx and
setup.ts, knownCommunities stubs in identity.test.tsx, and its edits to
builderlab-account.*, first-run-seed.*, setup.test.ts, vite-config.test.mjs
and the same four docs) is left unstaged, untouched and uncommitted; only
this change's hunks were staged, through `git add -p`. The staged test file
was run against the staged Welcome.tsx and setup.ts (103 tests pass) as
well as against the working tree.

Diff: production +118/−33 across ConnectChoice.tsx (53 new lines),
Welcome.tsx, setup.ts and builderlab-tenants.ts, against the plan's
≈+80/−12; the excess is the paused() restructure moving the five existing
cases under a second switch, plus doc comments. Tests +335/−17, docs
+19/−9. No FOUNDATION file (App.tsx, services.ts, main.tsx,
communities/service.ts, plugins/api.ts), no Rust, no new dependencies.

Validation on the working tree: `bin/pnpm vitest run src/features/identity`
(13 files, 365 tests), `tsc --noEmit`, `pnpm lint` (0 errors, pre-existing
infos only), `biome check` on the six changed source and test files,
`pnpm design:check`, `git diff --cached --check`.

Nothing was run in the native app: neither Connect from the choice nor an
import before any sign-in has ever run natively, so the first real run
should use a non-tenant relay (the throwaway Caddy relay from note
f72cf6f3) after resetting this branch's Keychain slot.

Squashed for the stacked PR — 3f8efb2 (fix(identity): lead the Connect to {host} page with why Buzz needs a key):

fix(identity): lead the Connect to {host} page with why Buzz needs a key

Copy change to the first-run **Connect to {host}** page from eba834b,
per feedback on project note 4925261e. The body framed the choice around
a limitation of the relay ("{host} isn’t hosted by Builderlab, so it can’t
sign you in. Buzz still needs a private key for you. …"). It now leads
with what Buzz actually needs, and says nothing about what the relay can
or cannot do. The final body, exactly:

    Buzz relies on a key for your identity. Connect with Builderlab to
    create and back one up, or bring a key you already have.

Unchanged: the heading "Connect to {host}", the primary lg "Connect with
Builderlab" and the small secondary "I already have a key" buttons, their
order, the Back footer, and all behaviour. The component's doc comment
still records the pause's rationale for developers.

- src/features/identity/ConnectChoice.tsx: the body paragraph only.
- identity.test.tsx: the one connect-choice journey that pinned the old
  body ("isn’t hosted by Builderlab") now asserts the new lead sentence;
  the other five journeys through connectChoicePage check the heading and
  buttons only and need no change.
- docs/identity.md: the Connect to {host} paragraph now says the page
  leads with why a key is needed and offers two ways to get one.

Shared worktree: another session's uncommitted known-communities work
(Welcome.tsx, setup.*, builderlab-account.*, first-run-seed.*,
vite-config.test.mjs, 14 lines of identity.test.tsx, the docs/identity.md
known-communities paragraph, .env.example, configuration.md, the README)
was left unstaged and untouched; only these three hunks were staged with
`git add -p`.

No FOUNDATION file (App.tsx, services.ts, main.tsx, communities/service.ts,
plugins/api.ts), no Rust, no new dependencies.

Validation on the working tree: `bin/pnpm vitest run src/features/identity`
(13 files, 365 tests), `tsc --noEmit`, `biome check` on ConnectChoice.tsx
and identity.test.tsx, `git diff --cached --check`. Not exercised in the
native app; the change is copy only.

Squashed for the stacked PR — 4946410 (fix(identity): trim the Connect to {host} body to one sentence):

fix(identity): trim the Connect to {host} body to one sentence

Copy trim to the first-run **Connect to {host}** page, following
f06994a. The body's second sentence ("Connect with Builderlab to
create and back one up, or bring a key you already have.") is removed
and not replaced; it restated the two buttons beneath it. The final
body, exactly:

    Buzz relies on a key for your identity.

Unchanged: the heading "Connect to {host}", the primary lg "Connect with
Builderlab" and small secondary "I already have a key" buttons, their
order, sizes and variants, the Back footer, and all behaviour.

- src/features/identity/ConnectChoice.tsx: the body paragraph only.
- identity.test.tsx: the connect-choice journey that matched the body
  with a prefix regex now asserts the exact full string
  "Buzz relies on a key for your identity.", so a second sentence
  cannot return unnoticed.
- docs/identity.md: the Connect to {host} paragraph no longer says the
  page "offers two ways to get one"; it says the page says only that
  Buzz relies on a key for the user's identity and lists the two
  choices. Reflowed to the file's 80-column wrap.

Shared worktree: another session's uncommitted known-communities work
(Welcome.tsx, setup.*, builderlab-account.*, first-run-seed.*,
vite-config.test.mjs, its hunks in identity.test.tsx and docs/identity.md,
.env.example, configuration.md, the README) was left unstaged and
untouched; only these three hunks were staged with `git add -p`.

No FOUNDATION file (App.tsx, services.ts, main.tsx, communities/service.ts,
plugins/api.ts), no Rust, no new dependencies.

Validation on the working tree: `bin/pnpm vitest run src/features/identity`
(13 files, 365 tests), `tsc --noEmit` (exit 0), `biome check` on
ConnectChoice.tsx and identity.test.tsx, `git diff --cached --check`.
Not exercised in the native app; the change is copy only.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
@matt2e
matt2e marked this pull request as ready for review October 28, 2026 12:26
@matt2e
matt2e requested review from a team as code owners October 28, 2026 12:26
@matt2e

matt2e commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Closing: this stack was cut as chronological slices of the branch history rather than logical, independently reviewable layers. It will be replaced by a stack built from the squashed diff. Nothing from this PR was merged.

@matt2e matt2e closed this Oct 28, 2026
@matt2e
matt2e deleted the onboarding/07-connect-choice branch October 28, 2026 12:30
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.

1 participant