---
name: database-prisma
description: Prisma ORM and database patterns for GoodGo services. Use for schemas, migrations, repositories, or query optimization.
compatibility: "prisma>=5, @prisma/client>=5"
---

# Prisma Database Patterns

## When to Use This Skill

Use this skill when:
- Setting up Prisma for a new service
- Creating or modifying database schemas
- Writing database migrations
- Implementing repository patterns
- Optimizing database queries
- Setting up database connections
- Implementing transactions
- Working with Neon PostgreSQL

## Core Concepts

### Architecture
- Repository pattern for data access
- Prisma as ORM for type safety
- Neon PostgreSQL as primary database
- Connection pooling for performance
- Transaction support for data consistency

## Key Patterns

### Prisma Setup

```bash
npm install @prisma/client prisma
npx prisma init
```

### Schema Definition

```prisma
model User {
  id        String   @id @default(cuid())
  email     String   @unique
  name      String?
  role      Role     @default(USER)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  posts     Post[]

  @@index([email])
  @@index([createdAt])
  @@map("users")
}
```

### Database Connection

```typescript
import { PrismaClient } from '@prisma/client';

const globalForPrisma = global as unknown as { prisma: PrismaClient | undefined };

export const prisma = globalForPrisma.prisma ?? new PrismaClient({
  log: process.env.NODE_ENV === 'development' ? ['query', 'error'] : ['error'],
});

if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;
```

### Repository Pattern

```typescript
export class UserRepository {
  async findById(id: string) {
    return prisma.user.findUnique({ where: { id }, include: { profile: true } });
  }

  async findAll({ page = 1, limit = 10, search }: QueryOptions) {
    const where = search ? { OR: [
      { email: { contains: search, mode: 'insensitive' } },
      { name: { contains: search, mode: 'insensitive' } }
    ]} : {};

    const [data, total] = await Promise.all([
      prisma.user.findMany({ where, skip: (page - 1) * limit, take: limit }),
      prisma.user.count({ where })
    ]);
    return { data, total };
  }

  async create(data: CreateUserDto) {
    return prisma.user.create({ data });
  }
}
```

### Transactions

```typescript
await prisma.$transaction(async (tx) => {
  await tx.account.update({ where: { id: from }, data: { balance: { decrement: amount } } });
  await tx.account.update({ where: { id: to }, data: { balance: { increment: amount } } });
}, { maxWait: 5000, timeout: 10000 });
```

## Best Practices

- **Schema Design**: Use appropriate field types, add indexes for frequently queried fields
- **Performance**: Use select to fetch only needed fields, implement pagination
- **Security**: Never expose sensitive fields, use parameterized queries
- **Maintenance**: Keep migrations small and focused, test before production

## Common Mistakes

1. **N+1 Query Problem**: Fetching related data in a loop
   ```typescript
   // BAD: N+1 queries
   for (const user of users) { await prisma.post.findMany({ where: { authorId: user.id } }); }
   // GOOD: Include relations
   await prisma.user.findMany({ include: { posts: true } });
   ```

2. **No Indexes**: Missing indexes on frequently queried columns
   ```prisma
   // GOOD: Add index
   @@index([createdAt])
   ```

3. **Raw Queries Without Parameters**: SQL injection risk
   ```typescript
   // BAD: prisma.$queryRawUnsafe(`SELECT * FROM users WHERE email = '${email}'`);
   // GOOD: prisma.$queryRaw`SELECT * FROM users WHERE email = ${email}`;
   ```

4. **Not Using Transactions**: Data inconsistency risk
   ```typescript
   // GOOD: Use transaction for related operations
   await prisma.$transaction([update1, update2]);
   ```

5. **Exposing Internal IDs**: Leaking database structure
   ```prisma
   // GOOD: Use CUID or UUID
   model User { id String @id @default(cuid()) }
   ```

## Quick Reference

| Operation | Command |
|-----------|---------|
| **Create migration** | `npx prisma migrate dev --name <name>` |
| **Apply migrations** | `npx prisma migrate deploy` |
| **Reset database** | `npx prisma migrate reset` |
| **Generate client** | `npx prisma generate` |
| **Open Studio** | `npx prisma studio` |
| **Seed database** | `npx prisma db seed` |

**Common Query Patterns:**
```typescript
await prisma.user.findUnique({ where: { id } });           // Find unique
await prisma.user.findMany({ include: { posts: true } });  // With relations
await prisma.user.findMany({ select: { id: true } });      // Select fields
await prisma.user.findMany({ skip: 10, take: 10 });        // Pagination
await prisma.$transaction(async (tx) => { ... });          // Transaction
```

**Schema Field Types:**
| Type | PostgreSQL | Description |
|------|------------|-------------|
| `String` | TEXT | Variable-length string |
| `Int` | INTEGER | 32-bit integer |
| `BigInt` | BIGINT | 64-bit integer |
| `Float` | DOUBLE PRECISION | Floating point |
| `Boolean` | BOOLEAN | True/false |
| `DateTime` | TIMESTAMP | Date and time |
| `Json` | JSONB | JSON data |

## Resources

- [Prisma Documentation](https://www.prisma.io/docs) - Official Prisma docs
- [Prisma Schema Reference](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference)
- [Detailed Code Examples](./references/REFERENCE.md)
- [Repository Pattern](../repository-pattern/SKILL.md) - Data access patterns
- [Caching Patterns](../caching-patterns/SKILL.md) - Query caching
- [Testing Patterns](../testing-patterns/SKILL.md) - Database mocking
