スキル一覧に戻る
eduardbar

migestion-prisma

by eduardbar

Multi-tenant SaaS CRM for local businesses

0🍴 0📅 2026年1月22日
GitHubで見るManusで実行

SKILL.md


name: migestion-prisma description: > Prisma ORM patterns for MiGestion - multi-tenant queries, migrations, seed. Trigger: When writing Prisma queries, migrations, or schema changes. license: MIT metadata: author: migestion version: '1.0' scope: [api] auto_invoke: 'Writing Prisma queries/migrations' allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task

Multi-Tenant Pattern (REQUIRED)

All queries MUST include tenantId in WHERE clause for tenant isolation.

// ✅ ALWAYS: Include tenantId
await prisma.client.findFirst({
  where: { tenantId, id: clientId },
});

await prisma.client.findMany({
  where: { tenantId },
});

// ❌ NEVER: Query without tenant
await prisma.client.findUnique({
  where: { id: clientId }, // NO! Bypasses tenant isolation
});

Repository Pattern

Repositories encapsulate all Prisma queries.

// ✅ Repository functions
export async function findById(tenantId: string, id: string) {
  return prisma.example.findFirst({
    where: { id, tenantId },
  });
}

export async function findMany(tenantId: string, params: FindParams) {
  const { page, limit, search, ...filters } = params;

  return await prisma.example.findMany({
    where: { tenantId, ...filters },
    skip: (page - 1) * limit,
    take: limit,
    orderBy: { createdAt: 'desc' },
  });
}

export async function create(data: PrismaExampleCreateInput) {
  return prisma.example.create({ data });
}

export async function update(tenantId: string, id: string, data: PrismaExampleUpdateInput) {
  return prisma.example.update({
    where: { id, tenantId },
    data,
  });
}

export async function remove(tenantId: string, id: string) {
  return prisma.example.delete({
    where: { id, tenantId },
  });
}

Pagination

export async function findManyPaginated(tenantId: string, page: number, limit: number) {
  const [data, total] = await Promise.all([
    prisma.example.findMany({
      where: { tenantId },
      skip: (page - 1) * limit,
      take: limit,
    }),
    prisma.example.count({ where: { tenantId } }),
  ]);

  return { data, total };
}

Search/Filter

export async function findWithSearch(tenantId: string, search?: string, status?: string) {
  return prisma.example.findMany({
    where: {
      tenantId,
      ...(search && {
        OR: [
          { name: { contains: search, mode: 'insensitive' } },
          { email: { contains: search, mode: 'insensitive' } },
        ],
      }),
      ...(status && { status }),
    },
  });
}

Relations

export async function findWithRelations(tenantId: string, id: string) {
  return prisma.example.findFirst({
    where: { id, tenantId },
    include: {
      user: true,
      interactions: {
        orderBy: { createdAt: 'desc' },
        take: 10,
      },
    },
  });
}

JSON Fields

// Reading JSON field
const client = await prisma.client.findUnique({
  where: { id },
  select: { tags: true, customFields: true },
});

// Writing JSON field
await prisma.client.create({
  data: {
    tags: ['vip', 'priority'] as Prisma.InputJsonValue,
    customFields: { preferences: { language: 'es' } } as Prisma.InputJsonValue,
  },
});

// Querying JSON field
await prisma.client.findMany({
  where: {
    tags: {
      path: ['0'],
      equals: 'vip',
    },
  },
});

Transactions

await prisma.$transaction(async tx => {
  const client = await tx.client.create({ data: clientData });

  await tx.interaction.create({
    data: {
      clientId: client.id,
      type: 'initial_contact',
    },
  });

  return client;
});

Schema Pattern

model Client {
  id          String   @id @default(cuid())
  tenantId    String
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  // Relations
  interactions Interaction[]
  assignedTo   User?    @relation(fields: [assignedToId], references: [id])
  assignedToId String?

  @@unique([id, tenantId])
  @@index([tenantId])
  @@index([tenantId, status])
}

Commands

npm run db:generate          # Generate Prisma client
npm run db:migrate           # Create and apply migration
npm run db:migrate:prod      # Apply migration in production
npm run db:seed              # Seed database
npm run db:studio            # Open Prisma Studio UI

# Manual migration
npx prisma migrate dev --name add_field
npx prisma migrate deploy   # Production
npx prisma studio

Migrations

# Create migration
npm run db:migrate -- --name add_client_field

# Reset database (development only)
npx prisma migrate reset

# Seed after migration
npm run db:seed

Seed Pattern

import { PrismaClient } from '@prisma/client';
import bcrypt from 'bcrypt';

const prisma = new PrismaClient();

async function main() {
  const hashedPassword = await bcrypt.hash('password123', 10);

  const tenant = await prisma.tenant.create({
    data: {
      name: 'Demo Company',
      users: {
        create: {
          email: 'admin@example.com',
          password: hashedPassword,
          name: 'Admin User',
          role: 'OWNER',
        },
      },
    },
  });

  console.log('Seed complete:', tenant);
}

main()
  .catch(console.error)
  .finally(() => prisma.$disconnect());
  • migestion-api - Full API module patterns
  • typescript - TypeScript patterns for Prisma types

スコア

総合スコア

50/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

レビュー

💬

レビュー機能は近日公開予定です