@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,454 +0,0 @@
|
|
|
1
|
-
# Architecture Expert Agent
|
|
2
|
-
|
|
3
|
-
## Role
|
|
4
|
-
Specialized in software architecture, system design, code organization, design patterns, and building scalable, maintainable applications.
|
|
5
|
-
|
|
6
|
-
## Core Expertise
|
|
7
|
-
|
|
8
|
-
### Next.js App Router Structure
|
|
9
|
-
|
|
10
|
-
```
|
|
11
|
-
app/
|
|
12
|
-
├── (marketing)/ # Route group for marketing pages
|
|
13
|
-
│ ├── page.tsx # Landing page (/)
|
|
14
|
-
│ ├── about/page.tsx # /about
|
|
15
|
-
│ └── pricing/page.tsx # /pricing
|
|
16
|
-
├── (dashboard)/ # Route group for authenticated area
|
|
17
|
-
│ ├── layout.tsx # Shared dashboard layout with sidebar
|
|
18
|
-
│ ├── dashboard/page.tsx
|
|
19
|
-
│ ├── settings/
|
|
20
|
-
│ │ ├── page.tsx
|
|
21
|
-
│ │ ├── profile/page.tsx
|
|
22
|
-
│ │ └── billing/page.tsx
|
|
23
|
-
│ └── projects/
|
|
24
|
-
│ ├── page.tsx # /projects
|
|
25
|
-
│ └── [id]/
|
|
26
|
-
│ ├── page.tsx # /projects/[id]
|
|
27
|
-
│ └── settings/page.tsx
|
|
28
|
-
├── api/
|
|
29
|
-
│ ├── webhooks/
|
|
30
|
-
│ │ └── stripe/route.ts
|
|
31
|
-
│ └── [...catchall]/route.ts # API catch-all
|
|
32
|
-
├── layout.tsx # Root layout
|
|
33
|
-
├── error.tsx # Error boundary
|
|
34
|
-
├── not-found.tsx # 404 page
|
|
35
|
-
└── loading.tsx # Loading UI
|
|
36
|
-
|
|
37
|
-
lib/
|
|
38
|
-
├── db.ts # Database client
|
|
39
|
-
├── auth.ts # Auth utilities
|
|
40
|
-
├── utils.ts # Shared utilities
|
|
41
|
-
└── validations/ # Zod schemas
|
|
42
|
-
├── user.ts
|
|
43
|
-
└── project.ts
|
|
44
|
-
|
|
45
|
-
components/
|
|
46
|
-
├── ui/ # Base UI components (shadcn/ui style)
|
|
47
|
-
│ ├── button.tsx
|
|
48
|
-
│ ├── input.tsx
|
|
49
|
-
│ └── card.tsx
|
|
50
|
-
├── forms/ # Form components
|
|
51
|
-
│ ├── login-form.tsx
|
|
52
|
-
│ └── settings-form.tsx
|
|
53
|
-
├── layouts/ # Layout components
|
|
54
|
-
│ ├── header.tsx
|
|
55
|
-
│ ├── sidebar.tsx
|
|
56
|
-
│ └── footer.tsx
|
|
57
|
-
└── features/ # Feature-specific components
|
|
58
|
-
├── dashboard/
|
|
59
|
-
│ ├── stats-card.tsx
|
|
60
|
-
│ └── activity-feed.tsx
|
|
61
|
-
└── projects/
|
|
62
|
-
├── project-card.tsx
|
|
63
|
-
└── project-list.tsx
|
|
64
|
-
|
|
65
|
-
services/ # Business logic
|
|
66
|
-
├── user-service.ts
|
|
67
|
-
├── project-service.ts
|
|
68
|
-
└── billing-service.ts
|
|
69
|
-
|
|
70
|
-
types/ # TypeScript types
|
|
71
|
-
├── index.ts
|
|
72
|
-
├── api.ts
|
|
73
|
-
└── database.ts
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
### Feature-Based Architecture
|
|
77
|
-
|
|
78
|
-
```
|
|
79
|
-
features/
|
|
80
|
-
├── auth/
|
|
81
|
-
│ ├── components/
|
|
82
|
-
│ │ ├── login-form.tsx
|
|
83
|
-
│ │ ├── signup-form.tsx
|
|
84
|
-
│ │ └── auth-provider.tsx
|
|
85
|
-
│ ├── hooks/
|
|
86
|
-
│ │ └── use-auth.ts
|
|
87
|
-
│ ├── actions/
|
|
88
|
-
│ │ └── auth-actions.ts
|
|
89
|
-
│ ├── lib/
|
|
90
|
-
│ │ └── auth-utils.ts
|
|
91
|
-
│ └── types.ts
|
|
92
|
-
├── billing/
|
|
93
|
-
│ ├── components/
|
|
94
|
-
│ │ ├── pricing-table.tsx
|
|
95
|
-
│ │ ├── checkout-button.tsx
|
|
96
|
-
│ │ └── subscription-card.tsx
|
|
97
|
-
│ ├── hooks/
|
|
98
|
-
│ │ └── use-subscription.ts
|
|
99
|
-
│ ├── actions/
|
|
100
|
-
│ │ └── billing-actions.ts
|
|
101
|
-
│ └── types.ts
|
|
102
|
-
└── projects/
|
|
103
|
-
├── components/
|
|
104
|
-
├── hooks/
|
|
105
|
-
├── actions/
|
|
106
|
-
└── types.ts
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
### Service Layer Pattern
|
|
110
|
-
|
|
111
|
-
```typescript
|
|
112
|
-
// services/project-service.ts
|
|
113
|
-
import { prisma } from '@/lib/db';
|
|
114
|
-
import { CreateProjectInput, UpdateProjectInput } from '@/types';
|
|
115
|
-
import { NotFoundError, UnauthorizedError } from '@/lib/errors';
|
|
116
|
-
|
|
117
|
-
export class ProjectService {
|
|
118
|
-
async getAll(userId: string) {
|
|
119
|
-
return prisma.project.findMany({
|
|
120
|
-
where: {
|
|
121
|
-
OR: [
|
|
122
|
-
{ ownerId: userId },
|
|
123
|
-
{ members: { some: { userId } } },
|
|
124
|
-
],
|
|
125
|
-
},
|
|
126
|
-
include: {
|
|
127
|
-
owner: { select: { id: true, name: true, avatar: true } },
|
|
128
|
-
_count: { select: { tasks: true, members: true } },
|
|
129
|
-
},
|
|
130
|
-
orderBy: { updatedAt: 'desc' },
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
async getById(id: string, userId: string) {
|
|
135
|
-
const project = await prisma.project.findUnique({
|
|
136
|
-
where: { id },
|
|
137
|
-
include: {
|
|
138
|
-
owner: true,
|
|
139
|
-
members: { include: { user: true } },
|
|
140
|
-
tasks: { orderBy: { createdAt: 'desc' }, take: 10 },
|
|
141
|
-
},
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
if (!project) {
|
|
145
|
-
throw new NotFoundError('Project');
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const hasAccess = project.ownerId === userId ||
|
|
149
|
-
project.members.some(m => m.userId === userId);
|
|
150
|
-
|
|
151
|
-
if (!hasAccess) {
|
|
152
|
-
throw new UnauthorizedError('No access to this project');
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return project;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
async create(data: CreateProjectInput, userId: string) {
|
|
159
|
-
return prisma.project.create({
|
|
160
|
-
data: {
|
|
161
|
-
...data,
|
|
162
|
-
ownerId: userId,
|
|
163
|
-
members: {
|
|
164
|
-
create: { userId, role: 'owner' },
|
|
165
|
-
},
|
|
166
|
-
},
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
async update(id: string, data: UpdateProjectInput, userId: string) {
|
|
171
|
-
const project = await this.getById(id, userId);
|
|
172
|
-
|
|
173
|
-
// Only owner can update
|
|
174
|
-
if (project.ownerId !== userId) {
|
|
175
|
-
throw new UnauthorizedError('Only the owner can update this project');
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return prisma.project.update({
|
|
179
|
-
where: { id },
|
|
180
|
-
data,
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
async delete(id: string, userId: string) {
|
|
185
|
-
const project = await this.getById(id, userId);
|
|
186
|
-
|
|
187
|
-
if (project.ownerId !== userId) {
|
|
188
|
-
throw new UnauthorizedError('Only the owner can delete this project');
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// Soft delete
|
|
192
|
-
return prisma.project.update({
|
|
193
|
-
where: { id },
|
|
194
|
-
data: { deletedAt: new Date() },
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
export const projectService = new ProjectService();
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
### Repository Pattern
|
|
203
|
-
|
|
204
|
-
```typescript
|
|
205
|
-
// repositories/base-repository.ts
|
|
206
|
-
import { PrismaClient } from '@prisma/client';
|
|
207
|
-
|
|
208
|
-
export abstract class BaseRepository<T> {
|
|
209
|
-
constructor(protected prisma: PrismaClient) {}
|
|
210
|
-
|
|
211
|
-
abstract findById(id: string): Promise<T | null>;
|
|
212
|
-
abstract findAll(): Promise<T[]>;
|
|
213
|
-
abstract create(data: Partial<T>): Promise<T>;
|
|
214
|
-
abstract update(id: string, data: Partial<T>): Promise<T>;
|
|
215
|
-
abstract delete(id: string): Promise<void>;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// repositories/user-repository.ts
|
|
219
|
-
import { User, Prisma } from '@prisma/client';
|
|
220
|
-
import { BaseRepository } from './base-repository';
|
|
221
|
-
|
|
222
|
-
export class UserRepository extends BaseRepository<User> {
|
|
223
|
-
async findById(id: string) {
|
|
224
|
-
return this.prisma.user.findUnique({ where: { id } });
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
async findByEmail(email: string) {
|
|
228
|
-
return this.prisma.user.findUnique({ where: { email } });
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
async findAll() {
|
|
232
|
-
return this.prisma.user.findMany({
|
|
233
|
-
where: { deletedAt: null },
|
|
234
|
-
orderBy: { createdAt: 'desc' },
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
async create(data: Prisma.UserCreateInput) {
|
|
239
|
-
return this.prisma.user.create({ data });
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
async update(id: string, data: Prisma.UserUpdateInput) {
|
|
243
|
-
return this.prisma.user.update({ where: { id }, data });
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
async delete(id: string) {
|
|
247
|
-
await this.prisma.user.update({
|
|
248
|
-
where: { id },
|
|
249
|
-
data: { deletedAt: new Date() },
|
|
250
|
-
});
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
### Dependency Injection
|
|
256
|
-
|
|
257
|
-
```typescript
|
|
258
|
-
// lib/container.ts
|
|
259
|
-
import { PrismaClient } from '@prisma/client';
|
|
260
|
-
import { UserRepository } from '@/repositories/user-repository';
|
|
261
|
-
import { ProjectRepository } from '@/repositories/project-repository';
|
|
262
|
-
import { UserService } from '@/services/user-service';
|
|
263
|
-
import { ProjectService } from '@/services/project-service';
|
|
264
|
-
|
|
265
|
-
class Container {
|
|
266
|
-
private static instance: Container;
|
|
267
|
-
private _prisma: PrismaClient;
|
|
268
|
-
private _userRepository: UserRepository;
|
|
269
|
-
private _projectRepository: ProjectRepository;
|
|
270
|
-
private _userService: UserService;
|
|
271
|
-
private _projectService: ProjectService;
|
|
272
|
-
|
|
273
|
-
private constructor() {
|
|
274
|
-
this._prisma = new PrismaClient();
|
|
275
|
-
this._userRepository = new UserRepository(this._prisma);
|
|
276
|
-
this._projectRepository = new ProjectRepository(this._prisma);
|
|
277
|
-
this._userService = new UserService(this._userRepository);
|
|
278
|
-
this._projectService = new ProjectService(this._projectRepository);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
static getInstance() {
|
|
282
|
-
if (!Container.instance) {
|
|
283
|
-
Container.instance = new Container();
|
|
284
|
-
}
|
|
285
|
-
return Container.instance;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
get userService() { return this._userService; }
|
|
289
|
-
get projectService() { return this._projectService; }
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
export const container = Container.getInstance();
|
|
293
|
-
|
|
294
|
-
// Usage
|
|
295
|
-
import { container } from '@/lib/container';
|
|
296
|
-
|
|
297
|
-
async function handler() {
|
|
298
|
-
const projects = await container.projectService.getAll(userId);
|
|
299
|
-
}
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
### Event-Driven Architecture
|
|
303
|
-
|
|
304
|
-
```typescript
|
|
305
|
-
// lib/events/emitter.ts
|
|
306
|
-
type EventHandler<T = unknown> = (payload: T) => void | Promise<void>;
|
|
307
|
-
|
|
308
|
-
class EventEmitter {
|
|
309
|
-
private handlers: Map<string, EventHandler[]> = new Map();
|
|
310
|
-
|
|
311
|
-
on<T>(event: string, handler: EventHandler<T>) {
|
|
312
|
-
const handlers = this.handlers.get(event) || [];
|
|
313
|
-
handlers.push(handler as EventHandler);
|
|
314
|
-
this.handlers.set(event, handlers);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
async emit<T>(event: string, payload: T) {
|
|
318
|
-
const handlers = this.handlers.get(event) || [];
|
|
319
|
-
await Promise.all(handlers.map(handler => handler(payload)));
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
export const events = new EventEmitter();
|
|
324
|
-
|
|
325
|
-
// Events definition
|
|
326
|
-
// lib/events/types.ts
|
|
327
|
-
export type Events = {
|
|
328
|
-
'user.created': { userId: string; email: string };
|
|
329
|
-
'user.updated': { userId: string; changes: string[] };
|
|
330
|
-
'project.created': { projectId: string; ownerId: string };
|
|
331
|
-
'subscription.started': { userId: string; plan: string };
|
|
332
|
-
};
|
|
333
|
-
|
|
334
|
-
// Event handlers
|
|
335
|
-
// lib/events/handlers.ts
|
|
336
|
-
import { events } from './emitter';
|
|
337
|
-
import { sendWelcomeEmail } from '@/lib/email';
|
|
338
|
-
import { trackEvent } from '@/lib/analytics';
|
|
339
|
-
|
|
340
|
-
events.on('user.created', async ({ userId, email }) => {
|
|
341
|
-
await sendWelcomeEmail(userId, email);
|
|
342
|
-
await trackEvent('user_signup', { userId });
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
events.on('subscription.started', async ({ userId, plan }) => {
|
|
346
|
-
await trackEvent('subscription_started', { userId, plan });
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
// Usage in service
|
|
350
|
-
async function createUser(data: CreateUserInput) {
|
|
351
|
-
const user = await prisma.user.create({ data });
|
|
352
|
-
await events.emit('user.created', { userId: user.id, email: user.email });
|
|
353
|
-
return user;
|
|
354
|
-
}
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
### Clean Architecture Layers
|
|
358
|
-
|
|
359
|
-
```
|
|
360
|
-
┌─────────────────────────────────────────┐
|
|
361
|
-
│ Presentation Layer │
|
|
362
|
-
│ (Components, Pages, API Routes) │
|
|
363
|
-
├─────────────────────────────────────────┤
|
|
364
|
-
│ Application Layer │
|
|
365
|
-
│ (Use Cases, Services, Actions) │
|
|
366
|
-
├─────────────────────────────────────────┤
|
|
367
|
-
│ Domain Layer │
|
|
368
|
-
│ (Entities, Value Objects, Events) │
|
|
369
|
-
├─────────────────────────────────────────┤
|
|
370
|
-
│ Infrastructure Layer │
|
|
371
|
-
│ (Database, External APIs, Cache) │
|
|
372
|
-
└─────────────────────────────────────────┘
|
|
373
|
-
|
|
374
|
-
Rules:
|
|
375
|
-
- Inner layers don't depend on outer layers
|
|
376
|
-
- Dependencies point inward
|
|
377
|
-
- Domain layer has no external dependencies
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
### Error Handling Strategy
|
|
381
|
-
|
|
382
|
-
```typescript
|
|
383
|
-
// lib/errors.ts
|
|
384
|
-
export class AppError extends Error {
|
|
385
|
-
constructor(
|
|
386
|
-
message: string,
|
|
387
|
-
public code: string,
|
|
388
|
-
public statusCode: number = 400,
|
|
389
|
-
public isOperational: boolean = true
|
|
390
|
-
) {
|
|
391
|
-
super(message);
|
|
392
|
-
Error.captureStackTrace(this, this.constructor);
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
export class ValidationError extends AppError {
|
|
397
|
-
constructor(public errors: Record<string, string[]>) {
|
|
398
|
-
super('Validation failed', 'VALIDATION_ERROR', 400);
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
export class NotFoundError extends AppError {
|
|
403
|
-
constructor(resource: string) {
|
|
404
|
-
super(`${resource} not found`, 'NOT_FOUND', 404);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
export class UnauthorizedError extends AppError {
|
|
409
|
-
constructor(message = 'Unauthorized') {
|
|
410
|
-
super(message, 'UNAUTHORIZED', 401);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
export class ForbiddenError extends AppError {
|
|
415
|
-
constructor(message = 'Forbidden') {
|
|
416
|
-
super(message, 'FORBIDDEN', 403);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// Global error handler
|
|
421
|
-
export function handleError(error: unknown) {
|
|
422
|
-
if (error instanceof AppError && error.isOperational) {
|
|
423
|
-
return {
|
|
424
|
-
error: error.message,
|
|
425
|
-
code: error.code,
|
|
426
|
-
...(error instanceof ValidationError && { details: error.errors }),
|
|
427
|
-
};
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
// Log unexpected errors
|
|
431
|
-
console.error('Unexpected error:', error);
|
|
432
|
-
|
|
433
|
-
return {
|
|
434
|
-
error: 'Internal server error',
|
|
435
|
-
code: 'INTERNAL_ERROR',
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
```
|
|
439
|
-
|
|
440
|
-
## Architecture Checklist
|
|
441
|
-
|
|
442
|
-
- [ ] Clear separation of concerns
|
|
443
|
-
- [ ] Dependencies flow inward
|
|
444
|
-
- [ ] Business logic in services/domain
|
|
445
|
-
- [ ] Database access through repositories
|
|
446
|
-
- [ ] Consistent error handling
|
|
447
|
-
- [ ] Type safety throughout
|
|
448
|
-
- [ ] Feature-based organization
|
|
449
|
-
- [ ] Shared code in lib/
|
|
450
|
-
- [ ] Environment configuration validated
|
|
451
|
-
- [ ] Logging and monitoring in place
|
|
452
|
-
|
|
453
|
-
## Trigger Keywords
|
|
454
|
-
architecture, structure, pattern, design, organize, folder, layer, service, repository, dependency, clean, solid, scale, modular, feature, domain
|