Skip to content

feat(app-shell): prefill the first organization name from the sign-up e-mail - #30305

Draft
objectstack-fleet[bot] wants to merge 4 commits into
mainfrom
claude/issue-30136-org-name-prefill
Draft

objectstack-fleet[bot] wants to merge 4 commits into
mainfrom
claude/issue-30136-org-name-prefill

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #30136

Clause-②: yes (widening)
Metadata-protocol: none

维护者速读

  • 改了什么:云端注册后自动弹出的「创建组织」对话框,名称不再是空的。企业邮箱用域名推出公司名(jane@acme.com → Acme),公共邮箱(gmail、qq、163 等,代码里的闭合清单)用「张三的组织」。用户可以改,也可以直接点创建;不会自动建组织。
  • 为什么改:执行 cloud#3559 裁决 A。新用户验证完邮箱后必须先想一个组织名才能进去,这是通往第一个应用路上唯一要用户动脑的一步,生产上 20 个新注册里有 1 个明确停在这里。
  • 风险与回滚:只影响「还没有任何组织」的用户第一次看到的输入框初值;再建第二个组织仍是空的。回滚就是 revert 这个 PR,没有数据或接口变化。
  • 先看:ui/packages/app-shell/src/console/organizations/defaultOrganizationName.ts(域名规则与公共邮箱清单)、CreateWorkspaceDialog.tsx(只在打开那一刻取默认值的那段)、ui/packages/i18n/src/locales/zh.ts 的 defaultPersonalName。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/app-shell/src/console/organizations/__tests__/ ,预期全部通过,其中 prefills a first organization from the e-mail 一组覆盖 gmail 用户(中英两种语言)与 acme.com 用户。
  • 需要你做的:无,席位落地。

What changes

  • New defaultOrganizationName({ email, name }) (ui/packages/app-shell/src/console/organizations/defaultOrganizationName.ts), a pure function returning either { kind: 'company', name } or { kind: 'personal', person }, or null when there is no usable e-mail.
    • Work domain: the registrable label, capitalised. The rule is the smallest one that handles the common multi-part suffixes without the Public Suffix List: the label left of the TLD, except under a two-letter country TLD whose second-level label is one of a closed set of registry-run labels (co, com, net, org, gov, edu, ac, or, ne, go, gob, ltd, plc), where it is the label before that pair. So acme.com, mail.acme.com, acme.co.uk, acme.com.cn, eu.acme.co.jp all give Acme. A suffix this misses gives a visible, editable guess, not an error.
    • Public mailbox domain: a closed list in code (PUBLIC_MAILBOX_DOMAINS, which carries every domain the card names plus similar providers); a subdomain of a listed domain counts too (vip.qq.com), while a domain that merely ends in a listed name does not (notgmail.com). Unknown domains are work domains, as ruled.
    • Personal form fallback: a user with no name, a blank name, or a name equal to the address itself falls back to the e-mail's local part (zhang.san@gmail.com → zhang.san).
    • Punycode: a work label spelled xn--… would show as gibberish, so it takes the personal form instead.
  • CreateWorkspaceDialog takes user, organizations and isOrganizationsLoading from useAuth() (it already called it) and prefills the name when the dialog opens. The personal form is rendered through the new workspace.defaultPersonalName key ({{name}}'s organization / {{name}}的组织), so all ten locales get it, not just en/zh. The default is read only at open time: creating the organization moves organizations off zero mid-submit, and the name being submitted must not change.
  • Scope decision, first organization only. The ruling scopes the default to 「注册后给组织起名这一步」, the naming step after sign-up. So the prefill applies only when the user's organization list is known and empty (not still loading). That covers the auto-open after sign-up and ?create=1 for a zero-org user. Creating a second organization still opens empty, because a second default from the same e-mail would just repeat the first organization's name. The check reads the auth context, so no new prop is added to the exported component and every caller behaves the same.
  • @object-ui/i18n: the new workspace.defaultPersonalName key is in all ten packs, and the organisation-noun vocabulary pin (organizations-picker-vocabulary-5215.test.ts) now lists it.
  • Changeset: @object-ui/i18n patch (@object-ui/app-shell is private and ships inside the Console build).

Tests

  • __tests__/defaultOrganizationName.test.ts (new) covers the domain rule (including the multi-part suffixes and the generic-TLD control), every entry of the closed list, the named domains, the subdomain and look-alike cases, the name fallbacks, punycode, and the null inputs (acceptance 4).
  • __tests__/CreateWorkspaceDialog.test.tsx gets a new top-level describe. The harness t can now answer from a real built-in pack, so the en and zh values themselves are what's tested:
    • a gmail user sees the personal default in en (Zhang San's organization) and zh (张三的组织), and one submit creates it and provisions its environment (acceptance 1, 3);
    • an @acme.com user sees Acme in both locales (acceptance 2, 3);
    • the field stays editable;
    • controls: a user who already has an organization, whose list is still loading, or with no list at all opens with an empty name;
    • the name does not change while the dialog is open when the organization list moves off zero.
Test run at head 8b0243f
pnpm --dir ui exec vitest run --maxWorkers=2 packages/app-shell/src/console/organizations/ \
  packages/i18n/src/__tests__/organizations-picker-vocabulary-5215.test.ts \
  packages/i18n/src/__tests__/all-locales-key-parity.test.ts \
  packages/i18n/src/__tests__/en-zh-key-parity.test.ts
 Test Files  21 passed (21)
      Tests  294 passed (294)
os-verify-lock: VERDICT command-exit 0

pnpm --filter @object-ui/app-shell --filter @object-ui/i18n run type-check
ui/packages/i18n type-check: Done
ui/packages/app-shell type-check: Done
os-verify-lock: VERDICT command-exit 0

(app-shell's tsconfig.test.json includes src/**/*.test.ts(x), so the type-check covers both new test files.)

Ablations (one-time, via scripts/ablation-replace.mjs, restored and verified blob == HEAD)
  1. The open-time reset changed from setName(defaultNameRef.current) to setName(''): 4 failed, 15 passed. The en, zh and work-domain cases and the mid-submit case went red; the editable case and the empty-name controls stayed green, as they should.
  2. The open-time snapshot replaced by an effect keyed on [open, defaultName]: 1 failed, 18 passed. Only the name does not change while open when the organization list moves off zero went red.

Acceptance notes

  • Hyphenated labels keep their hyphen (acme-labs.com → Acme-labs); only the first letter is capitalised, which is how the card states the rule. The user sees it and can edit it.
  • The Russian value is Организация {{name}}, with the name left in the nominative. Declining arbitrary personal names is out of reach for a template.
  • Not browser-verified against a live cloud stack. The dialog behaviour is pinned at component level with the real en/zh pack values.
  • Out of scope, held for the cloud lane per the card: the stale comment in cloud's packages/service-cloud/src/cloud-stack.ts.

Verification

Derived gate families (dispatch-gates --commands, 35 families), all run locally at head 8b0243f, every one exit 0

node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran FILE printed: Run reconciliation — 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN. All 35 recorded an exit code, and every one was 0. They include check:nul-bytes, check:published-files, check:type-check-coverage, check:type-check-debt, check:cross-package-test-inputs, check:test-source-alias, check-sdui-manifest, the changeset gates (check-adr-0087-registration, check-changeset-no-major, check-empty-changeset, check:changeset-gate-self-tests) and pnpm --dir ui exec vitest run scripts/ (170 files passed, 2 skipped). Also check:new-line-citations: VERDICT new-cross-file-line-citations: 0 new citation(s).

The repo-wide scans (pnpm lint, full Test UI, Type Check UI) are left to CI.


Generated by Claude Code

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Nov 5, 2026
…omain rules move to a neutral util

A public-mailbox user's first organization is prefilled with the existing
workspace.default copy ("My Organization" / 我的组织) instead of a new
per-person key, so the frozen workspace namespace (ADR-0060) gains nothing;
the workspace.defaultPersonalName key is removed from all ten packs. A work
e-mail still names the company from the domain's registrable label.

The address parse, the closed public-mailbox list and the registrable-label
rule move out of the frozen console/organizations directory into
utils/emailDomain.ts, with their test; only the company-versus-default
choice stays in CreateWorkspaceDialog. The changeset now names
@object-ui/app-shell at patch with Clause-②: no.

Claude-Session: https://claude.ai/code/session_01Q4EjjRhUZjdy8VXs6Kkur2
Co-authored-by: Claude <noreply@anthropic.com>

This branch has not been deployed

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

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

1 participant