feat(server): Stage 1 brand-domain resolver (#4159)#4299
Merged
Conversation
Introduces the single read surface for an org's brand-identity primary domain. Reads organization_domains.is_primary=true first (the canonical Stage 1 source after Stage 0's backfill), falls back to member_profiles.primary_brand_domain for any org Stage 0 missed. Logs a warn on every fallback so we can spot remaining drift before Stage 2 drops the column. Two surfaces: - getBrandPrimaryDomain(orgId): single-org lookup - getBrandPrimaryDomainsForOrgs(orgIds): batched, for list views No call site changes here. Subsequent PRs migrate the ~14 read sites identified in the spec. Spec: specs/domain-column-rationalization.md (#4215). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| */ | ||
|
|
||
| import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest'; | ||
| import { initializeDatabase, getPool, closeDatabase } from '../../src/db/client.js'; |
Code-reviewer: - Refactor test setup so beforeAll/afterAll runs once per file (was once per describe — duplicate runMigrations + double pool init). - Aggregate batch fallback warns into one log line per call instead of one-per-row. Keeps signal usable on large batches. - Add tests for verified=false is_primary=true (documents that the resolver doesn't filter on verified — verified is enforced at write time) and multiple-is_primary=true rows (documents the don't-crash contract on data anomalies). - Tighten doc comment: missing orgs are absent from the result map, not present with undefined values. Security-reviewer: - Add explicit AUTHORIZATION note to the file's doc comment. - Replace LIMIT 1 (without ORDER BY) with full-result + multi-primary detection. logger.error if the Stage 0 "exactly one" invariant is broken; still return a valid primary so callers don't crash on the anomaly. Same shape applied to the batch variant. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 9, 2026
bokelley
added a commit
that referenced
this pull request
May 9, 2026
….3) (#4303) * feat(http): dashboard + brand-feeds reads use resolver (#4159 Stage 1.3) Migrates four read sites: - GET /api/members: batched resolver lookup; brand-primary keyed by org_id rather than per-row column. - GET /api/members/carousel: same batched pattern. - GET /api/members/:slug: single-org resolver. - routes/brand-feeds.ts ownership check: replaces the member_profiles query in the owned-domains union with the resolver. orgDomains query unchanged (still walks all verified rows). The list endpoints are the first real users of the batched resolver variant getBrandPrimaryDomainsForOrgs from PR #4299. Behavior unchanged post-Stage-0 — brand-primary now keys on organization_domains.is_primary canonically with member_profiles fallback for orgs the backfill missed. 97 tests pass across the 6 affected test files. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * address Stage 1.3 review nits - Tighten the batched-resolver comment in /api/members (was 'three queries', should be 'constant number'; resolver itself can do 1-2). - Trim the brand-feeds ownership-gate comment. - TODO(#4159) noting the pre-existing verified-filter gap on the ownership gate. Set-equivalent to before this PR; worth fixing in Stage 2 when the column drops and the gate logic gets revisited. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- 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
Stage 1 of #4159 (spec at specs/domain-column-rationalization.md). Introduces the single read surface for an org's brand-identity primary domain.
Read order:
organization_domains.is_primary=true(Stage 1 canonical, post-Stage-0 backfill)member_profiles.primary_brand_domain(transition fallback; logs a warn on every hit so we can spot drift)Once every read site has migrated to the resolver, Stage 2 drops the column and the fallback becomes a no-op (and gets removed). Stage 3 introduces the matching
setPrimaryDomainwriter.What's here
server/src/services/brand-domain-resolver.ts— the resolver. Two surfaces (single + batched).server/tests/integration/brand-domain-resolver.test.ts— 9 cases covering primary-wins, fallback path, null/empty, mixed batches.What's NOT here
The ~14 call sites that read
member_profiles.primary_brand_domaindirectly. Those migrate in subsequent PRs — splitting them keeps each rewrite small and reviewable. Nothing breaks during the gap because writers continue to dual-write.Survey shows fallback should be ~empty in prod
Post-Stage-0 (this thread): 91 of 158 profiles have
brand_primary == organization_domains.is_primary, 66 are NULL, 1 (HYPD orphan) is divergent. So the fallback path will fire only on:Both are watchable signals via the warn log.
Test plan
getBrandPrimaryDomain fell backwarns to spot any drift; should be near-zero🤖 Generated with Claude Code