// "Database management with Prisma (schema, migrations, optimization). TRIGGERS: 'Prisma', 'schema', 'migration', 'database', 'query optimization', 'modelo de dados'. Use when modifying database schema, creating migrations, optimizing queries, troubleshooting database issues, data modeling."
| name | tokenmilagre-database |
| description | Database management with Prisma (schema, migrations, optimization). TRIGGERS: 'Prisma', 'schema', 'migration', 'database', 'query optimization', 'modelo de dados'. Use when modifying database schema, creating migrations, optimizing queries, troubleshooting database issues, data modeling. |
| license | MIT |
Complete guide for managing the PostgreSQL database with Prisma ORM in the Token Milagre Platform.
Provide standardized patterns for database schema design, migrations, query optimization, and data integrity in the Token Milagre Platform.
Use this skill when:
prisma/schema.prismalib/generated/prisma (custom path)// ❌ WRONG: HTTP fetch in Server Components
const res = await fetch('http://localhost:3000/api/articles');
// ✅ CORRECT: Direct Prisma access
import { prisma } from '@/lib/prisma';
const articles = await prisma.article.findMany();
Why? Eliminates HTTP overhead, environment variables dependency, serialization costs.
// ✅ CORRECT - Custom path
import { prisma } from '@/lib/prisma';
// ❌ WRONG - Default path (don't use)
import { PrismaClient } from '@prisma/client';
This project uses Prisma stub files for restricted environments (no internet, firewall blocks).
Required in package.json:
{
"scripts": {
"postinstall-disabled": "prisma generate" // DISABLED
}
}
Required in next.config.ts:
{
eslint: { ignoreDuringBuilds: true }
}
Schema Configuration:
generator client {
provider = "prisma-client-js"
output = "../lib/generated/prisma"
engineType = "library" // For stub compatibility
}
Vercel Build Checklist:
postinstall-disabled (NOT postinstall)lib/generated/prisma/next.config.ts with eslint.ignoreDuringBuilds: trueDATABASE_URL + DIRECT_URL set in Vercel# Production (Vercel) - Supabase
DATABASE_URL=postgresql://... (pooled via Supavisor)
DIRECT_URL=postgresql://... (direct for migrations)
2025-11-12: Neon → Supabase PostgreSQL (better free tier, docs: docs/MIGRACAO-SUPABASE.md)
2025-10-19: SQLite → Neon PostgreSQL
⚠️ NEVER use SQLite in production - Vercel serverless doesn't persist files.
Full schema: prisma/schema.prisma
Main Models:
Key Indexes:
JSON Fields (stored as strings):
// ✅ PREFERRED: String (flexible, no migration for new values)
model Article {
type String // 'news' | 'educational'
}
// ❌ AVOID: Enum (requires migration for new values)
enum ArticleType {
NEWS
EDUCATIONAL
}
// Store as String, parse in application
tags String? // JSON string: '["bitcoin", "ethereum"]'
// Application layer
const tags = article.tags ? JSON.parse(article.tags) : [];
Always index:
@@index([category]) // Filter: where: { category: 'bitcoin' }
@@index([published]) // Filter: where: { published: true }
@@index([createdAt]) // Sort: orderBy: { createdAt: 'desc' }
// Short text: String (default)
title String
// Long text: @db.Text
content String @db.Text
# 1. Modify prisma/schema.prisma
# 2. Create migration
npx prisma migrate dev --name add_article_level
# 3. Migration file created in prisma/migrations/
# Vercel automatically runs: prisma migrate deploy
# Or manually:
npx prisma migrate deploy
npx prisma migrate reset # DANGER: Deletes all data
npx prisma db seed
Seed file: prisma/seed.ts
// ❌ BAD: Fetch all fields
const article = await prisma.article.findUnique({ where: { slug } });
// ✅ GOOD: Select specific fields
const article = await prisma.article.findUnique({
where: { slug },
select: { id: true, title: true, content: true }
});
// ✅ INDEXED: Fast
where: { category: 'bitcoin' } // Has @@index([category])
// ❌ NOT INDEXED: Slow
where: { excerpt: { contains: 'crypto' } } // No index on excerpt
// ✅ Cursor-based (fast, consistent)
const articles = await prisma.article.findMany({
take: 10,
skip: 1,
cursor: { id: lastArticleId },
orderBy: { createdAt: 'desc' }
});
// ⚠️ Offset-based (slower for large offsets)
const articles = await prisma.article.findMany({
take: 10,
skip: 50, // Slow if offset is large
orderBy: { createdAt: 'desc' }
});
// Count
const count = await prisma.article.count({ where: { published: true } });
// Group by
const stats = await prisma.article.groupBy({
by: ['category'],
_count: { category: true },
orderBy: { _count: { category: 'desc' } }
});
// Use $transaction for atomic operations
await prisma.$transaction([
prisma.article.update({ where: { id }, data: { published: true } }),
prisma.copilotActivity.create({ data: { userId, action: 'publish' } })
]);
Prisma Client: Singleton pattern in lib/prisma.ts
import { PrismaClient } from '@/lib/generated/prisma';
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined;
};
export const prisma = globalForPrisma.prisma ?? new PrismaClient({
log: process.env.NODE_ENV === 'development' ? ['error', 'warn'] : ['error']
});
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;
Connection Pooling: Handled by Supabase Supavisor (pooled connection).
In Prisma Schema:
@unique: Enforced at database level@default: Default values? markerIn Application:
model Article {
authorId String
author User @relation(fields: [authorId], references: [id])
}
Cascade: Not configured (manual cleanup required on User delete).
const article = await prisma.article.create({
data: {
title: 'New Article',
slug: 'new-article',
content: '...',
category: 'bitcoin',
author: { connect: { id: userId } }
}
});
const article = await prisma.article.update({
where: { id },
data: { published: true, updatedAt: new Date() }
});
await prisma.article.delete({ where: { id } });
const resource = await prisma.resource.upsert({
where: { slug: 'binance' },
update: { title: 'Binance Updated' },
create: { slug: 'binance', title: 'Binance', url: '...' }
});
Common Issues:
"Unknown field" error: Schema not synced
npx prisma generate"Prisma Client not found": Path issue
output = "../lib/generated/prisma" in schemaimport { prisma } from '@/lib/prisma'"Can't reach database": Connection string wrong
DATABASE_URL in .envSlow queries: Missing indexes
@@index([field]) to schemaEXPLAIN ANALYZE on slow queries"Table does not exist" error: Missing migration
relation "Resource" does not existnpx prisma migrate deploy (recommended)npx prisma db push (development)prisma/manual-migration-resource-table.sql manuallyRESOURCE_TABLE_FIX.md for detailed stepsFor detailed troubleshooting: See skill troubleshooting
Database: Supabase PostgreSQL (Free Tier) Status: ✅ RESOLVED with optimization
Comportamento ATUAL - DEPOIS das otimizações:
Build 1, 2, 3... 100, 200 (quantos forem):
├─ Compila TypeScript ✅
└─ Query ao banco? ❌ ZERO
= Builds infinitos, ZERO impacto no banco ✅
Como foi resolvido:
prisma generate no build@prisma/client (npm package)Limitações do Free Tier (Supabase):
Monitoramento:
tokenmilagre-refactoring - Type safety patternstokenmilagre-testing - Database testing strategiestroubleshooting - Database error solutionsproject-context - Overall architectureLast Updated: 2025-11-17 Version: 2.0.0 Mudanças recentes: