Repository navigation
Invitation link while signed out: the generic 欢迎回来 login page with no inviter or organization, no prefilled email, and a second verification mail after sign-up #25886
Description
Filing gate ① a reproduced UX defect (class a, public door: the invitation link in the mail). reach: local stack, cloud main 36b07fdf + objectui pin 6f629a7 + framework pin 888d686, zh-CN, 2026-10-25. A signed-out person opening /_console/accept-invitation/<id> from the invitation mail is sent to the generic login page 「欢迎回来 / 登录后继续你的工作」. That page never says who invited them or to what, and their address is not filled in. Filed at the maintainer's request in this session: 「还需要测试验证邀请注册、邀请之后登录的完整流程和用户体验……必要的合理的建议都可以立卡」.
Batch-of: 10 · 2026-10-25 desktop E2E (signup · magic flow · invite).
Business reason. The invitation is how a customer's colleagues arrive: every seat after the first comes through it. The invitee has never heard of the product. Today the first screen greets them as a returning user, the action they need (注册) is the small link, and nothing ties the page to the mail they just clicked. Each extra moment of "is this the right site?" costs invitations that are never accepted. The owner's checklist step 「邀请一位同事」 stays open.
Reader who acts. The repo:objectui ui seat, in packages/app-shell/src/console/organizations/manage/AcceptInvitationPage.tsx and the login/register pages it redirects to. If the anonymous invitation preview needs a server read, the seat files the cloud/framework half.
Measured (in order)
- The mail reads 「陈静(chenjing…)邀请您以 Member 的身份加入 ObjectOS Cloud 上的 静安家居设计。接受邀请:http://localhost:4600/_console/accept-invitation/yzDo…」. The English role word is a separate card.
- The link lands on
/_console/login?redirect=/accept-invitation/…: 「欢迎回来」, empty email field, 注册 as a text link.AcceptInvitationPage.tsx:58doesnavigate('/login?redirect=…')for any unauthenticated visitor. - 注册 keeps the redirect (objectui#10893 fixed that ✓). The page is the generic 「创建账户 · 创建账号,开始搭建。」 and the invited address is again not prefilled. An invitee can register a different address than the one invited.
- After registering, the invitee must verify the same address again with a second mail, although they arrived by clicking a link sent to that address. The verify link carries
callbackURL=/_console/accept-invitation/…✓. - The accept page itself is clear: organization, role 成员, expiry 2026/10/27, 拒绝 / 接受邀请. It does not name the inviter.
Expected
- Opening an invitation link signed-out shows the invitation: who invited, which organization, which role. It offers 「注册并加入」 as the primary action and 「已有账号?登录」 second, with the invited email prefilled (and locked or warned on change).
- The accept page names the inviter.
- Optional, needs a server decision: skip the second verification mail when the registering address equals the invitation's address and the invitation link was just used. If the seat finds this needs a framework change, file it there as ② rather than build it here.
Dedupe
gh api search/issues, repos cloud / objectui / objectstack, incl. closed:
accept-invitation login register prefill: 0 / 0 / 2, unrelated QA runs.邀请 注册 验证邮箱: 5 / 1 / 5. objectui#10893 (closed) fixed the lost redirect, not the landing. cloud#3113 (closed) is signup security. objectstack#25040 (closed) is signup existence/verification posture.invitee verify email twice: 1 / 0 / 8, unrelated.invitation landing login page context: 4 / 5 / 26, none on the landing.
Activity
objectstack-fleet commentedon Oct 25, 2026
One more instance of the same generic-login copy, 2026-10-25T14:16Z. A plain member's first-ever entry into a hosted environment (after the member bounce, cloud#584) lands on the env login page titled 「欢迎回来 / 登录后继续你的工作」. That is the same objectui#12600 header copy (
zh.ts:2397) this card already covers for the invitation landing, now on the environment host. Whatever this card does for "first visit vs returning" should cover/_console/loginon environment hosts too. Measured on the 2026-10-25 local E2E (objectui pin6f629a7).objectstack-fleet commentedon Oct 26, 2026
Transferred 2026-10-26T02:46Z from objectstack-ai/objectui#13531, with its comments and timeline; the old URL redirects here. objectui moved into this repository as the
ui/workspace (epic #25677) and is being archived (#25854). The body is left exactly as filed.Paths. Read every repository path in the body with a
ui/prefix:packages/app-shell/src/console/organizations/manage/AcceptInvitationPage.tsxis nowui/packages/app-shell/src/console/organizations/manage/AcceptInvitationPage.tsx.No stale
pm:dispatchedor assignee to strip.Generated by Claude Code
objectstack-fleet commentedon Oct 26, 2026
Retriage request ·
domain:uiseat 1 (#25966) ·session_017iXjUm1rujwDk7f3KT1Pkk· 2026-10-26T06:28Z⛔ Not a claim, ⛔ not a dispatch.
pm:retriageadded with this comment.What is asked of triage: a first touch. This card carries
pm:queueand apriority:*label applied at filing (Batch-of 10, 2026-10-25), but its thread has no triage audit comment, in objectui before the transfer or here after it. The comments on this card are the transfer note and nothing from triage. Without the audit comment the card is not a candidate for this lane (execution-duties.md, candidates: a pre-appliedpm:queuereads as absent), so it waits here instead of being dispatched.The ui seat neither grades nor routes. Once triage has written the first grade and taken
pm:retriageoff, this seat reads the card again at its next pick.objectstack-fleet commentedon Oct 26, 2026
Triage: first touch —
bug·priority:p2·domain:ui·area:identity·pm:queue(pm:retriageremoved) · triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-26T06:59Z⛔ Not a claim, ⛔ not a dispatch. First touch after the transfer from objectui. The card had no triage audit comment there or here, which is what the
domain:uiseat (#25966) needs before it can pick it.Generated by Claude Code
objectstack-fleet commentedon Oct 26, 2026
Claim: PM loop round 1
Session:
session_017iXjUm1rujwDk7f3KT1Pkk(seat); implementing card threadsession_016msqupguN18F4BUKKWYbWYAccount:
os-steveBranch:
claude/project-thread-oojj3w(platform-assigned card-thread branch; a card thread can push only its assigned branch, and the name carries no issue number, so this claim is the identity record)Worktree: the card thread's own container
Domain:
domain:uiSeat:
domain:ui#1File surface:
ui/packages/app-shell/src/console/auth/LoginPage.tsx(signed-out arrival from an invitation link) andui/packages/app-shell/src/console/organizations/manage/AcceptInvitationPage.tsx, their tests,ui/packages/i18nlocale strings for the new copy, andscripts/sdui-manifest.record.json(derived hash). Boundary from triage (06:59Z): show only what the invitation carries (inviting org display name, inviter display name, invited address), read through the invitation id the link already holds, only for a valid, unexpired invitation. If a signed-out read needs a new server endpoint, stop and report; that part goes before review and is outside this card (stop on breach; explain in the report). ⛔ui/.github/**and the root.github/workflows/ci.ymlare out of bounds (maintainer's word, ui-merge epic in flight). Changeset in the root.changeset/.Container & model:
M,mode:thread,model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate),effort: mediumClause-②: no (console pages and locale strings only; a new server read, if one is needed, is a stop, not part of this card)
Metadata-protocol: none
Responsibility:
n/a: renderer defect in ui/, the producing code is the cited ui file; no platform path covers it; reached through the public ConsoleThread-read: 6410185888
Premise: holds (triage first touch 06:59Z, p2 as filed; read-only check by the seat at
origin/maina3e5bfa 2026-10-26T09:16Z)Serial constraints cleared: none: #25885 (Register page) is queued, not dispatched; no open PR touches these files (open-PR file scan 2026-10-26T09:16Z)
Dispatch order handed to the card thread by the project coordinator (three partitions: ruling / mechanism hypotheses / suggested route); the dev does not claim, and starts only once this claim names its branch.
objectstack-fleet commentedon Oct 26, 2026
Claim amendment (seat
domain:ui#1, 2026-10-26T09:19Z): the card thread measured before coding that the signed-out half needs a new server read. better-auth 1.7.12'sGET /organization/get-invitationanswers 401 with no session, and with a session it requires the session email to equal the invited address;auth-route-ledger.tshas no anonymous invitation read. So the inviting org's name and the inviter's name cannot be shown to a signed-out viewer from ui alone.The seat narrows this claim to the ui slice that needs no new endpoint, and the PR says
Part of #25886, notFixes:inviterEmailthe existing response already carries;/accept-invitation/, the login and register pages replace the generic 欢迎回来 copy with a generic "sign in or sign up to accept the invitation" line and make sign-up a visible action. No org data is shown.The file surface adds the pages the console actually mounts at
/login:ui/apps/console/src/pages/auth/LoginPage.tsxandui/apps/console/src/pages/auth/RegisterPage.tsx(the 欢迎回来 copy is theirauth.login.welcomeTitle). It also addsui/packages/app-shell/src/console/auth/RegisterPage.tsx, kept in step with the app-shell login page, and the same new keys in the tenui/packages/i18n/src/locales/*.tspacks.The anonymous read (org display name, inviter display name, invited address, pending and unexpired only) is a
plugin-authchange outside the ui lane. It goes to its own card before review, and this card stays open for it. Everything else in the claim is unchanged.Seat handover: on the maintainer's ask to balance the ui lane (09:18Z), this card moves to seat
domain:ui#2(seat post #25995), which now owns the auth pages. The card thread, its branch and this claim's surface stay as they are. Seat 2 does the review and landing; the thread reports to seat 2 from now on.objectstack-fleet commentedon Oct 26, 2026
os-dev-report
{ "issue": 25886, "status": "done", "branch": "claude/project-thread-oojj3w", "pr": "https://github.com/objectstack-ai/objectstack/pull/26044", "session": "session_016msqupguN18F4BUKKWYbWY", "premise_still_valid": true, "summary": "UI half only, as narrowed by the claim and its amendment (6412491564): both login pages (console /login and app-shell DefaultLoginPage) greet a signed-out visitor from an invitation redirect with an invitation header and, where decideSignUpOffer answers form, a full-width Create an account and join link (new app-shell export InvitationSignUpPrompt) in place of the small Sign up link; both register pages ask for the invited address; the accept page shows an Invited by row from inviterEmail. The signed-out preview (org, inviter, invited address, prefill) is NOT done: better-auth 1.7.12 get-invitation answers 401 without a session and requires the recipient email with one; no anonymous invitation route exists in auth-route-ledger.ts. PR says Part of #25886.", "tests": "at baa3ba94 lineage: pnpm exec vitest run (ui root, lock) over app-shell console/auth, console/organizations, apps/console pages/auth, packages/i18n, product-neutral ratchet: Test Files 133 passed (133), Tests 1691 passed, 13 skipped (run before merging origin/main c16c00f9; merge touched none of these files). Ablation: console LoginPage.tsx + AcceptInvitationPage.tsx restored to base a3e5bfa6 (marker grep counts 0/0): 5 failed of 14 in the two pinned files; restored via git checkout HEAD, git diff HEAD empty. type-check: pnpm --filter @object-ui/app-shell --filter @object-ui/console --filter @object-ui/i18n run type-check after building the @object-ui/console^... closure: lock VERDICT command-exit 0, 0 TS errors.", "gates": "local: dispatch-gates --commands derived 46 commands; all 46 exit 0 (check:query-options-erasure and check:type-check-debt exceeded a 300s per-command cap on the first pass, re-run uncapped exit 0); node scripts/check-sdui-manifest.mjs exit 0 after node scripts/gen-sdui-manifest-node.mjs (record re-recorded, manifest json unchanged); --ran reconciled 46 of 46. CI: in_progress at report time, not waited on.", "dogfood_battery": "n/a — no ! in the PR title and Clause-②: no without a (narrowing) arm", "mcp_calls": "5 — issue_read x4 (get, get_comments x3), subscribe_pr_activity x1; no MCP write", "api_writes": "2 — fleet-write relay pr_create (objectstack-ai/objectstack#26044), post-stamped comment on #25886 (this report); plus git push x3 to the branch (not REST)", "open_questions": [], "out_of_scope_findings": [ "carrier: seat 2 — anonymous invitation preview read in plugin-auth (org display name, inviter display name, invited address; pending and unexpired only) is needed for the signed-out half of #25886; dedupe words: invitation preview anonymous, get-invitation signed out, accept-invitation login context", "carrier: seat 2 — skip-second-verification-mail for an invitee registering the invited address is a server decision, same server card family", "noted, not filed: environment-host first-visit login greeted as Welcome back (card comment 6407079091) has no invitation signal and is not covered" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 26, 2026
Claim amendment ·
domain:uiseat 2 · 2026-10-26T10:08ZSession:
session_01SMps7wq7rBTk53e8KTSEupSeat:
domain:ui#2Branch:
claude/project-thread-oojj3wAmends: Claim 6412437492 (with amendment 6412491564)
Clause-②: yes
Reason: PR #26044 (head
baa3ba94) addsInvitationSignUpPromptto the root exports of@object-ui/app-shell(ui/packages/app-shell/src/index.ts). That package is published (noprivate), so the change widens its public surface, and that is the test foryes. The claim'snopredates the export, and the seat corrects it here. The PR body and the changeset follow. The seat writes theTIER_DEFAULTdeclaration review. Everything else in the claim is unchanged.objectstack-fleet commentedon Oct 26, 2026
Pointer ·
domain:uiseat 2 · 2026-10-26T10:13Zui slice: ACCEPT → PR #26044 comment 6413497853. Contract review (TIER_DEFAULT) PASS: comment 6413489249, head
5a7ff839. The seat lands it once the checks are green. The card stays open for the server items on #26020.objectstack-fleet commentedon Oct 26, 2026
Landed · seat 2 · 2026-10-26T16:52Z
326a5593. It carries #26044 (Part of #25886, head5a7ff839) verbatim, with seat 2's ACCEPT and contract review 6413489249origin/main6862ef62, contains326a5593(git merge-base --is-ancestorexit 0)gh-readonly-queue/main/pr-26158-*: 0 leftStatus: this card's ui half is done. The server half was split to #26020 (
domain:server), which carries it from here. Closing as completed;pm:dispatchedcomes off.