Skip to content

Frontend Architecture

The frontend is built with Next.js 16, React 19, and Tailwind CSS 4.

Project Structure

frontend/
├── app/                    # Next.js App Router
│   ├── layout.tsx          # Root layout
│   ├── page.tsx            # Homepage
│   ├── products/           # Product pages
│   └── designer/           # Product designer
├── components/
│   ├── header/             # Header components
│   ├── homepage/           # Homepage sections
│   ├── products/           # Product listing
│   ├── product-detail/     # Product detail page
│   ├── ProductDesigner/    # Canvas designer
│   └── providers/          # Context providers
├── contexts/               # React contexts
│   ├── AuthContext.tsx
│   ├── CartContext.tsx
│   └── ThemeContext.tsx
├── lib/                    # Utilities
│   ├── api/client.ts       # API client
│   └── queryClient.ts      # TanStack Query
├── types/                  # TypeScript types
│   └── index.ts
└── public/                 # Static assets

Component Architecture

Component Organization

Components are organized by feature:

components/
├── [feature]/
│   ├── FeatureComponent.tsx
│   ├── FeatureComponent.stories.tsx  # Storybook
│   └── FeatureComponent.test.tsx     # Jest tests

Component Patterns

Presentational Components

interface ButtonProps {
  variant: 'primary' | 'secondary';
  children: React.ReactNode;
}

export function Button({ variant, children }: ButtonProps) {
  return <button className={styles[variant]}>{children}</button>;
}

Container Components

export function ProductList() {
  const { data: products } = useQuery({
    queryKey: ['products'],
    queryFn: fetchProducts,
  });

  return <ProductGrid products={products} />;
}

State Management

Server State (TanStack Query)

const { data, isLoading, error } = useQuery({
  queryKey: ['products', categoryId],
  queryFn: () => api.products.list({ category: categoryId }),
});

Client State (Zustand)

const useCartStore = create((set) => ({
  items: [],
  addItem: (item) => set((state) => ({
    items: [...state.items, item],
  })),
}));

Context (React Context)

Used for: - Authentication state - Theme preferences - Feature flags

Styling

Tailwind CSS 4 with custom design tokens in app/globals.css:

:root {
  --primary: #31a8b6;
  --primary-dark: #2a919d;
}

@theme inline {
  --color-primary: var(--primary);
}

Product Designer

The Fabric.js canvas editor supports:

  • Text with custom fonts
  • Image uploads
  • Shape tools
  • Multi-view support (front/back/left/right)
  • Undo/redo
  • Print area boundaries