BetaViberTest is in active development — expect breaking changes.
Overview
DocsRulesSeparation of Concerns
#005mediumArchitecture & Structure

Separation of Concerns

Detects code that mixes UI, data fetching, and business logic layers.

Rule ID:separation-of-concerns

Examples#

BadUI component with data fetching
// UserProfile.tsx — UI + data fetching + business logic
export function UserProfile({ userId }: { userId: string }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => setUser(data));
  }, [userId]);

  const fullName = user
    ? `${user.firstName} ${user.lastName}`
    : '';
  const isAdmin = user?.roles.includes('admin');

  return (
    <div>
      <h1>{fullName}</h1>
      {isAdmin && <AdminBadge />}
    </div>
  );
}
GoodSeparated into layers
// hooks/use-user.ts — data fetching
export function useUser(userId: string) {
  const [user, setUser] = useState<User | null>(null);
  useEffect(() => {
    userService.getById(userId).then(setUser);
  }, [userId]);
  return user;
}

// lib/user-utils.ts — business logic
export function getFullName(user: User) {
  return `${user.firstName} ${user.lastName}`;
}
export function isAdmin(user: User) {
  return user.roles.includes('admin');
}

// UserProfile.tsx — UI only
export function UserProfile({ userId }: { userId: string }) {
  const user = useUser(userId);
  if (!user) return <Skeleton />;
  return (
    <div>
      <h1>{getFullName(user)}</h1>
      {isAdmin(user) && <AdminBadge />}
    </div>
  );
}

What It Detects#

mediumUI component (.tsx/.jsx) with direct data fetching (fetch, axios, prisma, supabase)
UI component contains data fetching logic

Fix: Move data fetching to a custom hook (useXxx) or service layer. Components should only handle rendering.

mediumRoute handler with >5 function definitions
Route handler contains {N} function definitions — too much business logic

Fix: Extract business logic to a service/use-case layer.

mediumRaw SQL outside data-layer directories
Raw SQL ({keyword}) found outside data access layer

Fix: Move database queries to a repository or data access layer.

Exclusions#

The following are automatically excluded from this rule:

  • Auth-related files (login, signup, etc.) where SDK calls are expected

Configuration#

This rule is enabled by default. To disable it:

.vibertestrc.jsonjson
{
  "rules": {
    "separation-of-concerns": {
      "enabled": false
    }
  }
}