@girardmedia/bootspring 1.2.0 → 2.0.3
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/README.md +107 -14
- package/bin/bootspring.js +166 -27
- package/cli/agent.js +189 -17
- package/cli/analyze.js +499 -0
- package/cli/audit.js +557 -0
- package/cli/auth.js +495 -38
- package/cli/billing.js +302 -0
- package/cli/build.js +695 -0
- package/cli/business.js +109 -26
- package/cli/checkpoint-utils.js +168 -0
- package/cli/checkpoint.js +639 -0
- package/cli/cloud-sync.js +447 -0
- package/cli/content.js +198 -0
- package/cli/context.js +1 -1
- package/cli/deploy.js +543 -0
- package/cli/fundraise.js +112 -50
- package/cli/github-cmd.js +435 -0
- package/cli/health.js +477 -0
- package/cli/init.js +84 -13
- package/cli/legal.js +107 -95
- package/cli/log.js +2 -2
- package/cli/loop.js +976 -73
- package/cli/manager.js +711 -0
- package/cli/metrics.js +480 -0
- package/cli/monitor.js +812 -0
- package/cli/onboard.js +521 -0
- package/cli/orchestrator.js +12 -24
- package/cli/prd.js +594 -0
- package/cli/preseed-start.js +1483 -0
- package/cli/preseed.js +2302 -0
- package/cli/project.js +436 -0
- package/cli/quality.js +233 -0
- package/cli/security.js +913 -0
- package/cli/seed.js +1441 -5
- package/cli/skill.js +273 -211
- package/cli/suggest.js +989 -0
- package/cli/switch.js +453 -0
- package/cli/visualize.js +527 -0
- package/cli/watch.js +769 -0
- package/cli/workspace.js +607 -0
- package/core/analyze-workflow.js +1134 -0
- package/core/api-client.js +535 -22
- package/core/audit-workflow.js +1350 -0
- package/core/build-orchestrator.js +480 -0
- package/core/build-state.js +577 -0
- package/core/checkpoint-engine.js +408 -0
- package/core/config.js +1109 -26
- package/core/context-loader.js +21 -1
- package/core/deploy-workflow.js +836 -0
- package/core/entitlements.js +93 -22
- package/core/github-sync.js +610 -0
- package/core/index.js +8 -1
- package/core/ingest.js +1111 -0
- package/core/metrics-engine.js +768 -0
- package/core/onboard-workflow.js +1007 -0
- package/core/preseed-workflow.js +934 -0
- package/core/preseed.js +1617 -0
- package/core/project-context.js +325 -0
- package/core/project-state.js +694 -0
- package/core/r2-sync.js +583 -0
- package/core/scaffold.js +525 -7
- package/core/session.js +258 -0
- package/core/task-extractor.js +758 -0
- package/core/telemetry.js +28 -6
- package/core/tier-enforcement.js +737 -0
- package/core/utils.js +38 -14
- package/generators/questionnaire.js +15 -12
- package/generators/sections/ai.js +7 -7
- package/generators/sections/content.js +300 -0
- package/generators/sections/index.js +3 -0
- package/generators/sections/plugins.js +7 -6
- package/generators/templates/build-planning.template.js +596 -0
- package/generators/templates/content.template.js +819 -0
- package/generators/templates/index.js +2 -1
- package/hooks/git-autopilot.js +1250 -0
- package/hooks/index.js +9 -0
- package/intelligence/agent-collab.js +2057 -0
- package/intelligence/auto-suggest.js +634 -0
- package/intelligence/content-gen.js +1589 -0
- package/intelligence/cross-project.js +1647 -0
- package/intelligence/index.js +184 -0
- package/intelligence/learning/insights.json +517 -7
- package/intelligence/learning/pattern-learner.js +1008 -14
- package/intelligence/memory/decision-tracker.js +1431 -31
- package/intelligence/memory/decisions.jsonl +0 -0
- package/intelligence/orchestrator.js +2896 -1
- package/intelligence/prd.js +92 -1
- package/intelligence/recommendation-weights.json +14 -2
- package/intelligence/recommendations.js +463 -9
- package/intelligence/workflow-composer.js +1451 -0
- package/marketplace/index.d.ts +324 -0
- package/marketplace/index.js +1921 -0
- package/mcp/contracts/mcp-contract.v1.json +342 -4
- package/mcp/registry.js +680 -3
- package/mcp/response-formatter.js +23 -0
- package/mcp/tools/assist-tool.js +78 -4
- package/mcp/tools/autopilot-tool.js +408 -0
- package/mcp/tools/content-tool.js +571 -0
- package/mcp/tools/dashboard-tool.js +251 -5
- package/mcp/tools/mvp-tool.js +344 -0
- package/mcp/tools/plugin-tool.js +23 -1
- package/mcp/tools/prd-tool.js +579 -0
- package/mcp/tools/seed-tool.js +447 -0
- package/mcp/tools/skill-tool.js +43 -14
- package/mcp/tools/suggest-tool.js +147 -0
- package/package.json +15 -6
- package/agents/README.md +0 -93
- package/agents/ai-integration-expert/context.md +0 -386
- package/agents/api-expert/context.md +0 -416
- package/agents/architecture-expert/context.md +0 -454
- package/agents/auth-expert/context.md +0 -399
- package/agents/backend-expert/context.md +0 -483
- package/agents/business-strategy-expert/context.md +0 -180
- package/agents/code-review-expert/context.md +0 -365
- package/agents/competitive-analysis-expert/context.md +0 -239
- package/agents/data-modeling-expert/context.md +0 -352
- package/agents/database-expert/context.md +0 -250
- package/agents/devops-expert/context.md +0 -446
- package/agents/email-expert/context.md +0 -379
- package/agents/financial-expert/context.md +0 -213
- package/agents/frontend-expert/context.md +0 -364
- package/agents/fundraising-expert/context.md +0 -257
- package/agents/growth-expert/context.md +0 -249
- package/agents/index.js +0 -140
- package/agents/investor-relations-expert/context.md +0 -266
- package/agents/legal-expert/context.md +0 -284
- package/agents/marketing-expert/context.md +0 -236
- package/agents/monitoring-expert/context.md +0 -362
- package/agents/operations-expert/context.md +0 -279
- package/agents/partnerships-expert/context.md +0 -286
- package/agents/payment-expert/context.md +0 -340
- package/agents/performance-expert/context.md +0 -377
- package/agents/private-equity-expert/context.md +0 -246
- package/agents/railway-expert/context.md +0 -284
- package/agents/research-expert/context.md +0 -245
- package/agents/sales-expert/context.md +0 -241
- package/agents/security-expert/context.md +0 -343
- package/agents/testing-expert/context.md +0 -414
- package/agents/ui-ux-expert/context.md +0 -448
- package/agents/vercel-expert/context.md +0 -426
- package/skills/index.js +0 -787
- package/skills/patterns/README.md +0 -163
- package/skills/patterns/ai/agents.md +0 -281
- package/skills/patterns/ai/claude.md +0 -138
- package/skills/patterns/ai/embeddings.md +0 -150
- package/skills/patterns/ai/rag.md +0 -266
- package/skills/patterns/ai/streaming.md +0 -170
- package/skills/patterns/ai/structured-output.md +0 -162
- package/skills/patterns/ai/tools.md +0 -154
- package/skills/patterns/analytics/tracking.md +0 -220
- package/skills/patterns/api/errors.md +0 -296
- package/skills/patterns/api/graphql.md +0 -440
- package/skills/patterns/api/middleware.md +0 -279
- package/skills/patterns/api/openapi.md +0 -285
- package/skills/patterns/api/rate-limiting.md +0 -231
- package/skills/patterns/api/route-handler.md +0 -217
- package/skills/patterns/api/server-action.md +0 -249
- package/skills/patterns/api/versioning.md +0 -443
- package/skills/patterns/api/webhooks.md +0 -247
- package/skills/patterns/auth/clerk.md +0 -132
- package/skills/patterns/auth/mfa.md +0 -313
- package/skills/patterns/auth/nextauth.md +0 -140
- package/skills/patterns/auth/oauth.md +0 -237
- package/skills/patterns/auth/rbac.md +0 -152
- package/skills/patterns/auth/session-management.md +0 -367
- package/skills/patterns/auth/session.md +0 -120
- package/skills/patterns/database/audit.md +0 -177
- package/skills/patterns/database/migrations.md +0 -177
- package/skills/patterns/database/pagination.md +0 -230
- package/skills/patterns/database/pooling.md +0 -357
- package/skills/patterns/database/prisma.md +0 -180
- package/skills/patterns/database/relations.md +0 -187
- package/skills/patterns/database/seeding.md +0 -246
- package/skills/patterns/database/soft-delete.md +0 -153
- package/skills/patterns/database/transactions.md +0 -162
- package/skills/patterns/deployment/ci-cd.md +0 -231
- package/skills/patterns/deployment/docker.md +0 -188
- package/skills/patterns/deployment/monitoring.md +0 -387
- package/skills/patterns/deployment/vercel.md +0 -160
- package/skills/patterns/email/resend.md +0 -143
- package/skills/patterns/email/templates.md +0 -245
- package/skills/patterns/email/transactional.md +0 -503
- package/skills/patterns/email/verification.md +0 -176
- package/skills/patterns/files/download.md +0 -243
- package/skills/patterns/files/upload.md +0 -239
- package/skills/patterns/i18n/nextintl.md +0 -188
- package/skills/patterns/logging/structured.md +0 -292
- package/skills/patterns/notifications/email-queue.md +0 -248
- package/skills/patterns/notifications/push.md +0 -279
- package/skills/patterns/payments/checkout.md +0 -303
- package/skills/patterns/payments/invoices.md +0 -287
- package/skills/patterns/payments/portal.md +0 -245
- package/skills/patterns/payments/stripe.md +0 -272
- package/skills/patterns/payments/subscriptions.md +0 -300
- package/skills/patterns/payments/usage.md +0 -279
- package/skills/patterns/performance/caching.md +0 -276
- package/skills/patterns/performance/code-splitting.md +0 -233
- package/skills/patterns/performance/edge.md +0 -254
- package/skills/patterns/performance/isr.md +0 -266
- package/skills/patterns/performance/lazy-loading.md +0 -281
- package/skills/patterns/realtime/sse.md +0 -327
- package/skills/patterns/realtime/websockets.md +0 -336
- package/skills/patterns/search/filtering.md +0 -329
- package/skills/patterns/search/fulltext.md +0 -260
- package/skills/patterns/security/audit-logging.md +0 -444
- package/skills/patterns/security/csrf.md +0 -234
- package/skills/patterns/security/headers.md +0 -252
- package/skills/patterns/security/sanitization.md +0 -258
- package/skills/patterns/security/secrets.md +0 -261
- package/skills/patterns/security/validation.md +0 -268
- package/skills/patterns/security/xss.md +0 -229
- package/skills/patterns/seo/metadata.md +0 -252
- package/skills/patterns/state/context.md +0 -349
- package/skills/patterns/state/react-query.md +0 -313
- package/skills/patterns/state/url-state.md +0 -482
- package/skills/patterns/state/zustand.md +0 -262
- package/skills/patterns/testing/api.md +0 -259
- package/skills/patterns/testing/component.md +0 -233
- package/skills/patterns/testing/coverage.md +0 -207
- package/skills/patterns/testing/fixtures.md +0 -225
- package/skills/patterns/testing/integration.md +0 -436
- package/skills/patterns/testing/mocking.md +0 -177
- package/skills/patterns/testing/playwright.md +0 -162
- package/skills/patterns/testing/snapshot.md +0 -175
- package/skills/patterns/testing/vitest.md +0 -307
- package/skills/patterns/ui/accordions.md +0 -395
- package/skills/patterns/ui/cards.md +0 -299
- package/skills/patterns/ui/dropdowns.md +0 -476
- package/skills/patterns/ui/empty-states.md +0 -320
- package/skills/patterns/ui/forms.md +0 -405
- package/skills/patterns/ui/inputs.md +0 -319
- package/skills/patterns/ui/layouts.md +0 -282
- package/skills/patterns/ui/loading.md +0 -291
- package/skills/patterns/ui/modals.md +0 -338
- package/skills/patterns/ui/navigation.md +0 -374
- package/skills/patterns/ui/tables.md +0 -407
- package/skills/patterns/ui/toasts.md +0 -300
- package/skills/patterns/ui/tooltips.md +0 -396
- package/skills/patterns/utils/dates.md +0 -435
- package/skills/patterns/utils/errors.md +0 -451
- package/skills/patterns/utils/formatting.md +0 -345
- package/skills/patterns/utils/validation.md +0 -434
- package/templates/bootspring.config.js +0 -83
- package/templates/business/business-model-canvas.md +0 -246
- package/templates/business/business-plan.md +0 -266
- package/templates/business/competitive-analysis.md +0 -312
- package/templates/fundraising/data-room-checklist.md +0 -300
- package/templates/fundraising/investor-research.md +0 -243
- package/templates/fundraising/pitch-deck-outline.md +0 -253
- package/templates/legal/gdpr-checklist.md +0 -339
- package/templates/legal/privacy-policy.md +0 -285
- package/templates/legal/terms-of-service.md +0 -222
- package/templates/mcp.json +0 -9
|
@@ -1,352 +0,0 @@
|
|
|
1
|
-
# Data Modeling Expert Agent
|
|
2
|
-
|
|
3
|
-
## Role
|
|
4
|
-
Specialized in database design, entity relationship modeling, schema design, and data architecture for applications.
|
|
5
|
-
|
|
6
|
-
## Core Expertise
|
|
7
|
-
|
|
8
|
-
### Entity Relationship Design
|
|
9
|
-
|
|
10
|
-
```markdown
|
|
11
|
-
## ERD Design Process
|
|
12
|
-
|
|
13
|
-
### 1. Identify Entities
|
|
14
|
-
- Core business objects
|
|
15
|
-
- Supporting entities
|
|
16
|
-
- Junction tables for many-to-many
|
|
17
|
-
|
|
18
|
-
### 2. Define Attributes
|
|
19
|
-
- Primary keys
|
|
20
|
-
- Required vs optional
|
|
21
|
-
- Data types
|
|
22
|
-
- Constraints
|
|
23
|
-
|
|
24
|
-
### 3. Establish Relationships
|
|
25
|
-
- One-to-one (1:1)
|
|
26
|
-
- One-to-many (1:N)
|
|
27
|
-
- Many-to-many (M:N)
|
|
28
|
-
|
|
29
|
-
### 4. Normalize
|
|
30
|
-
- Remove redundancy
|
|
31
|
-
- Ensure data integrity
|
|
32
|
-
- Balance with performance
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### Prisma Schema Patterns
|
|
36
|
-
|
|
37
|
-
```prisma
|
|
38
|
-
// schema.prisma - Common patterns
|
|
39
|
-
|
|
40
|
-
// User with relations
|
|
41
|
-
model User {
|
|
42
|
-
id String @id @default(cuid())
|
|
43
|
-
email String @unique
|
|
44
|
-
name String?
|
|
45
|
-
role Role @default(USER)
|
|
46
|
-
createdAt DateTime @default(now())
|
|
47
|
-
updatedAt DateTime @updatedAt
|
|
48
|
-
|
|
49
|
-
// Relations
|
|
50
|
-
profile Profile?
|
|
51
|
-
posts Post[]
|
|
52
|
-
teams TeamMember[]
|
|
53
|
-
|
|
54
|
-
@@index([email])
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
model Profile {
|
|
58
|
-
id String @id @default(cuid())
|
|
59
|
-
bio String?
|
|
60
|
-
avatar String?
|
|
61
|
-
userId String @unique
|
|
62
|
-
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// One-to-many
|
|
66
|
-
model Post {
|
|
67
|
-
id String @id @default(cuid())
|
|
68
|
-
title String
|
|
69
|
-
content String?
|
|
70
|
-
published Boolean @default(false)
|
|
71
|
-
authorId String
|
|
72
|
-
author User @relation(fields: [authorId], references: [id])
|
|
73
|
-
categories Category[]
|
|
74
|
-
createdAt DateTime @default(now())
|
|
75
|
-
updatedAt DateTime @updatedAt
|
|
76
|
-
|
|
77
|
-
@@index([authorId])
|
|
78
|
-
@@index([published, createdAt])
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Many-to-many (implicit)
|
|
82
|
-
model Category {
|
|
83
|
-
id String @id @default(cuid())
|
|
84
|
-
name String @unique
|
|
85
|
-
posts Post[]
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Many-to-many (explicit - with extra fields)
|
|
89
|
-
model Team {
|
|
90
|
-
id String @id @default(cuid())
|
|
91
|
-
name String
|
|
92
|
-
members TeamMember[]
|
|
93
|
-
createdAt DateTime @default(now())
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
model TeamMember {
|
|
97
|
-
id String @id @default(cuid())
|
|
98
|
-
userId String
|
|
99
|
-
teamId String
|
|
100
|
-
role TeamRole @default(MEMBER)
|
|
101
|
-
joinedAt DateTime @default(now())
|
|
102
|
-
|
|
103
|
-
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
104
|
-
team Team @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
|
105
|
-
|
|
106
|
-
@@unique([userId, teamId])
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
enum Role {
|
|
110
|
-
USER
|
|
111
|
-
ADMIN
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
enum TeamRole {
|
|
115
|
-
OWNER
|
|
116
|
-
ADMIN
|
|
117
|
-
MEMBER
|
|
118
|
-
}
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
### SaaS Data Model
|
|
122
|
-
|
|
123
|
-
```prisma
|
|
124
|
-
// Complete SaaS schema pattern
|
|
125
|
-
|
|
126
|
-
// Organizations (multi-tenant)
|
|
127
|
-
model Organization {
|
|
128
|
-
id String @id @default(cuid())
|
|
129
|
-
name String
|
|
130
|
-
slug String @unique
|
|
131
|
-
plan Plan @default(FREE)
|
|
132
|
-
stripeId String? @unique
|
|
133
|
-
members OrganizationMember[]
|
|
134
|
-
projects Project[]
|
|
135
|
-
subscription Subscription?
|
|
136
|
-
createdAt DateTime @default(now())
|
|
137
|
-
updatedAt DateTime @updatedAt
|
|
138
|
-
|
|
139
|
-
@@index([slug])
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
model OrganizationMember {
|
|
143
|
-
id String @id @default(cuid())
|
|
144
|
-
organizationId String
|
|
145
|
-
userId String
|
|
146
|
-
role OrgRole @default(MEMBER)
|
|
147
|
-
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
148
|
-
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
149
|
-
|
|
150
|
-
@@unique([organizationId, userId])
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Subscriptions
|
|
154
|
-
model Subscription {
|
|
155
|
-
id String @id @default(cuid())
|
|
156
|
-
organizationId String @unique
|
|
157
|
-
stripeSubscriptionId String @unique
|
|
158
|
-
stripePriceId String
|
|
159
|
-
status SubStatus
|
|
160
|
-
currentPeriodStart DateTime
|
|
161
|
-
currentPeriodEnd DateTime
|
|
162
|
-
cancelAtPeriodEnd Boolean @default(false)
|
|
163
|
-
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
enum Plan {
|
|
167
|
-
FREE
|
|
168
|
-
PRO
|
|
169
|
-
TEAM
|
|
170
|
-
ENTERPRISE
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
enum SubStatus {
|
|
174
|
-
ACTIVE
|
|
175
|
-
CANCELED
|
|
176
|
-
PAST_DUE
|
|
177
|
-
TRIALING
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
enum OrgRole {
|
|
181
|
-
OWNER
|
|
182
|
-
ADMIN
|
|
183
|
-
MEMBER
|
|
184
|
-
}
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### Soft Delete Pattern
|
|
188
|
-
|
|
189
|
-
```prisma
|
|
190
|
-
// Soft delete model
|
|
191
|
-
model Document {
|
|
192
|
-
id String @id @default(cuid())
|
|
193
|
-
title String
|
|
194
|
-
content String?
|
|
195
|
-
deletedAt DateTime? // Soft delete marker
|
|
196
|
-
createdAt DateTime @default(now())
|
|
197
|
-
updatedAt DateTime @updatedAt
|
|
198
|
-
|
|
199
|
-
@@index([deletedAt])
|
|
200
|
-
}
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
```typescript
|
|
204
|
-
// Prisma middleware for soft delete
|
|
205
|
-
import { Prisma } from '@prisma/client';
|
|
206
|
-
|
|
207
|
-
// Middleware to filter soft-deleted records
|
|
208
|
-
prisma.$use(async (params, next) => {
|
|
209
|
-
if (params.model === 'Document') {
|
|
210
|
-
if (params.action === 'findMany' || params.action === 'findFirst') {
|
|
211
|
-
params.args.where = {
|
|
212
|
-
...params.args.where,
|
|
213
|
-
deletedAt: null,
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
if (params.action === 'delete') {
|
|
218
|
-
params.action = 'update';
|
|
219
|
-
params.args.data = { deletedAt: new Date() };
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
if (params.action === 'deleteMany') {
|
|
223
|
-
params.action = 'updateMany';
|
|
224
|
-
params.args.data = { deletedAt: new Date() };
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
return next(params);
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
// Helper to include deleted
|
|
231
|
-
const withDeleted = { deletedAt: undefined };
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
### Audit Log Pattern
|
|
235
|
-
|
|
236
|
-
```prisma
|
|
237
|
-
model AuditLog {
|
|
238
|
-
id String @id @default(cuid())
|
|
239
|
-
entityType String // "User", "Post", etc.
|
|
240
|
-
entityId String
|
|
241
|
-
action String // "CREATE", "UPDATE", "DELETE"
|
|
242
|
-
changes Json? // What changed
|
|
243
|
-
userId String? // Who made the change
|
|
244
|
-
user User? @relation(fields: [userId], references: [id])
|
|
245
|
-
ipAddress String?
|
|
246
|
-
userAgent String?
|
|
247
|
-
createdAt DateTime @default(now())
|
|
248
|
-
|
|
249
|
-
@@index([entityType, entityId])
|
|
250
|
-
@@index([userId])
|
|
251
|
-
@@index([createdAt])
|
|
252
|
-
}
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
```typescript
|
|
256
|
-
// Audit log middleware
|
|
257
|
-
async function createAuditLog(
|
|
258
|
-
action: string,
|
|
259
|
-
entityType: string,
|
|
260
|
-
entityId: string,
|
|
261
|
-
changes?: object,
|
|
262
|
-
userId?: string
|
|
263
|
-
) {
|
|
264
|
-
await prisma.auditLog.create({
|
|
265
|
-
data: {
|
|
266
|
-
action,
|
|
267
|
-
entityType,
|
|
268
|
-
entityId,
|
|
269
|
-
changes: changes ? JSON.stringify(changes) : null,
|
|
270
|
-
userId,
|
|
271
|
-
},
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
### Indexing Strategy
|
|
277
|
-
|
|
278
|
-
```prisma
|
|
279
|
-
// Index examples
|
|
280
|
-
|
|
281
|
-
model Product {
|
|
282
|
-
id String @id @default(cuid())
|
|
283
|
-
name String
|
|
284
|
-
price Decimal @db.Decimal(10, 2)
|
|
285
|
-
category String
|
|
286
|
-
status String
|
|
287
|
-
createdAt DateTime @default(now())
|
|
288
|
-
|
|
289
|
-
// Single column index
|
|
290
|
-
@@index([category])
|
|
291
|
-
|
|
292
|
-
// Composite index (order matters!)
|
|
293
|
-
@@index([category, status])
|
|
294
|
-
|
|
295
|
-
// For sorting
|
|
296
|
-
@@index([createdAt(sort: Desc)])
|
|
297
|
-
|
|
298
|
-
// For text search (PostgreSQL)
|
|
299
|
-
// @@index([name], type: Gin)
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// Index Guidelines:
|
|
303
|
-
// - Index foreign keys
|
|
304
|
-
// - Index columns used in WHERE
|
|
305
|
-
// - Index columns used in ORDER BY
|
|
306
|
-
// - Consider composite indexes for common queries
|
|
307
|
-
// - Don't over-index (slows writes)
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
### Data Migration Pattern
|
|
311
|
-
|
|
312
|
-
```typescript
|
|
313
|
-
// migrations/add-slug-to-posts.ts
|
|
314
|
-
import { prisma } from '@/lib/db';
|
|
315
|
-
import { slugify } from '@/lib/utils';
|
|
316
|
-
|
|
317
|
-
async function migrate() {
|
|
318
|
-
const posts = await prisma.post.findMany({
|
|
319
|
-
where: { slug: null },
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
for (const post of posts) {
|
|
323
|
-
const slug = slugify(post.title);
|
|
324
|
-
|
|
325
|
-
await prisma.post.update({
|
|
326
|
-
where: { id: post.id },
|
|
327
|
-
data: { slug },
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
console.log(`Migrated ${posts.length} posts`);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
migrate()
|
|
335
|
-
.catch(console.error)
|
|
336
|
-
.finally(() => prisma.$disconnect());
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
## Data Modeling Checklist
|
|
340
|
-
|
|
341
|
-
- [ ] Entities identified
|
|
342
|
-
- [ ] Relationships mapped
|
|
343
|
-
- [ ] Primary keys defined
|
|
344
|
-
- [ ] Foreign keys established
|
|
345
|
-
- [ ] Indexes planned
|
|
346
|
-
- [ ] Constraints added
|
|
347
|
-
- [ ] Soft delete considered
|
|
348
|
-
- [ ] Audit logging planned
|
|
349
|
-
- [ ] Migration strategy set
|
|
350
|
-
|
|
351
|
-
## Trigger Keywords
|
|
352
|
-
data model, schema, database, ERD, entity, relationship, Prisma, migration, index, foreign key, normalization
|
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
# Database Expert Agent
|
|
2
|
-
|
|
3
|
-
## Role
|
|
4
|
-
Specialized in database design, ORM configuration, query optimization, and data modeling for modern web applications.
|
|
5
|
-
|
|
6
|
-
## Core Expertise
|
|
7
|
-
|
|
8
|
-
### Schema Design
|
|
9
|
-
- Relational database normalization (1NF through BCNF)
|
|
10
|
-
- Denormalization strategies for read-heavy workloads
|
|
11
|
-
- Index design and optimization
|
|
12
|
-
- Constraint enforcement (foreign keys, unique, check)
|
|
13
|
-
- Soft delete patterns vs hard delete
|
|
14
|
-
- Audit trail implementation
|
|
15
|
-
|
|
16
|
-
### ORM Mastery
|
|
17
|
-
|
|
18
|
-
#### Prisma
|
|
19
|
-
```prisma
|
|
20
|
-
// Example: User with relations
|
|
21
|
-
model User {
|
|
22
|
-
id String @id @default(cuid())
|
|
23
|
-
email String @unique
|
|
24
|
-
name String?
|
|
25
|
-
posts Post[]
|
|
26
|
-
profile Profile?
|
|
27
|
-
createdAt DateTime @default(now())
|
|
28
|
-
updatedAt DateTime @updatedAt
|
|
29
|
-
deletedAt DateTime? // Soft delete
|
|
30
|
-
|
|
31
|
-
@@index([email])
|
|
32
|
-
@@map("users")
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
model Post {
|
|
36
|
-
id String @id @default(cuid())
|
|
37
|
-
title String
|
|
38
|
-
content String?
|
|
39
|
-
published Boolean @default(false)
|
|
40
|
-
author User @relation(fields: [authorId], references: [id])
|
|
41
|
-
authorId String
|
|
42
|
-
|
|
43
|
-
@@index([authorId, published])
|
|
44
|
-
}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
#### Drizzle
|
|
48
|
-
```typescript
|
|
49
|
-
// Example: Type-safe schema
|
|
50
|
-
import { pgTable, text, timestamp, boolean, index } from 'drizzle-orm/pg-core';
|
|
51
|
-
|
|
52
|
-
export const users = pgTable('users', {
|
|
53
|
-
id: text('id').primaryKey().$defaultFn(() => createId()),
|
|
54
|
-
email: text('email').notNull().unique(),
|
|
55
|
-
name: text('name'),
|
|
56
|
-
createdAt: timestamp('created_at').defaultNow().notNull(),
|
|
57
|
-
updatedAt: timestamp('updated_at').defaultNow().notNull(),
|
|
58
|
-
deletedAt: timestamp('deleted_at'),
|
|
59
|
-
}, (table) => ({
|
|
60
|
-
emailIdx: index('email_idx').on(table.email),
|
|
61
|
-
}));
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### Query Patterns
|
|
65
|
-
|
|
66
|
-
#### Efficient Queries
|
|
67
|
-
```typescript
|
|
68
|
-
// Prisma: Selective loading
|
|
69
|
-
const user = await prisma.user.findUnique({
|
|
70
|
-
where: { id },
|
|
71
|
-
select: {
|
|
72
|
-
id: true,
|
|
73
|
-
email: true,
|
|
74
|
-
posts: {
|
|
75
|
-
where: { published: true },
|
|
76
|
-
take: 10,
|
|
77
|
-
orderBy: { createdAt: 'desc' }
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
// Drizzle: Join with conditions
|
|
83
|
-
const result = await db
|
|
84
|
-
.select({
|
|
85
|
-
user: users,
|
|
86
|
-
postCount: sql<number>`count(${posts.id})`
|
|
87
|
-
})
|
|
88
|
-
.from(users)
|
|
89
|
-
.leftJoin(posts, eq(posts.authorId, users.id))
|
|
90
|
-
.where(isNull(users.deletedAt))
|
|
91
|
-
.groupBy(users.id);
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
#### Transaction Patterns
|
|
95
|
-
```typescript
|
|
96
|
-
// Prisma transaction
|
|
97
|
-
const result = await prisma.$transaction(async (tx) => {
|
|
98
|
-
const user = await tx.user.create({ data: userData });
|
|
99
|
-
await tx.profile.create({
|
|
100
|
-
data: { ...profileData, userId: user.id }
|
|
101
|
-
});
|
|
102
|
-
return user;
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
// Drizzle transaction
|
|
106
|
-
const result = await db.transaction(async (tx) => {
|
|
107
|
-
const [user] = await tx.insert(users).values(userData).returning();
|
|
108
|
-
await tx.insert(profiles).values({ ...profileData, userId: user.id });
|
|
109
|
-
return user;
|
|
110
|
-
});
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
### Migration Strategies
|
|
114
|
-
|
|
115
|
-
#### Safe Migration Practices
|
|
116
|
-
1. **Always backup before migrations**
|
|
117
|
-
2. **Test migrations on staging first**
|
|
118
|
-
3. **Use transactions when possible**
|
|
119
|
-
4. **Plan for rollback scenarios**
|
|
120
|
-
|
|
121
|
-
```bash
|
|
122
|
-
# Prisma
|
|
123
|
-
npx prisma migrate dev --name add_user_status
|
|
124
|
-
npx prisma migrate deploy # Production
|
|
125
|
-
|
|
126
|
-
# Drizzle
|
|
127
|
-
npx drizzle-kit generate:pg
|
|
128
|
-
npx drizzle-kit push:pg
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
#### Data Migration Pattern
|
|
132
|
-
```typescript
|
|
133
|
-
// Safe data migration with batching
|
|
134
|
-
async function migrateUserStatuses(batchSize = 1000) {
|
|
135
|
-
let processed = 0;
|
|
136
|
-
|
|
137
|
-
while (true) {
|
|
138
|
-
const users = await prisma.user.findMany({
|
|
139
|
-
where: { status: null },
|
|
140
|
-
take: batchSize,
|
|
141
|
-
select: { id: true }
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
if (users.length === 0) break;
|
|
145
|
-
|
|
146
|
-
await prisma.user.updateMany({
|
|
147
|
-
where: { id: { in: users.map(u => u.id) } },
|
|
148
|
-
data: { status: 'active' }
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
processed += users.length;
|
|
152
|
-
console.log(`Migrated ${processed} users`);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
## Performance Optimization
|
|
158
|
-
|
|
159
|
-
### Index Strategy
|
|
160
|
-
```sql
|
|
161
|
-
-- Composite index for common queries
|
|
162
|
-
CREATE INDEX idx_posts_author_published
|
|
163
|
-
ON posts(author_id, published)
|
|
164
|
-
WHERE deleted_at IS NULL;
|
|
165
|
-
|
|
166
|
-
-- Partial index for specific conditions
|
|
167
|
-
CREATE INDEX idx_users_active
|
|
168
|
-
ON users(email)
|
|
169
|
-
WHERE status = 'active';
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### Query Analysis
|
|
173
|
-
```sql
|
|
174
|
-
-- Check query plan
|
|
175
|
-
EXPLAIN ANALYZE
|
|
176
|
-
SELECT * FROM posts
|
|
177
|
-
WHERE author_id = 'xxx' AND published = true;
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
### Connection Pooling
|
|
181
|
-
```typescript
|
|
182
|
-
// Prisma connection config
|
|
183
|
-
const prisma = new PrismaClient({
|
|
184
|
-
datasources: {
|
|
185
|
-
db: {
|
|
186
|
-
url: process.env.DATABASE_URL,
|
|
187
|
-
},
|
|
188
|
-
},
|
|
189
|
-
// Connection pool settings via URL params
|
|
190
|
-
// ?connection_limit=10&pool_timeout=20
|
|
191
|
-
});
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
## Common Patterns
|
|
195
|
-
|
|
196
|
-
### Repository Pattern
|
|
197
|
-
```typescript
|
|
198
|
-
// Type-safe repository
|
|
199
|
-
class UserRepository {
|
|
200
|
-
constructor(private prisma: PrismaClient) {}
|
|
201
|
-
|
|
202
|
-
async findById(id: string) {
|
|
203
|
-
return this.prisma.user.findUnique({ where: { id } });
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
async findByEmail(email: string) {
|
|
207
|
-
return this.prisma.user.findUnique({ where: { email } });
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
async create(data: Prisma.UserCreateInput) {
|
|
211
|
-
return this.prisma.user.create({ data });
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
async softDelete(id: string) {
|
|
215
|
-
return this.prisma.user.update({
|
|
216
|
-
where: { id },
|
|
217
|
-
data: { deletedAt: new Date() }
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
### Pagination
|
|
224
|
-
```typescript
|
|
225
|
-
// Cursor-based pagination (more efficient)
|
|
226
|
-
async function getPaginatedPosts(cursor?: string, limit = 20) {
|
|
227
|
-
return prisma.post.findMany({
|
|
228
|
-
take: limit + 1, // Fetch one extra to check hasMore
|
|
229
|
-
cursor: cursor ? { id: cursor } : undefined,
|
|
230
|
-
skip: cursor ? 1 : 0,
|
|
231
|
-
orderBy: { createdAt: 'desc' }
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
## Checklist for Database Work
|
|
237
|
-
|
|
238
|
-
- [ ] Schema follows naming conventions (snake_case for columns)
|
|
239
|
-
- [ ] Appropriate indexes for query patterns
|
|
240
|
-
- [ ] Foreign key constraints defined
|
|
241
|
-
- [ ] Soft delete considered for important data
|
|
242
|
-
- [ ] Timestamps (created_at, updated_at) included
|
|
243
|
-
- [ ] Migration is reversible
|
|
244
|
-
- [ ] N+1 queries avoided
|
|
245
|
-
- [ ] Connection pooling configured
|
|
246
|
-
- [ ] Sensitive data encrypted at rest
|
|
247
|
-
- [ ] Backup strategy in place
|
|
248
|
-
|
|
249
|
-
## Trigger Keywords
|
|
250
|
-
database, schema, prisma, drizzle, migration, query, model, relation, index, orm, sql, postgres, mysql, mongodb, transaction, seed, foreign key, constraint
|