project-mcp-server 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +335 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.js +38 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/scanner/actions.d.ts +9 -0
- package/dist/scanner/actions.js +77 -0
- package/dist/scanner/actions.js.map +1 -0
- package/dist/scanner/cache.d.ts +4 -0
- package/dist/scanner/cache.js +34 -0
- package/dist/scanner/cache.js.map +1 -0
- package/dist/scanner/components.d.ts +17 -0
- package/dist/scanner/components.js +74 -0
- package/dist/scanner/components.js.map +1 -0
- package/dist/scanner/prisma.d.ts +17 -0
- package/dist/scanner/prisma.js +75 -0
- package/dist/scanner/prisma.js.map +1 -0
- package/dist/scanner/routes.d.ts +11 -0
- package/dist/scanner/routes.js +98 -0
- package/dist/scanner/routes.js.map +1 -0
- package/dist/setup.d.ts +10 -0
- package/dist/setup.js +289 -0
- package/dist/setup.js.map +1 -0
- package/dist/tools/env/index.d.ts +2 -0
- package/dist/tools/env/index.js +152 -0
- package/dist/tools/env/index.js.map +1 -0
- package/dist/tools/generate/index.d.ts +2 -0
- package/dist/tools/generate/index.js +320 -0
- package/dist/tools/generate/index.js.map +1 -0
- package/dist/tools/project/index.d.ts +2 -0
- package/dist/tools/project/index.js +193 -0
- package/dist/tools/project/index.js.map +1 -0
- package/package.json +35 -0
- package/skills/commit.md +109 -0
- package/skills/infra.md +218 -0
- package/skills/nextauth.md +256 -0
- package/skills/nextjs.md +262 -0
- package/skills/prisma.md +281 -0
- package/skills/project-intelligence.SKILL.md +141 -0
- package/skills/security.md +353 -0
- package/skills/shadcn.md +299 -0
- package/skills/testing.md +188 -0
- package/skills/zod.md +253 -0
package/skills/prisma.md
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: prisma
|
|
3
|
+
description: "Activar cuando se modifican schemas de Prisma, se escriben queries de base de datos o se trabaja con migraciones"
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
version: "1.0.0"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Skill: Prisma 7 — multi-schema
|
|
10
|
+
|
|
11
|
+
## Cuándo cargar esta skill
|
|
12
|
+
- Modificar o crear schemas de Prisma
|
|
13
|
+
- Escribir queries de base de datos
|
|
14
|
+
- Crear o correr migrations
|
|
15
|
+
- Escribir seeds
|
|
16
|
+
- Trabajar con el cliente PostgreSQL o MySQL
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Arquitectura de clientes
|
|
21
|
+
|
|
22
|
+
Este proyecto tiene **dos conexiones** separadas:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// lib/db/postgres.ts — cliente principal (auth, rbac, audit, base)
|
|
26
|
+
import { PrismaClient } from "@prisma/client"
|
|
27
|
+
import { PrismaPg } from "@prisma/adapter-pg"
|
|
28
|
+
import { Pool } from "pg"
|
|
29
|
+
|
|
30
|
+
const pool = new Pool({ connectionString: process.env.DATABASE_URL })
|
|
31
|
+
const adapter = new PrismaPg(pool)
|
|
32
|
+
|
|
33
|
+
export const prismaPostgres = new PrismaClient({ adapter })
|
|
34
|
+
|
|
35
|
+
// lib/db/mysql.ts — cliente secundario
|
|
36
|
+
import { PrismaClient } from "@prisma/mysql-client" // cliente generado para mysql
|
|
37
|
+
import { createPool } from "mysql2/promise"
|
|
38
|
+
import { PrismaMysql } from "@prisma/adapter-mysql" // si aplica
|
|
39
|
+
|
|
40
|
+
export const prismaMySQL = new PrismaClient(...)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Regla**: siempre importar el cliente correcto según el dominio de la entidad.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Estructura de schemas multi-schema
|
|
48
|
+
|
|
49
|
+
```prisma
|
|
50
|
+
// prisma/schema/auth.prisma
|
|
51
|
+
generator client {
|
|
52
|
+
provider = "prisma-client-js"
|
|
53
|
+
previewFeatures = ["multiSchema"]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
datasource db {
|
|
57
|
+
provider = "postgresql"
|
|
58
|
+
url = env("DATABASE_URL")
|
|
59
|
+
schemas = ["auth", "rbac", "audit", "base"]
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
model User {
|
|
63
|
+
id String @id @default(cuid())
|
|
64
|
+
email String @unique
|
|
65
|
+
password String
|
|
66
|
+
createdAt DateTime @default(now())
|
|
67
|
+
updatedAt DateTime @updatedAt
|
|
68
|
+
|
|
69
|
+
@@schema("auth")
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
model Session {
|
|
73
|
+
id String @id @default(cuid())
|
|
74
|
+
sessionToken String @unique
|
|
75
|
+
userId String
|
|
76
|
+
expires DateTime
|
|
77
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
78
|
+
|
|
79
|
+
@@schema("auth")
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
```prisma
|
|
84
|
+
// prisma/schema/rbac.prisma
|
|
85
|
+
model Role {
|
|
86
|
+
id String @id @default(cuid())
|
|
87
|
+
name String @unique
|
|
88
|
+
permissions Permission[]
|
|
89
|
+
users UserRole[]
|
|
90
|
+
|
|
91
|
+
@@schema("rbac")
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
model Permission {
|
|
95
|
+
id String @id @default(cuid())
|
|
96
|
+
action String // ej: "users:create", "posts:delete"
|
|
97
|
+
roleId String
|
|
98
|
+
role Role @relation(fields: [roleId], references: [id])
|
|
99
|
+
|
|
100
|
+
@@schema("rbac")
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Queries con Prisma 7
|
|
107
|
+
|
|
108
|
+
### Patrones correctos de selección
|
|
109
|
+
```typescript
|
|
110
|
+
// ✓ Siempre select explícito — nunca traer campos sensibles por defecto
|
|
111
|
+
const user = await prismaPostgres.user.findUnique({
|
|
112
|
+
where: { id },
|
|
113
|
+
select: {
|
|
114
|
+
id: true,
|
|
115
|
+
email: true,
|
|
116
|
+
name: true,
|
|
117
|
+
// nunca incluir 'password' salvo en contexto de auth
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
// ✓ Include para relaciones — solo lo que se usa en la UI
|
|
122
|
+
const userWithRoles = await prismaPostgres.user.findUnique({
|
|
123
|
+
where: { id },
|
|
124
|
+
include: {
|
|
125
|
+
roles: {
|
|
126
|
+
include: { permissions: true }
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Queries cross-schema (dentro del mismo cliente PostgreSQL)
|
|
133
|
+
```typescript
|
|
134
|
+
// Las relaciones entre schemas se manejan en el schema de Prisma
|
|
135
|
+
// En queries, se accede igual que cualquier relación
|
|
136
|
+
const auditLogs = await prismaPostgres.auditLog.findMany({
|
|
137
|
+
where: { userId: user.id },
|
|
138
|
+
orderBy: { createdAt: "desc" },
|
|
139
|
+
take: 50
|
|
140
|
+
})
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Transactions
|
|
144
|
+
```typescript
|
|
145
|
+
// Para operaciones atómicas entre tablas
|
|
146
|
+
const result = await prismaPostgres.$transaction(async (tx) => {
|
|
147
|
+
const user = await tx.user.create({ data: userData })
|
|
148
|
+
await tx.userRole.create({ data: { userId: user.id, roleId: defaultRoleId } })
|
|
149
|
+
await tx.auditLog.create({ data: { action: "user.created", userId: user.id } })
|
|
150
|
+
return user
|
|
151
|
+
})
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Queries en MySQL (cliente secundario)
|
|
155
|
+
```typescript
|
|
156
|
+
import { prismaMySQL } from "@/lib/db/mysql"
|
|
157
|
+
|
|
158
|
+
const records = await prismaMySQL.legacyRecord.findMany({
|
|
159
|
+
where: { status: "active" }
|
|
160
|
+
})
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Migrations
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
# Crear migration después de cambiar un schema
|
|
169
|
+
pnpm prisma migrate dev --name nombre-descriptivo-en-snake-case
|
|
170
|
+
|
|
171
|
+
# Ejemplos de nombres:
|
|
172
|
+
# add-user-roles-table
|
|
173
|
+
# add-email-verified-to-user
|
|
174
|
+
# create-audit-schema
|
|
175
|
+
# add-permissions-index
|
|
176
|
+
|
|
177
|
+
# Aplicar en producción (no crea archivos, solo aplica pending)
|
|
178
|
+
pnpm prisma migrate deploy
|
|
179
|
+
|
|
180
|
+
# Reset completo (solo en dev)
|
|
181
|
+
pnpm prisma migrate reset
|
|
182
|
+
|
|
183
|
+
# Ver estado de migrations
|
|
184
|
+
pnpm prisma migrate status
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Importante**: nunca editar archivos de migration ya aplicados. Si hay un error,
|
|
188
|
+
crear una nueva migration que lo corrija.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Seeds con tsx
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
// prisma/seeds/roles.ts
|
|
196
|
+
import { prismaPostgres } from "@/lib/db/postgres"
|
|
197
|
+
|
|
198
|
+
const ROLES = [
|
|
199
|
+
{
|
|
200
|
+
name: "admin",
|
|
201
|
+
permissions: ["users:create", "users:delete", "users:read", "posts:*"]
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
name: "editor",
|
|
205
|
+
permissions: ["posts:create", "posts:update", "posts:read"]
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
name: "viewer",
|
|
209
|
+
permissions: ["posts:read", "users:read"]
|
|
210
|
+
}
|
|
211
|
+
]
|
|
212
|
+
|
|
213
|
+
async function seedRoles() {
|
|
214
|
+
console.log("Seeding roles...")
|
|
215
|
+
|
|
216
|
+
for (const roleData of ROLES) {
|
|
217
|
+
const role = await prismaPostgres.role.upsert({
|
|
218
|
+
where: { name: roleData.name },
|
|
219
|
+
update: {},
|
|
220
|
+
create: { name: roleData.name }
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
for (const action of roleData.permissions) {
|
|
224
|
+
await prismaPostgres.permission.upsert({
|
|
225
|
+
where: { roleId_action: { roleId: role.id, action } },
|
|
226
|
+
update: {},
|
|
227
|
+
create: { roleId: role.id, action }
|
|
228
|
+
})
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
console.log("✓ Roles seeded")
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
seedRoles()
|
|
236
|
+
.catch(console.error)
|
|
237
|
+
.finally(() => prismaPostgres.$disconnect())
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
# Correr seed
|
|
242
|
+
pnpm tsx prisma/seeds/roles.ts
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Prisma Studio y herramientas
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
pnpm prisma studio # UI visual para explorar datos (localhost:5555)
|
|
251
|
+
pnpm prisma generate # Regenerar cliente después de cambiar schema
|
|
252
|
+
pnpm prisma db push # Sync schema → DB sin migration (solo en dev)
|
|
253
|
+
pnpm prisma validate # Validar syntax del schema
|
|
254
|
+
pnpm prisma format # Formatear archivos .prisma
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Anti-patrones a evitar
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
// ❌ No hacer queries sin select — expone datos sensibles
|
|
263
|
+
const user = await prismaPostgres.user.findUnique({ where: { id } })
|
|
264
|
+
// Devuelve password hasheado y otros campos sensibles
|
|
265
|
+
|
|
266
|
+
// ❌ No mezclar clientes — MySQL con entidades de PostgreSQL
|
|
267
|
+
import { prismaMySQL } from "@/lib/db/mysql"
|
|
268
|
+
const user = await prismaMySQL.user.findUnique(...) // El modelo User es de PostgreSQL
|
|
269
|
+
|
|
270
|
+
// ❌ No hardcodear IDs de roles o permisos — usar queries o constantes
|
|
271
|
+
const adminRole = await prismaPostgres.role.findUnique({ where: { name: "admin" } })
|
|
272
|
+
|
|
273
|
+
// ❌ No hacer N+1 queries — usar include o select con relaciones
|
|
274
|
+
const users = await prismaPostgres.user.findMany()
|
|
275
|
+
for (const user of users) {
|
|
276
|
+
// ❌ Query por cada usuario
|
|
277
|
+
const roles = await prismaPostgres.userRole.findMany({ where: { userId: user.id } })
|
|
278
|
+
}
|
|
279
|
+
// ✓ Un solo query con include
|
|
280
|
+
const users = await prismaPostgres.user.findMany({ include: { roles: true } })
|
|
281
|
+
```
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: project-intelligence
|
|
3
|
+
description: "Activar cuando se trabaja con SDD en un proyecto Next.js que tiene project-mcp-server configurado como MCP"
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
version: "1.0.0"
|
|
7
|
+
author: "Fernando Secchi"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Project Intelligence para SDD
|
|
11
|
+
|
|
12
|
+
Integra el MCP `project-mcp-server` con el flujo SDD. Este MCP expone 10 tools que dan inteligencia real del proyecto: escaneo de rutas, Server Actions, modelos Prisma, componentes, y generación de código basada en el schema real.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Cuándo cargar esta skill
|
|
17
|
+
|
|
18
|
+
- Cuando se inicia un flujo SDD en un proyecto Next.js con Prisma
|
|
19
|
+
- Cuando se necesita explorar la estructura real del proyecto antes de proponer cambios
|
|
20
|
+
- Cuando se va a generar código que debe respetar convenciones existentes
|
|
21
|
+
- Cuando se necesita verificar que los cambios no rompieron el build
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Fase: sdd-init / sdd-explore
|
|
26
|
+
|
|
27
|
+
Usar `project_scan` para obtener el mapa completo del proyecto antes de proponer cambios:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
project_scan({ force_refresh: true })
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Esto devuelve:
|
|
34
|
+
- Rutas del App Router (páginas, layouts, route handlers)
|
|
35
|
+
- Server Actions existentes con sus schemas Zod
|
|
36
|
+
- Modelos de Prisma con campos y relaciones
|
|
37
|
+
- Componentes UI instalados (shadcn) y custom
|
|
38
|
+
|
|
39
|
+
Con esta información el agente puede identificar seams sin tener que explorar el filesystem manualmente.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Fase: sdd-spec / sdd-design
|
|
44
|
+
|
|
45
|
+
Usar herramientas granulares para detallar el diseño:
|
|
46
|
+
|
|
47
|
+
**Entender la capa de datos:**
|
|
48
|
+
```
|
|
49
|
+
project_models({ schema: "base" })
|
|
50
|
+
```
|
|
51
|
+
Devuelve modelos de Prisma con campos, tipos, relaciones y atributos. Usar para saber qué entidades existen y cómo se relacionan.
|
|
52
|
+
|
|
53
|
+
**Mapear rutas existentes:**
|
|
54
|
+
```
|
|
55
|
+
project_routes({ filter: "all" })
|
|
56
|
+
```
|
|
57
|
+
Devuelve rutas del App Router con: rendering mode (RSC/client), params dinámicos, métodos HTTP (para route handlers), y si tienen loading/error boundaries.
|
|
58
|
+
|
|
59
|
+
**Ver Server Actions existentes:**
|
|
60
|
+
```
|
|
61
|
+
project_actions({ feature: "users" })
|
|
62
|
+
```
|
|
63
|
+
Devuelve actions con: schema Zod asociado, parámetros, flags de auth y revalidación. Usar como referencia de patrones antes de crear nuevas actions.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Fase: sdd-apply
|
|
68
|
+
|
|
69
|
+
Usar generadores que respetan las convenciones del proyecto:
|
|
70
|
+
|
|
71
|
+
**Server Action con Zod + auth + revalidación:**
|
|
72
|
+
```
|
|
73
|
+
generate_action({
|
|
74
|
+
entity: "user",
|
|
75
|
+
operation: "create",
|
|
76
|
+
with_auth: true,
|
|
77
|
+
prisma_schema: "base"
|
|
78
|
+
})
|
|
79
|
+
```
|
|
80
|
+
Genera código basado en el schema de Prisma real del proyecto, no templates genéricos.
|
|
81
|
+
|
|
82
|
+
**Página RSC con metadata y estructura correcta:**
|
|
83
|
+
```
|
|
84
|
+
generate_page({
|
|
85
|
+
path: "/dashboard/users/[id]",
|
|
86
|
+
type: "detail",
|
|
87
|
+
with_auth: true,
|
|
88
|
+
with_metadata: true
|
|
89
|
+
})
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**Componente con cn(), tipado explícito y directiva correcta:**
|
|
93
|
+
```
|
|
94
|
+
generate_component({
|
|
95
|
+
name: "UserCard",
|
|
96
|
+
feature: "users",
|
|
97
|
+
type: "display",
|
|
98
|
+
is_client: false
|
|
99
|
+
})
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Fase: sdd-verify
|
|
105
|
+
|
|
106
|
+
Usar `env_run_check` para validar que los cambios no rompieron nada:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
env_run_check({ check: "typecheck" }) → verificar tipos
|
|
110
|
+
env_run_check({ check: "lint" }) → verificar lint
|
|
111
|
+
env_run_check({ check: "test" }) → correr tests
|
|
112
|
+
env_run_check({ check: "build" }) → verificar build completo
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
También verificar estado de migraciones si hubo cambios en Prisma:
|
|
116
|
+
```
|
|
117
|
+
env_prisma_status()
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Fase: sdd-archive
|
|
123
|
+
|
|
124
|
+
Usar `env_status()` para confirmar que el entorno quedó sano después de los cambios. Los resultados se pueden guardar en Engram como observación de tipo `context`.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Tools disponibles (referencia rápida)
|
|
129
|
+
|
|
130
|
+
| Tool | Fase SDD | Descripción |
|
|
131
|
+
|------|----------|-------------|
|
|
132
|
+
| `project_scan` | explore | Mapa completo del proyecto |
|
|
133
|
+
| `project_routes` | spec/design | Rutas del App Router |
|
|
134
|
+
| `project_actions` | spec/design | Server Actions con schemas |
|
|
135
|
+
| `project_models` | spec/design | Modelos Prisma con campos |
|
|
136
|
+
| `env_status` | init/archive | Estado del entorno |
|
|
137
|
+
| `env_run_check` | verify | Typecheck, lint, test, build |
|
|
138
|
+
| `env_prisma_status` | verify | Estado de migraciones |
|
|
139
|
+
| `generate_action` | apply | Generar Server Action |
|
|
140
|
+
| `generate_page` | apply | Generar página RSC |
|
|
141
|
+
| `generate_component` | apply | Generar componente React |
|