Claude
Skills
Sign in
Back

frontend-engineer

Included with Lifetime
$97 forever

Expert frontend engineering with simplified pragmatic architecture, React 19, TanStack ecosystem, and Zustand state management. **ALWAYS use when implementing ANY frontend features.** Use when setting up project structure, creating pages and state management, designing gateway injection patterns, setting up HTTP communication and routing, organizing feature modules, or optimizing performance. **ALWAYS use when implementing Gateway Pattern (Interface + HTTP + Fake), Context API injection, Zustand stores, TanStack Router, or feature-based architecture.**

Web Dev

What this skill does


# Frontend Engineer Skill

**Purpose**: Expert frontend engineering with simplified pragmatic architecture, React 19, TanStack ecosystem, and Zustand state management. Provides implementation examples for building testable, maintainable, scalable frontend applications.

**When to Use**:

- Implementing frontend features and components
- Setting up project structure
- Creating pages and state management
- Designing gateway injection patterns
- Setting up HTTP communication and routing
- Organizing feature modules
- Performance optimization and code splitting

**NOTE**: For UI component design, Tailwind styling, shadcn/ui setup, responsive layouts, and accessibility implementation, defer to the `ui-designer` skill. This skill focuses on architecture, state management, and business logic orchestration.

---

## Documentation Lookup (MANDATORY)

**ALWAYS use MCP servers for up-to-date documentation:**

- **Context7 MCP**: Use for comprehensive library documentation, API reference, import statements, and version-specific patterns

  - When user asks about TanStack Router, Query, Form, Table APIs
  - For React 19 features and patterns
  - For Vite configuration and build setup
  - For Zustand API and patterns
  - To verify correct import paths, hooks usage, and API patterns

- **Perplexity MCP**: Use for architectural research, design patterns, and best practices
  - When researching pragmatic frontend architectures
  - For state management strategies and trade-offs
  - For performance optimization techniques
  - For folder structure and code organization patterns
  - For troubleshooting complex architectural issues

**Examples of when to use MCP:**

- "How to setup TanStack Router file-based routing?" → Use Context7 MCP for TanStack Router docs
- "What are React 19 use() hook patterns?" → Use Context7 MCP for React docs
- "How to use Zustand with TypeScript?" → Use Context7 MCP for Zustand docs
- "Best practices for feature-based architecture in React?" → Use Perplexity MCP for research
- "How to configure Vite with React 19?" → Use Context7 MCP for Vite docs

---

## Tech Stack

**For complete frontend tech stack details, see "Tech Stack > Frontend" section in CLAUDE.md**

**Quick Architecture Reference:**

This skill focuses on:

- Feature-based architecture (NOT Clean Architecture layers)
- Gateway Pattern (Interface + HTTP + Fake)
- Context API injection for testability
- Zustand for global client state
- TanStack Query for server state

### Testing:

- **Unit**: Vitest + React Testing Library
- **E2E**: Playwright

→ See `project-standards` skill for complete tech stack
→ See `ui-designer` skill for UI/UX specific technologies
→ See `docs/plans/2025-10-24-simplified-frontend-architecture-design.md` for architecture details

---

## Architecture Overview

Frontend follows a **simplified, pragmatic, feature-based architecture**.

**Core Principles:**

1. **Feature-based organization** - Code grouped by business functionality
2. **Pages as use cases** - Pages orchestrate business logic
3. **Externalized state** - Zustand stores are framework-agnostic, 100% testable
4. **Gateway injection** - Gateways injected via Context API for isolated testing
5. **YAGNI rigorously** - No unnecessary layers or abstractions

**Design Philosophy**: Simplicity and pragmatism over architectural purity. Remove Clean Architecture complexity (domain/application/infrastructure layers) in favor of direct, maintainable code.

### Recommended Structure

```
apps/web/src/
├── app/                              # Application setup
│   ├── config/
│   │   ├── env.ts                   # Environment variables
│   │   └── index.ts
│   ├── providers/
│   │   ├── gateway-provider.tsx     # Gateway injection (Context API)
│   │   ├── query-provider.tsx       # TanStack Query setup
│   │   ├── theme-provider.tsx       # Theme provider (shadcn/ui)
│   │   └── index.ts
│   ├── router.tsx                   # TanStack Router configuration
│   └── main.tsx                     # Application entry point
│
├── features/                         # Feature modules (self-contained)
│   ├── auth/
│   │   ├── components/              # Pure UI components
│   │   │   ├── login-form.tsx
│   │   │   └── index.ts
│   │   ├── pages/                   # Use cases - orchestrate logic
│   │   │   ├── login-page.tsx
│   │   │   └── index.ts
│   │   ├── stores/                  # Zustand stores - testable entities
│   │   │   ├── auth-store.ts
│   │   │   └── index.ts
│   │   ├── gateways/                # External resource abstractions
│   │   │   ├── auth-gateway.ts      # Interface + HTTP implementation
│   │   │   ├── auth-gateway.fake.ts # Fake for unit tests
│   │   │   └── index.ts
│   │   ├── hooks/                   # Custom hooks (optional)
│   │   │   └── index.ts
│   │   ├── types/                   # TypeScript types
│   │   │   ├── user.ts
│   │   │   └── index.ts
│   │   └── index.ts                 # Barrel file - public API
│   │
│   ├── dashboard/
│   └── profile/
│
├── shared/                           # Shared code across features
│   ├── services/                    # Global services
│   │   ├── http-api.ts             # HTTP client base (Axios wrapper)
│   │   ├── storage.ts              # LocalStorage/Cookie abstraction
│   │   └── index.ts
│   ├── components/
│   │   ├── ui/                     # shadcn/ui components
│   │   └── layout/                 # Shared layouts
│   ├── hooks/                      # Global utility hooks
│   ├── lib/                        # Utilities and helpers
│   │   ├── validators.ts           # Zod schemas (common)
│   │   ├── formatters.ts
│   │   └── index.ts
│   └── types/                      # Global types
│
├── routes/                          # TanStack Router routes
│   ├── __root.tsx
│   ├── index.tsx
│   └── auth/
│       └── login.tsx
│
└── index.css
```

**Benefits**:

- ✅ Feature isolation - delete folder, remove feature
- ✅ No unnecessary layers - direct, maintainable code
- ✅ Testable business logic - Zustand stores are pure JS/TS
- ✅ Isolated page testing - inject fake gateways
- ✅ Clear separation - pages (orchestration), components (UI), stores (state)

---

## Layer Responsibilities (MANDATORY)

### 1. Shared Services Layer

**Purpose**: Reusable infrastructure used across features.

**Example - HTTP Client**:

```typescript
// shared/services/http-api.ts
import axios, { type AxiosInstance, type AxiosRequestConfig } from "axios";

export class HttpApi {
  private client: AxiosInstance;

  constructor(baseURL: string) {
    this.client = axios.create({
      baseURL,
      timeout: 10000,
      headers: { "Content-Type": "application/json" },
    });

    // Auto-inject auth token
    this.client.interceptors.request.use((config) => {
      const token = localStorage.getItem("auth_token");
      if (token) config.headers.Authorization = `Bearer ${token}`;
      return config;
    });

    // Handle 401 globally
    this.client.interceptors.response.use(
      (response) => response,
      (error) => {
        if (error.response?.status === 401) {
          localStorage.removeItem("auth_token");
          window.location.href = "/auth/login";
        }
        return Promise.reject(error);
      }
    );
  }

  async get<T>(url: string, config?: AxiosRequestConfig) {
    const response = await this.client.get<T>(url, config);
    return response.data;
  }

  async post<T>(url: string, data?: unknown, config?: AxiosRequestConfig) {
    const response = await this.client.post<T>(url, data, config);
    return response.data;
  }

  async put<T>(url: string, data?: unknown, config?: AxiosRequestConfig) {
    const response = await this.client.put<T>(url, data, config);
    return response.data;
  }

  async delete<T>(url: string, config?: AxiosRequestConfig) {
    const response = await this.client.delete<T>(url, config);
    return response.data;
  }
}

// Singleton instance
export const httpApi = new HttpApi(import.meta.env.VITE_API_URL);
```

Related in Web Dev