Skip to content

Account migration import for organization accounts#321

Merged
dahlia merged 6 commits into
hackers-pub:mainfrom
dahlia:feature/org-account-migration
Jun 27, 2026
Merged

Account migration import for organization accounts#321
dahlia merged 6 commits into
hackers-pub:mainfrom
dahlia:feature/org-account-migration

Conversation

@dahlia

@dahlia dahlia commented Jun 27, 2026

Copy link
Copy Markdown
Member

Why

Organization accounts are first-class ActivityPub actors (Organization) with their own followers, but the Mastodon-style account migration import added in #319 was offered to personal accounts only. An organization moving from another fediverse server should be able to point its old account at Hackers' Pub just like a person can, so this lifts that restriction.

The migration machinery was already kind-agnostic: the model functions edit the actor row by account, federation/person.ts already advertises alsoKnownAs for Organization actors, and the inbox Move handler validates aliases the same way for any actor. Only two places assumed the account could sign in:

  • Server authorization in graphql/account.ts required the alias to belong to the signed-in account itself. Organizations never sign in, so their admins could never reach it. It now reuses the existing viewerCanManageAccountSettings helper, which already authorizes the personal holder and an organization's accepted admins. Routing migration through the same helper keeps it consistent with profile updates and account deletion (admins only) instead of introducing a separate permission rule.

  • The settings UI in web-next/src/routes/(root)/[handle]/settings/account.tsx rendered the migration card only for personal accounts; it now appears for organizations too, reusing the same form.

While reordering the authorization check, I also made a well-formed but nonexistent account id return the same NotAuthorizedError as an unauthorized one, so the error no longer reveals whether an account exists.

How I tested

  • New tests in graphql/account.test.ts: an organization's accepted admin can add and remove aliases, while non-admin members and non-members get NotAuthorizedError, and a nonexistent id is rejected without leaking existence.
  • Full graphql/account.test.ts file (38 tests)
  • deno task check (type check, lint, and Relay codegen across web-next)

AI assistance

Implemented with Claude Code (claude-opus-4-8) and reviewed with Codex (gpt-5.5); see the Assisted-by trailers on the commits.

dahlia added 2 commits June 27, 2026 13:37
Account migration (advertising `alsoKnownAs` aliases so an account can be
the destination of a Mastodon-style Move) was authorized only for the
signed-in account itself. Since organizations cannot sign in, their
accepted admins could never manage the organization's migration aliases.

Make `getAuthorizedMigrationAccount` reuse `viewerCanManageAccountSettings`,
which already authorizes the personal account holder and accepted admins of
an organization account, matching how `updateAccount` and `deleteAccount`
are gated. A nonexistent account now returns `NotAuthorizedError` (rather
than leaking existence via `InvalidInputError`), consistent with the
mutation input descriptions.

Assisted-by: Claude Code:claude-opus-4-8
Assisted-by: Codex:gpt-5.5
The account settings page rendered the "Account migration" card only in the
personal-account branch. Add the same card to the organization branch so an
organization's accepted admins can prepare it as a Move destination. It
reuses the existing AccountMigrationAliasesForm and the aliases already
selected by the page query, so no new query or strings are needed.

Assisted-by: Claude Code:claude-opus-4-8
@coderabbitai

coderabbitai Bot commented Jun 27, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@dahlia, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 11 minutes and 2 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 06f410a0-40a0-42f7-ac90-e698dfaf6af6

📥 Commits

Reviewing files that changed from the base of the PR and between 44ae75c and 2334988.

📒 Files selected for processing (1)
  • web-next/src/routes/(root)/[handle]/settings/account.tsx
📝 Walkthrough

Walkthrough

Migration alias mutations now allow viewers who manage an organization account to add or remove aliases, return NotAuthorizedError for missing or unmanaged targets, show the migration card for organization settings, and update the related UI copy and locale strings.

Changes

Account migration aliases

Layer / File(s) Summary
Authorization and contract
graphql/schema.graphql, graphql/account.ts, graphql/account.test.ts
addAccountMigrationAlias and removeAccountMigrationAlias now describe manage-based access for organization accounts, getAuthorizedMigrationAccount returns NotAuthorizedError for missing or unmanaged targets, and tests cover the organization-admin, member, outsider, and nonexistent-account cases.
Settings card and copy
web-next/src/routes/(root)/[handle]/settings/account.tsx, web-next/src/locales/*/messages.po
The account settings page now renders a shared migration card for personal and organization accounts, and the migration permission text was updated across the UI locale files.

Sequence Diagram(s)

sequenceDiagram
  participant AccountMigrationAliasesForm
  participant addAccountMigrationAliasMutation
  participant removeAccountMigrationAliasMutation
  participant getAuthorizedMigrationAccount
  participant viewerCanManageAccountSettings
  AccountMigrationAliasesForm->>addAccountMigrationAliasMutation: submit accountId and alias
  addAccountMigrationAliasMutation->>getAuthorizedMigrationAccount: load account and actor by id
  getAuthorizedMigrationAccount->>viewerCanManageAccountSettings: check manage access
  viewerCanManageAccountSettings-->>getAuthorizedMigrationAccount: allowed or denied
  getAuthorizedMigrationAccount-->>addAccountMigrationAliasMutation: account or NotAuthorizedError
  AccountMigrationAliasesForm->>removeAccountMigrationAliasMutation: remove alias
  removeAccountMigrationAliasMutation->>getAuthorizedMigrationAccount: load account and actor by id
  getAuthorizedMigrationAccount->>viewerCanManageAccountSettings: check manage access
  viewerCanManageAccountSettings-->>getAuthorizedMigrationAccount: allowed or denied
  getAuthorizedMigrationAccount-->>removeAccountMigrationAliasMutation: account or NotAuthorizedError
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • hackers-pub/hackerspub#319: Adds the migration-alias data and mutation handling that this PR updates for organization-admin access.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change: organization accounts can now use account migration import.
Description check ✅ Passed The description accurately describes organization-account support and the auth/UI/test changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request enables organization admins to manage account migration aliases for organization accounts. It updates the authorization logic in getAuthorizedMigrationAccount to allow personal holders or organization admins to manage migration settings, while preventing information leakage for nonexistent account IDs by returning a NotAuthorizedError. Additionally, it adds the "Account migration" settings card to the organization settings page and updates the GraphQL schema descriptions and tests accordingly. Feedback suggests refactoring the settings page to avoid duplicating the "Account migration" card between the personal and organization views.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread web-next/src/routes/(root)/[handle]/settings/account.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web-next/src/routes/`(root)/[handle]/settings/account.tsx:
- Around line 590-592: The reused authorization copy in
AccountMigrationAliasesForm is still hardcoded for personal accounts, so update
the NotAuthorizedError toast text used by the add/remove alias paths to say
“accounts you can manage” instead of “only for your own account.” Make the
change in the AccountMigrationAliasesForm flow so the organization entry point
uses the corrected wording consistently wherever the authorization failure
message is shown.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 55a84081-e1d1-46f1-b665-95fc7a9957a8

📥 Commits

Reviewing files that changed from the base of the PR and between 70adc97 and 6bddecc.

📒 Files selected for processing (4)
  • graphql/account.test.ts
  • graphql/account.ts
  • graphql/schema.graphql
  • web-next/src/routes/(root)/[handle]/settings/account.tsx

Comment thread web-next/src/routes/(root)/[handle]/settings/account.tsx Outdated
@dahlia

dahlia commented Jun 27, 2026

Copy link
Copy Markdown
Member Author

@codex review

@dahlia dahlia self-assigned this Jun 27, 2026
@dahlia dahlia added enhancement New feature or request web-next The new web frontend (SolidStart) graphql GraphQL API server labels Jun 27, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6bddecced0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread graphql/account.ts
dahlia added 3 commits June 27, 2026 14:15
The accountId input descriptions already note that organization
admins may manage migration aliases, but the mutation-level
descriptions for addAccountMigrationAlias and removeAccountMigrationAlias
still said the alias belonged to the authenticated viewer's own local
account. That left the generated schema docs implying organization-admin
calls are unsupported even though the resolvers now allow them. Reword
both descriptions to cover any account the viewer can manage and
regenerate graphql/schema.graphql.

hackers-pub#321 (comment)

Assisted-by: Claude Code:claude-opus-4-8
Adding the migration card to the organization branch of the account
settings Switch left it duplicated verbatim with the personal branch.
Extract it into a shared AccountMigrationCard component used by both
branches. Keeping it as a component (rather than splitting the Switch
into two around a shared card) preserves the personal branch's existing
viewer gating without rendering the card outside that boundary.

hackers-pub#321 (comment)

Assisted-by: Claude Code:claude-opus-4-8
The account migration form is now shared by organization accounts, but
its NotAuthorizedError toast still read "only for your own account" in
both the add and remove paths. That is misleading for organization
admins, who can manage migration for accounts they do not own. Reword it
to "accounts you can manage" and update the locale catalogs.

hackers-pub#321 (comment)

Assisted-by: Claude Code:claude-opus-4-8
@dahlia

dahlia commented Jun 27, 2026

Copy link
Copy Markdown
Member Author

@codex review

@dahlia

dahlia commented Jun 27, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request extends the account migration alias feature to allow organization administrators to manage migration aliases for organization accounts. It updates the GraphQL mutations addAccountMigrationAlias and removeAccountMigrationAlias to authorize organization admins, adds corresponding integration tests, and updates the frontend settings page to display the migration card for both personal and organization accounts. The feedback suggests aligning the newly introduced AccountMigrationCard component with the repository's style guide by defining an interface for its props and using props destructuring.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread web-next/src/routes/(root)/[handle]/settings/account.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
web-next/src/routes/(root)/[handle]/settings/account.tsx (1)

1598-1616: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use an interface for the new card props.

AccountMigrationCard is a new component in this diff, and the repo TS guideline asks for component props to use interfaces instead of an inline object type.

Suggested change
+interface AccountMigrationCardProps {
+  account: AccountPageAccount;
+}
+
-function AccountMigrationCard(props: { account: AccountPageAccount }) {
+function AccountMigrationCard(props: AccountMigrationCardProps) {

As per coding guidelines, "Use interfaces for component props (e.g., ButtonProps)."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web-next/src/routes/`(root)/[handle]/settings/account.tsx around lines 1598 -
1616, AccountMigrationCard currently defines its props with an inline object
type, which violates the component props guideline. Introduce a named interface
for the props used by AccountMigrationCard (referencing AccountPageAccount for
the account field), update the function signature to use that interface, and
keep the component behavior unchanged.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@web-next/src/routes/`(root)/[handle]/settings/account.tsx:
- Around line 1598-1616: AccountMigrationCard currently defines its props with
an inline object type, which violates the component props guideline. Introduce a
named interface for the props used by AccountMigrationCard (referencing
AccountPageAccount for the account field), update the function signature to use
that interface, and keep the component behavior unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 48cda296-1fe2-4e62-bb40-fa7bdd724356

📥 Commits

Reviewing files that changed from the base of the PR and between 6bddecc and 44ae75c.

📒 Files selected for processing (8)
  • graphql/account.ts
  • graphql/schema.graphql
  • web-next/src/locales/en-US/messages.po
  • web-next/src/locales/ja-JP/messages.po
  • web-next/src/locales/ko-KR/messages.po
  • web-next/src/locales/zh-CN/messages.po
  • web-next/src/locales/zh-TW/messages.po
  • web-next/src/routes/(root)/[handle]/settings/account.tsx
✅ Files skipped from review due to trivial changes (3)
  • web-next/src/locales/ja-JP/messages.po
  • web-next/src/locales/ko-KR/messages.po
  • graphql/schema.graphql
🚧 Files skipped from review as they are similar to previous changes (1)
  • graphql/account.ts

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Can't wait for the next one!

Reviewed commit: 44ae75c8ac

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Give AccountMigrationCard a named AccountMigrationCardProps interface
instead of an inline object type, matching the style guide and the other
prop interfaces in this file (AccountMigrationAliasesFormProps,
AccountDeletionFormProps). Props are still accessed via props.account
rather than destructured, since destructuring breaks reactivity in Solid.

hackers-pub#321 (comment)

Assisted-by: Claude Code:claude-opus-4-8
@dahlia

dahlia commented Jun 27, 2026

Copy link
Copy Markdown
Member Author

@codex review

@dahlia

dahlia commented Jun 27, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request extends the account migration alias feature to support organization accounts, allowing organization administrators to manage migration aliases. It updates the backend authorization logic to check if the viewer can manage the account, prevents leaking account existence by returning NotAuthorizedError for nonexistent accounts, and updates the GraphQL schema and translations accordingly. On the frontend, the migration settings are extracted into a reusable AccountMigrationCard component. The reviewer noted that this new component should use props destructuring instead of accessing properties directly from the props object, as specified in the repository style guide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread web-next/src/routes/(root)/[handle]/settings/account.tsx
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

Reviewed commit: 23349881fd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@dahlia dahlia merged commit 064561b into hackers-pub:main Jun 27, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request graphql GraphQL API server web-next The new web frontend (SolidStart)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant