feat: PersonDetail slackHandle + email (self/staff) — screen-gaps phase 2 (refs #83)#103
Merged
Merged
Conversation
Backend serializer + screen work to surface slackHandle (already in Person, public field) and email (in PrivateProfile, gated to self + staff) on /members/:slug. PersonService.get becomes async to incorporate the private-store read. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per specs/screens/person-detail.md authorization table: slackHandle is
a public Person field, exposed to all callers; email lives in
PrivateProfile and is gated to self + staff.
serializer — adds slackHandle + email to the PersonDetail shape.
slackHandle is read from the Person record directly;
email is supplied by the service via the new
opts.visibleEmail field.
service — PersonService.get becomes async. After the existing
in-memory work it conditionally awaits
privateStore.getProfile(personId) when the caller is
self or staff. Anonymous reads stay free of any
private-store touch.
plugin — PersonService gets the private store in its
constructor.
routes — GET /api/people/:slug and the PATCH-then-refetch site
pick up the awaits.
Seed fixture's Jane Doe now carries `slackHandle: 'jane-doe'` so
existing tests have a public-handle value to assert against. Three
new read-api cases: slackHandle visible to anonymous, email NOT
visible to anonymous, plus the original detail-shape test still passing.
Refs #83.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Renders a Contact section in the sidebar when either slackHandle or email is present: - "DM on Slack" link to https://<SLACK_TEAM_HOST>/team/<slackHandle> - Email rendered as a mailto: link Section is hidden entirely when neither field is set, so the sidebar stays clean for anonymous reads of contact-less profiles. The API client's PersonDetail type picks up the two new fields with load-bearing JSDoc explaining the email gating. Three new tests: section hidden when neither field set, Slack link href correct when slackHandle set, mailto href correct when email set. Refs #83. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
All 6 validation checkboxes ticked. Notes covers the seed-fixture augmentation (slackHandle on Jane Doe), the small PersonService.get caller surface (only 2 call sites), and the Contact-section-hides- when-empty behavior. Follow-ups: phase 3 (/pages/:slug content) and phase 4 (/buzz/new form) named for later plans. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI lint caught what my local sweep missed — beforeEach was imported but never used (afterEach handles cleanup per-test; setup is inside each it() block via makeFetchMock). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Second phase of #83 — backend serializer + screen work to surface the two PersonDetail fields the audit flagged.
`PersonService.get` becomes `async` so it can do the conditional private-store read. Anonymous reads stay free of any private-store touch.
Test plan
🤖 Generated with Claude Code