# Architecture report — web

Generated 2026-09-17T21:04:34.927Z

## Summary

**web** — next15 app ts | tw3 @radix-ui/react-slot | swr react-hook-form+zod | next-auth prisma | vitest+playwright | turbopack
3620 source files in 21 modules, 12806 internal imports.
6 framework errors, 18 warnings, 1 dependency cycle, 7 near-duplicate groups.
The whole project was scanned.

## Modules

| Module | Files | Imports in | Imports out |
| --- | --- | --- | --- |
| lib | 1228 | 5763 | 30 |
| ui | 815 | 1094 | 1264 |
| app/(ee) | 680 | 2 | 2926 |
| app/app.dub.co | 412 | 2 | 1477 |
| app/api | 161 | 1 | 682 |
| tests | 126 | 0 | 109 |
| scripts | 110 | 0 | 235 |
| playwright | 56 | 2 | 89 |
| app/(root) | 10 | 0 | 9 |
| (root) | 7 | 0 | 12 |
| app/password | 4 | 0 | 7 |
| app/inspect | 2 | 0 | 2 |
| app/proxy | 1 | 0 | 1 |
| app/stats | 1 | 0 | 1 |
| app/banned | 1 | 0 | 6 |

## Two-way coupling

These module pairs import each other. A layered design usually wants one direction only.
- ui and lib (1264 imports)
- lib and ui (30 imports)

## Dependency cycles

- lib -> ui
  e.g. lib/actions/partners/create-reward.ts imports ui/partners/format-reward-description.ts

## Framework findings

| Severity | Location | Problem |
| --- | --- | --- |
| error | lib/api/create-id.ts:2 | 'use client' file imports the Node built-in "crypto", which cannot run in the browser. |
| error | lib/api/rewards/custom-reward-utils.ts:7 | 'use client' file imports the Node built-in "crypto", which cannot run in the browser. |
| error | lib/auth/sso-login-programs.ts:8 | process.env.FRAMER_CLIENT_ID is undefined in the browser. Only NEXT_PUBLIC_* variables reach client code. |
| error | lib/auth/sso-login-programs.ts:9 | process.env.FRAMER_CLIENT_SECRET is undefined in the browser. Only NEXT_PUBLIC_* variables reach client code. |
| error | lib/auth/sso-login-programs.ts:22 | process.env.BEEHIIV_CLIENT_ID is undefined in the browser. Only NEXT_PUBLIC_* variables reach client code. |
| error | lib/swr/use-workspace-preferences.ts:3 | 'use client' only counts as a directive at the top of the file, above every import. |
| warning | app/(ee)/admin.dub.co/(dashboard)/programs/program-categories-list.tsx:100 | useState needs 'use client'. No importer of this file declares the directive, so it looks like a Server Component. |
| warning | app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/invite-network-partner-sheet.tsx:65 | useState needs 'use client'. No importer of this file declares the directive, so it looks like a Server Component. |
| warning | app/app.dub.co/(dashboard)/[slug]/(ee)/settings/domains/email/email-domain-card.tsx:31 | useState needs 'use client'. No importer of this file declares the directive, so it looks like a Server Component. |
| warning | lib/actions/partners/get-conversion-score.ts:1 | This looks like a server action module but never declares 'use server'. |
| warning | lib/actions/partners/throw-if-negative-network-balance.ts:1 | This looks like a server action module but never declares 'use server'. |
| warning | lib/actions/partners/trigger-aggregate-due-commissions.ts:1 | This looks like a server action module but never declares 'use server'. |
| warning | lib/actions/throw-if-no-permission.ts:1 | This looks like a server action module but never declares 'use server'. |
| warning | ui/guides/guide-selector.tsx:46 | useState needs 'use client'. No importer of this file declares the directive, so it looks like a Server Component. |
| warning | ui/layout/sidebar/icons/gear.tsx:9 | useEffect needs 'use client'. No importer of this file declares the directive, so it looks like a Server Component. |
| warning | ui/links/link-builder/draft-controls.tsx:46 | useState needs 'use client'. No importer of this file declares the directive, so it looks like a Server Component. |
| warning | ui/modals/add-customer-modal.tsx:60 | useState needs 'use client'. No importer of this file declares the directive, so it looks like a Server Component. |
| warning | ui/modals/delete-email-domain-modal.tsx:126 | useState needs 'use client'. No importer of this file declares the directive, so it looks like a Server Component. |
| warning | ui/modals/google-oauth-modal.tsx:19 | useState needs 'use client'. No importer of this file declares the directive, so it looks like a Server Component. |
| warning | ui/modals/identity-sync-confirm-modal.tsx:144 | useState needs 'use client'. No importer of this file declares the directive, so it looks like a Server Component. |
| warning | ui/modals/link-builder/ab-testing/ab-testing-modal.tsx:643 | useState needs 'use client'. No importer of this file declares the directive, so it looks like a Server Component. |
| warning | ui/modals/link-builder/ab-testing/traffic-split-slider.tsx:54 | useEffect needs 'use client'. No importer of this file declares the directive, so it looks like a Server Component. |
| warning | ui/modals/link-builder/webhooks-modal.tsx:146 | useState needs 'use client'. No importer of this file declares the directive, so it looks like a Server Component. |
| warning | ui/partners/update-partner-tags-modal.tsx:61 | useRef needs 'use client'. No importer of this file declares the directive, so it looks like a Server Component. |

## Conventions

Maturity: established.

Enforced:
- 100% of tests (141) sit beside the file they cover rather than in __tests__/.

Observed (not enforced):
- 76% of page and layout files (246) are server components.

Where things live:
- `icons/` holds component files (56)
- `count/` holds route files (30)
- `utils/` holds util files (88)
- `modals/` holds hook files (136)
- `export/` holds route files (12)
- `hooks/` holds hook files (12)
- `callback/` holds route files (10)
- `api/` holds util files (37)

## Near-duplicate files

Roughly 538 lines could be removed by consolidating these.
- 100% similar:
  - app/app.dub.co/(dashboard)/[slug]/(ee)/links/customers/[customerId]/sales/page-client.tsx
  - app/app.dub.co/(dashboard)/[slug]/(ee)/program/customers/[customerId]/sales/page-client.tsx
- 100% similar:
  - playwright/partners/auth.setup.ts
  - playwright/workspaces/auth.setup.ts
- 100% similar:
  - ui/layout/page-content/toggle-side-panel-button.tsx
  - ui/messages/toggle-side-panel-button.tsx
- 100% similar:
  - ui/partners/groups/design/application-form/fields/form-control.tsx
  - ui/submitted-leads/form-fields/form-control.tsx
- 93% similar:
  - app/app.dub.co/(dashboard)/[slug]/(ee)/links/customers/[customerId]/earnings/page.tsx
  - app/app.dub.co/(dashboard)/[slug]/(ee)/program/customers/[customerId]/earnings/page-client.tsx
- 82% similar:
  - tests/utils/integration-member.ts
  - tests/utils/integration-old.ts
- 82% similar:
  - ui/partners/groups/design/application-form/modals/generate-lander-modal.tsx
  - ui/partners/groups/design/lander/modals/generate-lander-modal.tsx

## Most depended-on files

- lib/prisma/index.ts (910 importers)
- lib/types.ts (732 importers)
- lib/swr/use-workspace.ts (454 importers)
- lib/api/errors.ts (322 importers)
- lib/auth/index.ts (279 importers)
- lib/api/create-id.ts (158 importers)
- lib/api/programs/get-default-program-id-or-throw.ts (155 importers)
- ui/shared/icons/index.tsx (129 importers)
- lib/cron/index.ts (128 importers)
- lib/actions/safe-action.ts (123 importers)

## Imported by nothing

Entry points and tests are excluded, so these are candidates for deletion.
- app/(ee)/admin.dub.co/(dashboard)/programs/program-categories-list.tsx
- app/(ee)/app.dub.co/embed/referrals/bounties/performance-section.tsx
- app/(ee)/app.dub.co/embed/referrals/bounties/submission-fields.tsx
- app/(ee)/partners.dub.co/(dashboard)/programs/[programSlug]/(enrolled)/bounties/[bountyId]/bounty-performance-section.tsx
- app/(ee)/partners.dub.co/(onboarding)/onboarding/payouts/payout-provider.tsx
- app/api/ai/sync-embeddings/fetch-plausible-pageviews.ts
- app/api/callback/plain/utils.ts
- app/app.dub.co/(dashboard)/[slug]/(ee)/program/analytics/program-analytics-nav.tsx
- app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/campaign-recipients-selector.tsx
- app/app.dub.co/(dashboard)/[slug]/(ee)/program/coming-soon-page.tsx
- app/app.dub.co/(dashboard)/[slug]/(ee)/program/customers/customers-dropdown-menu.tsx
- app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners-graphic.tsx
- app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/invite-network-partner-sheet.tsx
- app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/invite-sheet-ui.tsx
- app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/program-payout-holding-periods.tsx
