CtrlK
BlogDocsLog inGet started
Tessl Logo

jbvc/frontend-dev-guidelines

Opinionated frontend development standards for modern React + TypeScript applications. Covers Suspense-first data fetching, lazy loading, feature-based architecture, MUI v7 styling, TanStack Router, performance optimization, and strict TypeScript practices.

67

Quality

67%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

file-organization.mdresources/

File Organization

Proper file and directory structure for maintainable, scalable frontend code in the the application.


features/ vs components/ Distinction

features/ Directory

Purpose: Domain-specific features with their own logic, API, and components

When to use:

  • Feature has multiple related components
  • Feature has its own API endpoints
  • Feature has domain-specific logic
  • Feature has custom hooks/utilities

Examples:

  • features/posts/ - Project catalog/post management
  • features/blogs/ - Blog builder and rendering
  • features/auth/ - Authentication flows

Structure:

features/
  my-feature/
    api/
      myFeatureApi.ts         # API service layer
    components/
      MyFeatureMain.tsx       # Main component
      SubComponents/          # Related components
    hooks/
      useMyFeature.ts         # Custom hooks
      useSuspenseMyFeature.ts # Suspense hooks
    helpers/
      myFeatureHelpers.ts     # Utility functions
    types/
      index.ts                # TypeScript types
    index.ts                  # Public exports

components/ Directory

Purpose: Truly reusable components used across multiple features

When to use:

  • Component is used in 3+ places
  • Component is generic (no feature-specific logic)
  • Component is a UI primitive or pattern

Examples:

  • components/SuspenseLoader/ - Loading wrapper
  • components/CustomAppBar/ - Application header
  • components/ErrorBoundary/ - Error handling
  • components/LoadingOverlay/ - Loading overlay

Structure:

components/
  SuspenseLoader/
    SuspenseLoader.tsx
    SuspenseLoader.test.tsx
  CustomAppBar/
    CustomAppBar.tsx
    CustomAppBar.test.tsx

Feature Directory Structure (Detailed)

Complete Feature Example

Based on features/posts/ structure:

features/
  posts/
    api/
      postApi.ts              # API service layer (GET, POST, PUT, DELETE)

    components/
      PostTable.tsx           # Main container component
      grids/
        PostDataGrid/
          PostDataGrid.tsx
      drawers/
        ProjectPostDrawer/
          ProjectPostDrawer.tsx
      cells/
        editors/
          TextEditCell.tsx
        renderers/
          DateCell.tsx
      toolbar/
        CustomToolbar.tsx

    hooks/
      usePostQueries.ts       # Regular queries
      useSuspensePost.ts      # Suspense queries
      usePostMutations.ts     # Mutations
      useGridLayout.ts              # Feature-specific hooks

    helpers/
      postHelpers.ts          # Utility functions
      validation.ts                 # Validation logic

    types/
      index.ts                      # TypeScript types/interfaces

    queries/
      postQueries.ts          # Query key factories (optional)

    context/
      PostContext.tsx         # React context (if needed)

    index.ts                        # Public API exports

Subdirectory Guidelines

api/ Directory

Purpose: Centralized API calls for the feature

Files:

  • {feature}Api.ts - Main API service

Pattern:

// features/my-feature/api/myFeatureApi.ts
import apiClient from '@/lib/apiClient';

export const myFeatureApi = {
    getItem: async (id: number) => {
        const { data } = await apiClient.get(`/blog/items/${id}`);
        return data;
    },
    createItem: async (payload) => {
        const { data } = await apiClient.post('/blog/items', payload);
        return data;
    },
};

components/ Directory

Purpose: Feature-specific components

Organization:

  • Flat structure if <5 components
  • Subdirectories by responsibility if >5 components

Examples:

components/
  MyFeatureMain.tsx           # Main component
  MyFeatureHeader.tsx         # Supporting components
  MyFeatureFooter.tsx

  # OR with subdirectories:
  containers/
    MyFeatureContainer.tsx
  presentational/
    MyFeatureDisplay.tsx
  blogs/
    MyFeatureBlog.tsx

hooks/ Directory

Purpose: Custom hooks for the feature

Naming:

  • use prefix (camelCase)
  • Descriptive of what they do

Examples:

hooks/
  useMyFeature.ts               # Main hook
  useSuspenseMyFeature.ts       # Suspense version
  useMyFeatureMutations.ts      # Mutations
  useMyFeatureFilters.ts        # Filters/search

helpers/ Directory

Purpose: Utility functions specific to the feature

Examples:

helpers/
  myFeatureHelpers.ts           # General utilities
  validation.ts                 # Validation logic
  transblogers.ts               # Data transblogations
  constants.ts                  # Constants

types/ Directory

Purpose: TypeScript types and interfaces

Files:

types/
  index.ts                      # Main types, exported
  internal.ts                   # Internal types (not exported)

Import Aliases (Vite Configuration)

Available Aliases

From vite.config.ts lines 180-185:

AliasResolves ToUse For
@/src/Absolute imports from src root
~typessrc/typesShared TypeScript types
~componentssrc/componentsReusable components
~featuressrc/featuresFeature imports

Usage Examples

// ✅ PREFERRED - Use aliases for absolute imports
import { apiClient } from '@/lib/apiClient';
import { SuspenseLoader } from '~components/SuspenseLoader';
import { postApi } from '~features/posts/api/postApi';
import type { User } from '~types/user';

// ❌ AVOID - Relative paths from deep nesting
import { apiClient } from '../../../lib/apiClient';
import { SuspenseLoader } from '../../../components/SuspenseLoader';

When to Use Which Alias

@/ (General):

  • Lib utilities: @/lib/apiClient
  • Hooks: @/hooks/useAuth
  • Config: @/config/theme
  • Shared services: @/services/authService

~types (Type Imports):

import type { Post } from '~types/post';
import type { User, UserRole } from '~types/user';

~components (Reusable Components):

import { SuspenseLoader } from '~components/SuspenseLoader';
import { CustomAppBar } from '~components/CustomAppBar';
import { ErrorBoundary } from '~components/ErrorBoundary';

~features (Feature Imports):

import { postApi } from '~features/posts/api/postApi';
import { useAuth } from '~features/auth/hooks/useAuth';

File Naming Conventions

Components

Pattern: PascalCase with .tsx extension

MyComponent.tsx
PostDataGrid.tsx
CustomAppBar.tsx

Avoid:

  • camelCase: myComponent.tsx
  • kebab-case: my-component.tsx
  • All caps: MYCOMPONENT.tsx

Hooks

Pattern: camelCase with use prefix, .ts extension

useMyFeature.ts
useSuspensePost.ts
useAuth.ts
useGridLayout.ts

API Services

Pattern: camelCase with Api suffix, .ts extension

myFeatureApi.ts
postApi.ts
userApi.ts

Helpers/Utilities

Pattern: camelCase with descriptive name, .ts extension

myFeatureHelpers.ts
validation.ts
transblogers.ts
constants.ts

Types

Pattern: camelCase, index.ts or descriptive name

types/index.ts
types/post.ts
types/user.ts

When to Create a New Feature

Create New Feature When:

  • Multiple related components (>3)
  • Has own API endpoints
  • Domain-specific logic
  • Will grow over time
  • Reused across multiple routes

Example: features/posts/

  • 20+ components
  • Own API service
  • Complex state management
  • Used in multiple routes

Add to Existing Feature When:

  • Related to existing feature
  • Shares same API
  • Logically grouped
  • Extends existing functionality

Example: Adding export dialog to posts feature

Create Reusable Component When:

  • Used across 3+ features
  • Generic, no domain logic
  • Pure presentation
  • Shared pattern

Example: components/SuspenseLoader/


Import Organization

Import Order (Recommended)

// 1. React and React-related
import React, { useState, useCallback, useMemo } from 'react';
import { lazy } from 'react';

// 2. Third-party libraries (alphabetical)
import { Box, Paper, Button, Grid } from '@mui/material';
import type { SxProps, Theme } from '@mui/material';
import { useSuspenseQuery, useQueryClient } from '@tanstack/react-query';
import { createFileRoute } from '@tanstack/react-router';

// 3. Alias imports (@ first, then ~)
import { apiClient } from '@/lib/apiClient';
import { useAuth } from '@/hooks/useAuth';
import { useMuiSnackbar } from '@/hooks/useMuiSnackbar';
import { SuspenseLoader } from '~components/SuspenseLoader';
import { postApi } from '~features/posts/api/postApi';

// 4. Type imports (grouped)
import type { Post } from '~types/post';
import type { User } from '~types/user';

// 5. Relative imports (same feature)
import { MySubComponent } from './MySubComponent';
import { useMyFeature } from '../hooks/useMyFeature';
import { myFeatureHelpers } from '../helpers/myFeatureHelpers';

Use single quotes for all imports (project standard)


Public API Pattern

feature/index.ts

Export public API from feature for clean imports:

// features/my-feature/index.ts

// Export main components
export { MyFeatureMain } from './components/MyFeatureMain';
export { MyFeatureHeader } from './components/MyFeatureHeader';

// Export hooks
export { useMyFeature } from './hooks/useMyFeature';
export { useSuspenseMyFeature } from './hooks/useSuspenseMyFeature';

// Export API
export { myFeatureApi } from './api/myFeatureApi';

// Export types
export type { MyFeatureData, MyFeatureConfig } from './types';

Usage:

// ✅ Clean import from feature index
import { MyFeatureMain, useMyFeature } from '~features/my-feature';

// ❌ Avoid deep imports (but OK if needed)
import { MyFeatureMain } from '~features/my-feature/components/MyFeatureMain';

Directory Structure Visualization

src/
├── features/                    # Domain-specific features
│   ├── posts/
│   │   ├── api/
│   │   ├── components/
│   │   ├── hooks/
│   │   ├── helpers/
│   │   ├── types/
│   │   └── index.ts
│   ├── blogs/
│   └── auth/
│
├── components/                  # Reusable components
│   ├── SuspenseLoader/
│   ├── CustomAppBar/
│   ├── ErrorBoundary/
│   └── LoadingOverlay/
│
├── routes/                      # TanStack Router routes
│   ├── __root.tsx
│   ├── index.tsx
│   ├── project-catalog/
│   │   ├── index.tsx
│   │   └── create/
│   └── blogs/
│
├── hooks/                       # Shared hooks
│   ├── useAuth.ts
│   ├── useMuiSnackbar.ts
│   └── useDebounce.ts
│
├── lib/                         # Shared utilities
│   ├── apiClient.ts
│   └── utils.ts
│
├── types/                       # Shared TypeScript types
│   ├── user.ts
│   ├── post.ts
│   └── common.ts
│
├── config/                      # Configuration
│   └── theme.ts
│
└── App.tsx                      # Root component

Summary

Key Principles:

  1. features/ for domain-specific code
  2. components/ for truly reusable UI
  3. Use subdirectories: api/, components/, hooks/, helpers/, types/
  4. Import aliases for clean imports (@/, ~types, ~components, ~features)
  5. Consistent naming: PascalCase components, camelCase utilities
  6. Export public API from feature index.ts

See Also:

  • component-patterns.md - Component structure
  • data-fetching.md - API service patterns
  • complete-examples.md - Full feature example

resources

common-patterns.md

complete-examples.md

component-patterns.md

data-fetching.md

file-organization.md

loading-and-error-states.md

performance.md

routing-guide.md

styling-guide.md

typescript-standards.md

SKILL.md

tile.json