mcpField
A
application-patterns

application-patterns

github.com/miles990開発2649 回インストール40 週間前に更新
リポジトリ

application-patterns について

application-patternsは、実用的なアプリケーション開発で繰り返し使われるパターンをまとめたリファレンススキルです。アプリケーション開発者向けに、CRUD、認証、管理画面、ファイル処理、検索、ワークフロー、国際化を扱います。

主な機能

  1. 01CRUDのデータフローとフォーム検証
  2. 02認証とセッション方式
  3. 03管理テーブルと一括操作
  4. 04ファイルアップロードと画像処理
  5. 05検索アーキテクチャと機能チェックリスト
  6. 06ワークフローパターンと国際化

活用シーン

  1. 01CRUDフォームからデータベースまでの流れの設計
  2. 02認証とセッション方式の選択
  3. 03ファイルアップロードや検索構成の設計
  4. 04承認ワークフローと翻訳の構成

インストール

コマンドをコピーしてターミナルで実行します。

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

インストール後、Claude Code で/application-patternsを入力して読み込まれたか確認します。

詳細

アプリケーション開発パターン

概要

実用的なアプリケーションを構築するための一般的なパターンです。これらのパターンは、アプリケーション開発で繰り返し発生する問題を解決します。


CRUD アプリケーション

データフローパターン
┌─────────┐     ┌─────────┐     ┌─────────┐     ┌─────────┐
│  Form   │ ──→ │Validate │ ──→ │ Service │ ──→ │   DB    │
└─────────┘     └─────────┘     └─────────┘     └─────────┘
     ↑                                               │
     └───────────── Response ←───────────────────────┘
フォーム処理のベストプラクティス
// 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;
  }
}

ユーザー認証

認証フロー
┌────────────────────────────────────────────────────────────┐
│                    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       │
│                                                            │
└────────────────────────────────────────────────────────────┘
セッション管理
戦略メリットデメリット
JWTステートレスでスケーラブル簡単には無効化できない
サーバーセッション無効化可能で安全セッションストアが必要
ハイブリッド両方の長所を備えるより複雑
セキュリティチェックリスト
  • パスワードのハッシュ化(bcrypt/argon2)
  • ログイン時のレート制限
  • CSRF 保護
  • セキュアな Cookie 設定(httpOnly、secure、sameSite)
  • ログイン失敗後のアカウントロック
  • パスワードリセットトークンの有効期限

管理ダッシュボード

データテーブルパターン
// 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 };
}
一括操作
// 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
  };
}

ファイル管理

アップロード戦略
方法用途最大サイズ
サーバーへ直接小さなファイル約10MB
署名付き URL大きなファイル無制限
チャンク分割アップロード非常に大きなファイル無制限
再開可能なアップロード不安定なネットワーク無制限
署名付き URL のフロー
Client                    Server                    S3
   │                         │                       │
   │── Request upload URL ──→│                       │
   │                         │── Generate presigned ─→│
   │←── Return presigned URL─│                       │
   │                         │                       │
   │───────── Upload file directly ─────────────────→│
   │                         │                       │
   │── Confirm upload ──────→│                       │
   │                         │── Verify file exists ─→│
   │←── Success ─────────────│                       │
画像処理パイプライン
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,
    }
  });
}

検索の実装

検索アーキテクチャ
┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│   Database   │ ──→ │    Sync      │ ──→ │   Search     │
│  (Primary)   │     │   Worker     │     │   Engine     │
└──────────────┘     └──────────────┘     └──────────────┘
                                                  ↑
                                                  │
┌──────────────┐     ┌──────────────┐             │
│    Client    │ ──→ │  Search API  │ ────────────┘
└──────────────┘     └──────────────┘
検索機能のチェックリスト
  • 全文検索
  • ファセットフィルタリング
  • オートコンプリート/候補表示
  • 誤字の許容(あいまい一致)
  • ハイライト表示
  • 同義語
  • 関連度の調整

ワークフローエンジン

ステートマシンパターン
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'
      }
    }
  }
};
承認ワークフロー
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);
  }
}

多言語対応(i18n)

翻訳の構成
locales/
├── en/
│   ├── common.json    # Shared strings
│   ├── auth.json      # Auth module
│   └── dashboard.json # Dashboard module
├── zh-TW/
│   ├── common.json
│   ├── auth.json
│   └── dashboard.json
└── ja/
    └── ...
ベストプラクティス
  1. キーの命名:名前空間付きのキーを使用する

    {
      "auth.login.title": "Sign In",
      "auth.login.email": "Email Address",
      "auth.login.submit": "Sign In"
    }
    
  2. 複数形:複数形を適切に処理する

    {
      "items": "{count, plural, =0 {No items} =1 {1 item} other {# items}}"
    }
    
  3. 変数:補間を使用する

    {
      "welcome": "Welcome, {name}!"
    }
    
  4. 日付/数値の書式設定:Intl API を使用する

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

関連スキル

  • [[architecture-patterns]] - システム全体の設計
  • [[frontend]] - UI の実装
  • [[backend]] - サーバーの実装
  • [[database]] - データの永続化
  • [[security-practices]] - セキュリティ上の考慮事項

コメント