skills/azure12355/weilan-skills/nextjs-enterprise-init

nextjs-enterprise-init

SKILL.md

Next.js Enterprise Project Initialization

Initialize Next.js projects with enterprise-grade architecture and conventions.

Quick Start

To initialize a Next.js project with enterprise structure:

python3 scripts/init_nextjs_structure.py /path/to/project

The script will:

  1. Create src/common/ with utilities, components, hooks, services
  2. Create src/features/ with example feature module
  3. Set up proper TypeScript path aliases
  4. Create global styles with CSS variables for theming
  5. Generate example API routes

Architecture Overview

This skill implements a feature-first architecture with clear separation of concerns:

src/
├── app/                    # Next.js App Router (routes, layouts, pages)
├── features/               # Feature-based modules (business logic)
├── common/                 # Shared utilities and components
└── styles/                 # Global styles

Key Principles:

  • Feature-first: Organize by business domain, not technical layers
  • Separation of concerns: UI, logic, and data fetching are separate
  • Dependency direction: app/features/common/ (one-way)
  • Atomic components: Build complex UIs from simple, reusable parts

Directory Structure

For complete directory structure details, see structure.md.

Key Directories

Directory Purpose
app/ Next.js App Router - routes, layouts, pages, API routes
features/ Feature modules - self-contained business logic
common/components/ui/ Atomic UI components (Button, Input, etc.)
common/hooks/ Shared React hooks
common/services/ API services and data fetching
common/utils/ Pure utility functions
common/config/ Configuration (theme, i18n)

Component Conventions

Atomic Component Pattern

Each component lives in its own directory:

ComponentName/
├── ComponentName.tsx       # Main component
├── ComponentName.module.css # Styles
├── ComponentName.test.tsx  # Tests
└── index.ts                # Exports

Size Guidelines:

  • Atomic: ≤150 lines (Button, Input)
  • Composite: 150-300 lines (composed of atomics)
  • Complex: >300 lines (split into sub-components)

Component Declaration

Always use function components with explicit types:

import { ButtonProps } from './Button.types';
import styles from './Button.module.css';

export function Button({ variant = 'primary', children, ...props }: ButtonProps) {
  return (
    <button className={`${styles.button} ${styles[variant]}`} {...props}>
      {children}
    </button>
  );
}

Hooks Conventions

Custom Hook Pattern

// useUserProfile.ts
export function useUserProfile(userId: string) {
  const [state, setState] = useState<AsyncState<User>>({ status: 'idle' });

  // ... implementation

  return {
    user: state.status === 'success' ? state.data : null,
    loading: state.status === 'loading',
    error: state.status === 'error' ? state.error : null,
    refetch,
  };
}

Rules:

  • Prefix with use
  • Return stable object (use useMemo if needed)
  • Handle cleanup in useEffect
  • Specify all dependencies

API & Services

API Client Pattern

Use the base apiClient from common/services/apiClient.ts:

import { apiClient } from '@/common/services/apiClient';

export const userApi = {
  async getById(id: string): Promise<User> {
    return apiClient.get<User>(`/users/${id}`);
  },

  async update(id: string, data: UserUpdateData): Promise<User> {
    return apiClient.put<User>(`/users/${id}`, data);
  },
};

State Management Strategy

State Type Solution Example
Server State React Query User data, API responses
URL State URL params/search ?page=2&filter=active
Form State Component state Input values, validation
Global UI Context Theme, language, auth status

Styling Conventions

CSS Modules (Preferred)

import styles from './Button.module.css';

export function Button({ variant = 'primary' }: ButtonProps) {
  return <button className={`${styles.button} ${styles[variant]}`}>...</button>;
}

Theming with CSS Variables

:root {
  --color-primary: #0070f3;
  --spacing-md: 1rem;
  --radius-md: 8px;
}

[data-theme='dark'] {
  --color-primary: #3291ff;
}

For detailed styling patterns, see conventions.md.

Feature Module Structure

Each feature is self-contained:

features/feature-name/
├── components/             # Feature-specific components
├── hooks/                  # Feature-specific hooks
├── services/               # Feature-specific API calls
├── types/                  # Feature-specific types
└── index.ts                # Public API exports

Feature conventions:

  • Export only public API via index.ts
  • Keep feature-specific code within the feature
  • Use barrel exports for clean imports

Import Conventions

Order imports consistently:

// 1. React and Next.js
import { useState } from 'react';
import Link from 'next/link';

// 2. Third-party libraries
import { clsx } from 'clsx';

// 3. Internal imports - features
import { UserProfile } from '@/features/user-profile';

// 4. Internal imports - common
import { Button } from '@/common/components/ui/Button';
import { useDebounce } from '@/common/hooks/useDebounce';

File Naming Conventions

  • Components: PascalCase (UserProfile.tsx)
  • Hooks: camelCase with 'use' prefix (useUserProfile.ts)
  • Utilities: camelCase (formatDate.ts)
  • Types: *.types.ts suffix (user.types.ts)
  • Tests: *.test.tsx or *.spec.tsx

Theming Extensibility

The theme system supports extension:

import { extendTheme, lightTheme } from '@/common/config/theme';

const customTheme = extendTheme(lightTheme, {
  colors: {
    primary: '#custom-color',
  },
});

Theme config is in common/config/theme.ts - see architecture.md for details.

i18n Extensibility

Add new locales by:

  1. Adding locale to i18nConfig.locales in common/config/i18n.ts
  2. Creating translation file in common/locales/{locale}.json

No code changes required for new locales.

Error Handling

Async Error Handling Pattern

export function UserProfile() {
  const [state, setState] = useState<AsyncState<User>>({ status: 'idle' });

  useEffect(() => {
    const fetchUser = async () => {
      setState({ status: 'loading' });
      try {
        const user = await userApi.getById(userId);
        setState({ status: 'success', data: user });
      } catch (error) {
        setState({
          status: 'error',
          error: error instanceof Error ? error : new Error('Unknown error'),
        });
      }
    };
    fetchUser();
  }, [userId]);

  if (state.status === 'error') {
    return <ErrorMessage error={state.error} />;
  }
  // ...
}

Testing Conventions

Test Structure

import { render, screen } from '@testing-library/react';
import { describe, it, expect, vi } from 'vitest';
import { Button } from './Button';

describe('Button', () => {
  it('renders children correctly', () => {
    render(<Button>Click me</Button>);
    expect(screen.getByText('Click me')).toBeInTheDocument();
  });
});

Security Considerations

  1. Never expose secrets - Use environment variables
  2. Validate user input - Client and server-side
  3. Sanitize user-generated content - Use DOMPurify for HTML
  4. Implement rate limiting - For API routes
  5. Use CSRF protection - For form submissions

CLAUDE.md

Generate CLAUDE.md in project root using the template from assets/CLAUDE.md.template.

The CLAUDE.md should contain:

  • Project overview
  • Architecture summary
  • Development guidelines
  • Project-specific rules
  • Common tasks

Using the Initialization Script

The script handles the complete setup:

# Run from project root
python3 scripts/init_nextjs_structure.py

# Or specify project path
python3 scripts/init_nextjs_structure.py /path/to/nextjs/project

What it creates:

  • src/common/ with full subdirectory structure
  • src/features/ with example feature
  • src/app/api/ with example API route
  • Global CSS with theme variables
  • Updated tsconfig.json with path aliases

Additional References

Load these files when you need detailed information about specific aspects of the project structure.

Weekly Installs
1
GitHub Stars
1
First Seen
7 days ago
Installed on
zencoder1
amp1
cline1
openclaw1
opencode1
cursor1