Skip to main content

Overview

This example demonstrates how to structure a complete e-commerce application with shopping features, user authentication, and product management. The architecture clearly communicates business functionality through its organization.

Project Structure

The Scope Rule determines every placement decision: code used by 2+ features goes in shared directories, code used by 1 feature stays local.
src/
  app/
    (auth)/                        # Authentication feature
      login/
        page.tsx                   # /login route
        _components/               # Login-specific components
          login-form.tsx
      register/
        page.tsx                   # /register route
        _components/               # Register-specific components
          register-form.tsx
      _components/                 # Shared auth components
        social-login.tsx           # Used by login & register
      _hooks/                      # Auth hooks
        use-auth.ts
      _actions/                    # Auth server actions
        auth-actions.ts
      layout.tsx                   # Auth layout

    (shop)/                        # E-commerce feature
      shop/
        page.tsx                   # /shop route
        _components/               # Shop-specific components
          product-list.tsx
          product-filter.tsx
      cart/
        page.tsx                   # /cart route
        _components/               # Cart-specific components
          cart-item.tsx
          cart-summary.tsx
      wishlist/
        page.tsx                   # /wishlist route
        _components/               # Wishlist-specific components
          wishlist-item.tsx
          wishlist-grid.tsx
      _hooks/                      # Shop hooks
        use-products.ts
        use-cart.ts
        use-wishlist.ts
      _actions/                    # Shop server actions
        product-actions.ts
        cart-actions.ts
        wishlist-actions.ts
      layout.tsx                   # Shop layout

    api/                           # API routes
      auth/route.ts
      products/route.ts
      cart/route.ts

    page.tsx                       # Home page
    layout.tsx                     # Root layout

  shared/                          # ONLY for 2+ route groups
    components/
      ui/                          # Reusable UI components
        button.tsx
        card.tsx
        input.tsx
      product-card.tsx             # Used in shop, cart, wishlist
      cart-widget.tsx              # Used in multiple routes
    hooks/
      use-local-storage.ts
      use-debounce.ts

  lib/                             # Utilities
    auth.ts
    db.ts
    utils.ts
    validations.ts

Key Architectural Decisions

Product Card Component

Usage: Shop page, Cart page, Wishlist page (3 locations) Decision: Shared component Reasoning: Used by multiple features within the shop domain. This is a perfect example of the Scope Rule - since it’s used in 2+ places, it MUST go in the shared directory.

Cart Actions

Usage: Cart page only Decision: Local to cart feature Reasoning: These actions are specific to cart functionality. Even though the cart is accessed from multiple places, the cart-specific logic stays local.

Social Login Component

Usage: Login page, Register page Decision: Shared within auth feature Reasoning: Used by 2 pages within the same feature group, so it goes in the feature’s shared components directory.

Screaming Architecture Benefits

Looking at this structure, you immediately understand:
  • This is an e-commerce application
  • It has authentication features (login, register)
  • It has shopping features (products, cart, wishlist)
  • Each feature is self-contained with its own components and logic
  • Shared code is clearly marked and justified by 2+ usage

Scalability Patterns

Easy Feature Addition

Add new features like “orders” or “reviews” as new route groups or feature directories without affecting existing code.

Clear Dependencies

Shared components make dependencies explicit. You know exactly what’s being reused across features.

Team Ownership

Each feature can be owned by a different team. Clear boundaries prevent conflicts.

Refactoring Safety

Move entire features as units. Local code moves together, reducing the risk of breaking changes.

Migration Strategy

If you have an existing e-commerce application with everything in a single components/ folder:
  1. Identify features - Group routes by business functionality (auth, shop, etc.)
  2. Analyze usage - For each component, count how many features use it
  3. Move local first - Start by moving components used by only 1 feature
  4. Extract shared - Move components used by 2+ features to shared directories
  5. Update imports - Use path aliases to keep imports clean
  6. Validate structure - Ensure the structure “screams” what your app does

Common Anti-patterns to Avoid

  • Everything in shared - Don’t put components in shared “just in case”
  • Premature abstraction - Start local, move to shared only when needed
  • Technical naming - Use business terms (“shop”, “cart”) not technical ones (“data”, “views”)
  • Deep nesting - Keep structures flat within features for easy navigation

Build docs developers (and LLMs) love