Skip to content

feat(settings): add a private-account toggle with follow requests - #81

Merged
Adron merged 1 commit into
mainfrom
feat/private-account-toggle
Sep 17, 2026
Merged

Adron merged 1 commit into
mainfrom
feat/private-account-toggle

Conversation

@Adron

@Adron Adron commented Sep 15, 2026

Copy link
Copy Markdown
Member

Summary

Closes #48. Adds the Private account setting to iOS. It is a real server-side gate — it drives
follow requests instead of instant follows and restricts profile/wall visibility — and iOS already
shipped FollowRequestsView, so an iOS-only user could receive follow requests without any way to
turn the producing setting on or off.

⚠️ Stacked on #75. Base is fix/default-publicly-visible-wire-key, not main — both PRs edit
updateUserSettings. Merge #75 first, then this retargets to main cleanly.

What's included

  • Models/User.swift: decode isPrivateAccount: Bool?. Confirmed GET /api/user already returns it
    (lib/auth/user-select.ts names isPrivateAccount), so no backend work was needed.
  • Services/APIClient.swift: updateUserSettings takes isPrivateAccount, sent camelCase via
    patchCamel — the exact key app/api/user/update/route.ts:33 destructures.
  • Views/SettingsView.swift: a Privacy section with the toggle, a footer ("New followers must be
    approved. Your posts stay visible only to approved followers.") and a Follow requests
    NavigationLink shown only while the account is private.
  • Rollback on failure reuses the existing syncFromUser() path, matching postingSection.

Testing

  • xcodebuild … -parallel-testing-enabled NO -skip-testing:InterlinedListTests/E2EReadOnlyTests test
    1153 tests, 0 failures (+4 new).
  • New: test_updateUserSettings_sendsIsPrivateAccountKey (asserts the body key is exactly
    isPrivateAccount), test_updateUserSettings_omitsIsPrivateAccountWhenNotSet,
    test_decodesIsPrivateAccount, test_isPrivateAccount_isNilWhenAbsent.

Not verified here

The round-trip acceptance criteria — set on iOS → visible on the web, and a new follower landing in
FollowRequestsView — need a live logged-in account and were not exercised. The wire key and decode
are covered by unit tests.

🤖 Generated with Claude Code

An iOS-only user could receive follow requests (FollowRequestsView ships) but
had no way to turn on the setting that produces them — `isPrivateAccount` was
neither decoded nor writable from the app.

- decode `isPrivateAccount` on `User`; `GET /api/user` already returns it via
  `userSelect`
- extend `updateUserSettings` with `isPrivateAccount` (camelCase body, the key
  `PATCH /api/user/update` destructures)
- add a Privacy section to `SettingsView`: the toggle, a footer explaining what
  private means, and a Follow requests link that appears only while private, so
  the setting and its consequence live together
- failures roll the toggle back through the existing `syncFromUser` path

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017bss5MgZa7Jvj2m9zdaUd1
Base automatically changed from fix/default-publicly-visible-wire-key to main September 17, 2026 03:21
@Adron
Adron merged commit 2a11f58 into main Sep 17, 2026
@Adron
Adron deleted the feat/private-account-toggle branch September 17, 2026 03:21
Adron added a commit that referenced this pull request Sep 17, 2026
Conflict confined to project.pbxproj. Both sides were pure additions — this
branch registers DMConversation.swift, APIClient+DirectMessages.swift and
APIClientDMConversationsTests.swift; main brought the files from #75/#81/#82/
#83/#84 — so both sides were kept.

Integrity checked after resolving: no Sources entry without a PBXBuildFile, no
build file pointing at a missing fileRef, no duplicate object definitions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017bss5MgZa7Jvj2m9zdaUd1
Adron added a commit that referenced this pull request Sep 17, 2026
Conflict confined to project.pbxproj. Both sides were pure additions — this
branch registers ListRowSorting.swift and ListRowSortingTests.swift, main
brought the files from #75/#81/#82/#83/#84 — so both sides were kept.

Integrity checked after resolving: no Sources entry without a PBXBuildFile, no
build file pointing at a missing fileRef, no duplicate object definitions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017bss5MgZa7Jvj2m9zdaUd1
Adron added a commit that referenced this pull request Sep 17, 2026
Conflict confined to project.pbxproj. Both sides were pure additions — this
branch registers DocumentPresence.swift, APIClient+DocumentPresence.swift,
DocumentPresenceService.swift and their two test files; main brought the files
from #75/#81/#82/#83/#84 — so both sides were kept.

DocumentsView.swift auto-merged, since #83 (seed default templates) edits the
template picker and this branch edits the document detail toolbar. Verified
after merging that both survive: the subscriber-gated "Add the default
templates" action and the presence chip are each still wired.

Integrity checked after resolving: no Sources entry without a PBXBuildFile, no
build file pointing at a missing fileRef, no duplicate object definitions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017bss5MgZa7Jvj2m9zdaUd1
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.

W2: Private-account toggle in Settings (isPrivateAccount)

1 participant