Graphify audit resolutions โ alby-studio
Context
Follow-up analysis on the 3 actionable items surfaced by graphify-audit-2026-05-21. For each god-node, applies the deletion test from external/improve-codebase-architecture skill and assigns a verdict: leave-as-is / refactor-low-priority / refactor-with-scope.
Item 1 โ cn() god-utility (88 edges) โ LEAVE AS-IS
Source
// src/lib/utils.ts L4
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
Deletion test
If deleted, complexity moves into 88 places where every component manually composes twMerge(clsx(...)). Worse, not better.
Verdict
This is the canonical shadcn convention โ moving off cn() means migrating off shadcn entirely. The 88 edges aren't a code smell; they're the expected shape of a design-system-driven UI.
Action
None. Awareness only: this is the largest blast radius for any future class-merging or design-system migration.
Item 2 โ getVendorBySlug() (21 edges) โ REFACTOR LOW PRIORITY
Source
// src/lib/services/storefront.service.ts L3
export async function getVendorBySlug(slug: string) {
return prisma.vendorProfile.findUnique({
where: { storeSlug: slug },
include: { storeTheme: true },
});
}
All 21 call sites
| File | Line | Pattern |
|---|---|---|
src/app/api/store/[slug]/products/[productSlug]/route.ts | 9 | const vendor = await getVendorBySlug(params.slug) |
src/app/api/store/[slug]/checkout/route.ts | 12 | same |
src/app/api/store/[slug]/cart/route.ts | 21, 37 | same (ร2 in one file) |
src/app/(storefront)/store/[slug]/layout.tsx | 12 | same |
src/app/(storefront)/store/[slug]/page.tsx | 10 | same |
src/app/(storefront)/store/[slug]/shop/page.tsx | 13 | same |
src/app/(storefront)/store/[slug]/checkout/success/page.tsx | 26 | same |
src/app/(storefront)/store/[slug]/blog/page.tsx | 11 | same |
src/app/(storefront)/store/[slug]/blog/[postSlug]/page.tsx | 13, 46 | same (ร2 in one file) |
Plus ~10 more identical-pattern imports โ all in the [slug] route tree.
Deletion test
If deleted, complexity moves into 21 places that each call prisma.vendorProfile.findUnique({ where, include }). Complexity stays the same (per file: same 3 lines of Prisma), but knowledge centralization is lost โ 21 places to update if the include needs to change.
โ deepening worthwhile, but the current function IS the deepening.
Verdict
Function is correctly placed. The 21 callsites are a feature, not a bug โ clear domain boundary (storefront โ vendor lookup).
Lower-priority improvements (optional)
| Change | Effort | Value |
|---|---|---|
Extract a typed VendorWithTheme return interface | 15 min | Type-check call sites better |
| Move to a Next.js middleware that injects vendor into request context | 4-6 hrs | Eliminates 21 repeated calls but adds middleware complexity. Probably not worth it for a single 4-line function. |
| Add Redis cache (TTL ~5 min) โ every storefront page hit calls this | 2 hrs | Real perf win at scale (>100 vendors active). Defer until measured. |
Action
- [ ] Add the
VendorWithThemetyped interface (15 min) โ call thisPhase 4 polishnot a priority blocker - [ ] Defer middleware refactor + Redis cache until friendly-beta data shows perf characteristics
Item 3 โ authOptions (30 edges) โ DOCUMENTED MIGRATION SCOPE
Source
// src/lib/auth.ts L8
export const authOptions: NextAuthOptions = {
adapter: PrismaAdapter(prisma),
session: { strategy: "jwt", maxAge: 30 * 24 * 60 * 60 },
providers: [CredentialsProvider({...}), GoogleProvider({...})],
// ...
}
Call site breakdown
| Pattern | Count |
|---|---|
getServerSession(authOptions) (in API routes) | 29 |
NextAuth(authOptions) (1 NextAuth handler) | 1 |
import { authOptions } from "@/lib/auth" | 29 (one per consuming file) |
| Total touch surface for migration | 30 files |
Affected file categories
- 13 onboarding routes (
/api/onboarding/*) - 12 vendor routes (
/api/vendor/*) - 1 NextAuth catch-all (
/api/auth/[...nextauth]/route.ts) - ~4 store/storefront routes
Migration scope: alby-studio โ Aspire Hub OIDC SSO
Pre-conditions:
- Aspire Hub OIDC IdP is LIVE (confirmed per aspire-hub)
- smart-dashboard already migrated as the SSO pilot (2026-05-12, per MEMORY.md)
- alby-studio merchants are NOT Aspire Hub users (different audience โ merchants vs staff). So this migration applies to admin/staff routes only, NOT to vendor login.
Implication: TWO auth surfaces, not one
This is a critical finding for the migration plan:
- Vendor / merchant login โ STAYS on NextAuth + CredentialsProvider (these users aren't in Aspire Hub)
- Admin / staff console (the deferred
/adminUI from_STATUS.md) โ SHOULD use Aspire Hub OIDC from day 1, not NextAuth
So the 29 getServerSession(authOptions) calls in /api/onboarding/* and /api/vendor/* correctly belong to the merchant auth surface and don't need migration. Only the future /api/admin/* routes (currently non-existent) should adopt the Hub OIDC pattern.
Verdict
No migration scope for existing routes. The 30-edge blast radius is a non-issue โ it correctly serves the merchant audience. The migration concern was misplaced.
Action
- [ ] When
/adminUI is built (currently in_STATUS.mdpost-launch deferred list), wire it to Aspire Hub OIDC via the staff-portal helpers, NOT via the existingauthOptions. - [ ] Add a comment to
src/lib/auth.tsnoting: "This is the MERCHANT auth surface (NextAuth + Credentials/Google). Admin/staff routes use Aspire Hub OIDC โ see aspire-hub."
Combined action list (from this audit)
| # | Item | Effort | Priority |
|---|---|---|---|
| 1 | None for cn() โ current pattern is correct | โ | โ |
| 2 | Extract typed VendorWithTheme return interface for getVendorBySlug() | 15 min | Phase 4 polish |
| 3 | Add comment to src/lib/auth.ts clarifying merchant vs staff auth boundary | 2 min | Now |
| 4 | When /admin UI is built, use Aspire Hub OIDC (not the existing authOptions) | (future) | Post-launch |
Open production-gating items (from _STATUS.md, not this audit)
| # | Item | Owner | Status |
|---|---|---|---|
| A | Stripe live-mode keys (current: Sandbox) | Kom | โธ blocked on Stripe Connect activation |
| B | Legal counsel review of /terms /privacy /refund-policy /vendor-agreement | Kom + lawyer | โธ blocked on counsel |
| C | Stripe webhook cleanup (delete alby-studio-empowering-rhythm-thin duplicate) | Kom | โธ Stripe MCP wired to wrong account (Zinga eSIM), Kom-only |
| D | Friendly beta โ 3-5 real vendors through full flow | Kom | โธ recruitment task |
Related
- graphify-audit-2026-05-21 โ the audit that surfaced these items
- aspire-hub โ OIDC IdP target for future /admin routes
external/improve-codebase-architectureskill โ the deletion test methodology used here