mcpField
A
application-patterns

application-patterns

github.com/miles990Development2649 installsUpdated 40w ago
Repository

About application-patterns

application-patterns is a reference skill on recurring patterns for building real-world applications. It covers CRUD, authentication, admin dashboards, file handling, search, workflows, and internationalization for application developers.

Key features

  1. 01CRUD data flow and form validation
  2. 02Authentication and session strategies
  3. 03Admin tables and bulk operations
  4. 04File uploads and image processing
  5. 05Search architecture and feature checklist
  6. 06Workflow patterns and internationalization

Use cases

  1. 01Plan a CRUD form-to-database flow
  2. 02Choose an authentication and session approach
  3. 03Design file uploads or search architecture
  4. 04Structure approval workflows and translations

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/miles990/claude-software-skills --skill application-patterns

After installing, type/application-patternsin Claude Code to confirm it loaded.

Details

From the project README

Application Development Patterns

Overview

Common patterns for building real-world applications. These patterns solve recurring problems in application development.


CRUD Applications

Data Flow Pattern
┌─────────┐     ┌─────────┐     ┌─────────┐     ┌─────────┐
│  Form   │ ──→ │Validate │ ──→ │ Service │ ──→ │   DB    │
└─────────┘     └─────────┘     └─────────┘     └─────────┘
     ↑                                               │
     └───────────── Response ←───────────────────────┘
Form Handling Best Practices
// 1. Validation schema (shared frontend/backend)
const userSchema = z.object({
  email: z.string().email(),
  name: z.string().min(2).max(100),
  role: z.enum(['admin', 'user', 'guest'])
});

// 2. Server action with error handling
async function createUser(formData: FormData) {
  const result = userSchema.safeParse(Object.fromEntries(formData));

  if (!result.success) {
    return { error: result.error.flatten() };
  }

  try {
    const user = await db.user.create({ data: result.data });
    return { success: true, data: user };
  } catch (e) {
    if (e.code === 'P2002') {
      return { error: { email: 'Email already exists' } };
    }
    throw e;
  }
}

User Authentication

Authentication Flow
┌────────────────────────────────────────────────────────────┐
│                    Authentication Flows                     │
├────────────────────────────────────────────────────────────┤
│                                                            │
│  Email/Password:                                           │
│  Login → Validate → Create Session → Set Cookie → Redirect │
│                                                            │
│  OAuth (Social Login):                                     │
│  Redirect → Provider Auth → Callback → Upsert User → Done │
│                                                            │
│  Magic Link:                                               │
│  Email → Generate Token → Send Link → Verify → Login       │
│                                                            │
└────────────────────────────────────────────────────────────┘
Session Management
StrategyProsCons
JWTStateless, scalableCan't revoke easily
Server SessionRevocable, secureRequires session store
HybridBest of bothMore complex
Security Checklist
  • Password hashing (bcrypt/argon2)
  • Rate limiting on login
  • CSRF protection
  • Secure cookie settings (httpOnly, secure, sameSite)
  • Account lockout after failed attempts
  • Password reset token expiration

Admin Dashboards

Data Table Pattern
// Reusable data table with sorting, filtering, pagination
interface DataTableProps<T> {
  data: T[];
  columns: ColumnDef<T>[];
  pagination: { page: number; pageSize: number; total: number };
  sorting: { field: string; direction: 'asc' | 'desc' }[];
  filters: Record<string, unknown>;
  onStateChange: (state: TableState) => void;
}

// Server-side handling
async function getUsers(params: TableState) {
  const { page, pageSize, sorting, filters } = params;

  const query = {
    where: buildWhereClause(filters),
    orderBy: buildOrderBy(sorting),
    skip: (page - 1) * pageSize,
    take: pageSize,
  };

  const [users, total] = await Promise.all([
    db.user.findMany(query),
    db.user.count({ where: query.where })
  ]);

  return { data: users, total };
}
Bulk Operations
// Safe bulk delete with confirmation
async function bulkDelete(ids: string[]) {
  // 1. Validate permissions for each item
  const items = await db.item.findMany({
    where: { id: { in: ids } },
    select: { id: true, ownerId: true }
  });

  const authorized = items.filter(item =>
    canDelete(currentUser, item)
  );

  // 2. Soft delete or hard delete
  await db.item.updateMany({
    where: { id: { in: authorized.map(i => i.id) } },
    data: { deletedAt: new Date() }
  });

  return {
    deleted: authorized.length,
    skipped: ids.length - authorized.length
  };
}

File Management

Upload Strategies
MethodUse CaseMax Size
Direct to serverSmall files~10MB
Presigned URLLarge filesUnlimited
Chunked uploadVery large filesUnlimited
ResumableUnreliable networkUnlimited
Presigned URL Flow
Client                    Server                    S3
   │                         │                       │
   │── Request upload URL ──→│                       │
   │                         │── Generate presigned ─→│
   │←── Return presigned URL─│                       │
   │                         │                       │
   │───────── Upload file directly ─────────────────→│
   │                         │                       │
   │── Confirm upload ──────→│                       │
   │                         │── Verify file exists ─→│
   │←── Success ─────────────│                       │
Image Processing Pipeline
async function processUpload(file: File) {
  // 1. Validate file type and size
  if (!ALLOWED_TYPES.includes(file.type)) {
    throw new Error('Invalid file type');
  }

  // 2. Generate variants
  const variants = await Promise.all([
    sharp(file.buffer).resize(100, 100).toBuffer(),   // thumbnail
    sharp(file.buffer).resize(800, 600).toBuffer(),   // medium
    sharp(file.buffer).resize(1920, 1080).toBuffer(), // large
  ]);

  // 3. Upload to CDN
  const urls = await uploadToS3(variants);

  // 4. Store metadata
  return db.image.create({
    data: {
      original: urls.original,
      thumbnail: urls.thumbnail,
      medium: urls.medium,
      large: urls.large,
      mimeType: file.type,
      size: file.size,
    }
  });
}

Search Implementation

Search Architecture
┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│   Database   │ ──→ │    Sync      │ ──→ │   Search     │
│  (Primary)   │     │   Worker     │     │   Engine     │
└──────────────┘     └──────────────┘     └──────────────┘
                                                  ↑
                                                  │
┌──────────────┐     ┌──────────────┐             │
│    Client    │ ──→ │  Search API  │ ────────────┘
└──────────────┘     └──────────────┘
Search Features Checklist
  • Full-text search
  • Faceted filtering
  • Autocomplete/suggestions
  • Typo tolerance (fuzzy matching)
  • Highlighting
  • Synonyms
  • Relevance tuning

Workflow Engines

State Machine Pattern
const orderStateMachine = {
  initial: 'pending',
  states: {
    pending: {
      on: {
        PAY: 'paid',
        CANCEL: 'cancelled'
      }
    },
    paid: {
      on: {
        SHIP: 'shipped',
        REFUND: 'refunded'
      }
    },
    shipped: {
      on: {
        DELIVER: 'delivered',
        RETURN: 'returned'
      }
    },
    delivered: { type: 'final' },
    cancelled: { type: 'final' },
    refunded: { type: 'final' },
    returned: {
      on: {
        REFUND: 'refunded'
      }
    }
  }
};
Approval Workflow
interface ApprovalStep {
  id: string;
  approvers: string[];        // User IDs or roles
  requiredApprovals: number;  // How many need to approve
  timeout?: Duration;         // Auto-escalate after
  escalateTo?: string;        // Next approver on timeout
}

async function processApproval(stepId: string, userId: string, decision: 'approve' | 'reject') {
  const step = await db.approvalStep.findUnique({ where: { id: stepId } });

  // Record decision
  await db.approval.create({
    data: { stepId, userId, decision, timestamp: new Date() }
  });

  // Check if complete
  const approvals = await db.approval.count({
    where: { stepId, decision: 'approve' }
  });

  if (approvals >= step.requiredApprovals) {
    await advanceToNextStep(step);
  }
}

Multi-language (i18n)

Translation Structure
locales/
├── en/
│   ├── common.json    # Shared strings
│   ├── auth.json      # Auth module
│   └── dashboard.json # Dashboard module
├── zh-TW/
│   ├── common.json
│   ├── auth.json
│   └── dashboard.json
└── ja/
    └── ...
Best Practices
  1. Key Naming: Use namespaced keys

    {
      "auth.login.title": "Sign In",
      "auth.login.email": "Email Address",
      "auth.login.submit": "Sign In"
    }
    
  2. Pluralization: Handle plural forms

    {
      "items": "{count, plural, =0 {No items} =1 {1 item} other {# items}}"
    }
    
  3. Variables: Use interpolation

    {
      "welcome": "Welcome, {name}!"
    }
    
  4. Date/Number Formatting: Use Intl APIs

    new Intl.DateTimeFormat(locale).format(date)
    new Intl.NumberFormat(locale, { style: 'currency', currency }).format(amount)
    

Related Skills

  • [[architecture-patterns]] - Overall system design
  • [[frontend]] - UI implementation
  • [[backend]] - Server implementation
  • [[database]] - Data persistence
  • [[security-practices]] - Security considerations

Comments

Markdown supported