# ADR-044: Frontend Feature Organization Pattern

**Date**: 2026-01-09

**Status**: Accepted

**Implemented**: 2026-01-09

## Context

The React frontend has grown to include multiple distinct features:

- Flyer viewing and management
- Shopping list creation
- Budget tracking and charts
- Voice assistant
- User personalization
- Admin dashboard

Without clear organization, code becomes scattered across generic folders (`/components`, `/hooks`, `/utils`), making it hard to:

1. Understand feature boundaries
2. Find related code
3. Refactor or remove features
4. Onboard new developers

## Decision

We will adopt a **feature-based folder structure** where each major feature is self-contained in its own directory under `/features`. Shared code lives in dedicated top-level folders.

### Design Principles

- **Colocation**: Keep related code together (components, hooks, types, utils).
- **Feature Independence**: Features should minimize cross-dependencies.
- **Shared Extraction**: Only extract to shared folders when truly reused.
- **Flat Within Features**: Avoid deep nesting within feature folders.

## Implementation Details

### Directory Structure

```
src/
├── features/                    # Feature modules
│   ├── flyer/                   # Flyer viewing/management
│   │   ├── components/
│   │   ├── hooks/
│   │   ├── types.ts
│   │   └── index.ts
│   ├── shopping/                # Shopping lists
│   │   ├── components/
│   │   ├── hooks/
│   │   └── index.ts
│   ├── charts/                  # Budget/analytics charts
│   │   ├── components/
│   │   └── index.ts
│   ├── voice-assistant/         # Voice commands
│   │   ├── components/
│   │   └── index.ts
│   └── admin/                   # Admin dashboard
│       ├── components/
│       └── index.ts
├── components/                  # Shared UI components
│   ├── ui/                      # Primitive components (Button, Input, etc.)
│   ├── layout/                  # Layout components (Header, Footer, etc.)
│   └── common/                  # Shared composite components
├── hooks/                       # Shared hooks
│   ├── queries/                 # TanStack Query hooks
│   ├── mutations/               # TanStack Mutation hooks
│   └── utils/                   # Utility hooks (useDebounce, etc.)
├── providers/                   # React context providers
│   ├── AppProviders.tsx
│   ├── UserDataProvider.tsx
│   └── FlyersProvider.tsx
├── pages/                       # Route page components
├── services/                    # API clients, external services
├── types/                       # Shared TypeScript types
├── utils/                       # Shared utility functions
└── lib/                         # Third-party library wrappers
```

### Feature Module Structure

Each feature follows a consistent internal structure:

```
features/flyer/
├── components/
│   ├── FlyerCard.tsx
│   ├── FlyerGrid.tsx
│   ├── FlyerUploader.tsx
│   ├── FlyerItemList.tsx
│   └── index.ts              # Re-exports all components
├── hooks/
│   ├── useFlyerDetails.ts
│   ├── useFlyerUpload.ts
│   └── index.ts              # Re-exports all hooks
├── types.ts                   # Feature-specific types
├── utils.ts                   # Feature-specific utilities
└── index.ts                   # Public API of the feature
```

### Feature Index File

Each feature has an `index.ts` that defines its public API:

```typescript
// features/flyer/index.ts
export { FlyerCard, FlyerGrid, FlyerUploader } from './components';
export { useFlyerDetails, useFlyerUpload } from './hooks';
export type { FlyerViewProps, FlyerUploadState } from './types';
```

### Import Patterns

```typescript
// Importing from a feature (preferred)
import { FlyerCard, useFlyerDetails } from '@/features/flyer';

// Importing shared components
import { Button, Card } from '@/components/ui';
import { useDebounce } from '@/hooks/utils';

// Avoid: reaching into feature internals
// import { FlyerCard } from '@/features/flyer/components/FlyerCard';
```

### Provider Organization

Located in `src/providers/`:

```typescript
// AppProviders.tsx - Composes all providers
export function AppProviders({ children }: { children: React.ReactNode }) {
  return (
    <QueryClientProvider client={queryClient}>
      <AuthProvider>
        <UserDataProvider>
          <FlyersProvider>
            <ThemeProvider>
              {children}
            </ThemeProvider>
          </FlyersProvider>
        </UserDataProvider>
      </AuthProvider>
    </QueryClientProvider>
  );
}
```

### Query/Mutation Hook Organization

Located in `src/hooks/`:

```typescript
// hooks/queries/useFlyersQuery.ts
export function useFlyersQuery(options?: { storeId?: number }) {
  return useQuery({
    queryKey: ['flyers', options],
    queryFn: () => flyerService.getFlyers(options),
    staleTime: 5 * 60 * 1000,
  });
}

// hooks/mutations/useFlyerUploadMutation.ts
export function useFlyerUploadMutation() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: flyerService.uploadFlyer,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['flyers'] });
    },
  });
}
```

### Page Components

Pages are thin wrappers that compose feature components:

```typescript
// pages/Flyers.tsx
import { FlyerGrid, FlyerUploader } from '@/features/flyer';
import { PageLayout } from '@/components/layout';

export function FliversPage() {
  return (
    <PageLayout title="My Flyers">
      <FlyerUploader />
      <FlyerGrid />
    </PageLayout>
  );
}
```

### Cross-Feature Communication

When features need to communicate, use:

1. **Shared State Providers**: For global state (user, theme).
2. **Query Invalidation**: For data synchronization.
3. **Event Bus**: For loose coupling (see ADR-036).

```typescript
// Feature A triggers update
const uploadMutation = useFlyerUploadMutation();
await uploadMutation.mutateAsync(file);
// Query invalidation automatically updates Feature B's flyer list
```

## Naming Conventions

| Item           | Convention           | Example              |
| -------------- | -------------------- | -------------------- |
| Feature folder | kebab-case           | `voice-assistant/`   |
| Component file | PascalCase           | `FlyerCard.tsx`      |
| Hook file      | camelCase with `use` | `useFlyerDetails.ts` |
| Type file      | lowercase            | `types.ts`           |
| Utility file   | lowercase            | `utils.ts`           |
| Index file     | lowercase            | `index.ts`           |

## When to Create a New Feature

Create a new feature folder when:

1. The functionality is distinct and self-contained.
2. It has its own set of components, hooks, and potentially types.
3. It could theoretically be extracted into a separate package.
4. It has minimal dependencies on other features.

Do NOT create a feature folder for:

- A single reusable component (use `components/`).
- A single utility function (use `utils/`).
- A single hook (use `hooks/`).

## Consequences

### Positive

- **Discoverability**: Easy to find all code related to a feature.
- **Encapsulation**: Features have clear boundaries and public APIs.
- **Refactoring**: Can modify or remove features with confidence.
- **Scalability**: Supports team growth with feature ownership.
- **Testing**: Can test features in isolation.

### Negative

- **Duplication Risk**: Similar utilities might be duplicated across features.
- **Decision Overhead**: Must decide when to extract to shared folders.
- **Import Verbosity**: Feature imports can be longer.

### Mitigation

- Regular refactoring sessions to extract shared code.
- Lint rules to prevent importing from feature internals.
- Code review focus on proper feature boundaries.

## Key Directories

- `src/features/flyer/` - Flyer viewing and management
- `src/features/shopping/` - Shopping list functionality
- `src/features/charts/` - Budget and analytics charts
- `src/features/voice-assistant/` - Voice command interface
- `src/features/admin/` - Admin dashboard
- `src/components/ui/` - Shared primitive components
- `src/hooks/queries/` - TanStack Query hooks
- `src/providers/` - React context providers

## Related ADRs

- [ADR-005](./0005-frontend-state-management-and-server-cache-strategy.md) - State Management
- [ADR-012](./0012-frontend-component-library-and-design-system.md) - Component Library
- [ADR-026](./0026-standardized-client-side-structured-logging.md) - Client Logging
