@mars-stack/cli 0.2.0 → 1.0.2
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/dist/index.js +137 -12
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
- package/template/.cursor/rules/composition-patterns.mdc +186 -0
- package/template/.cursor/rules/data-access.mdc +29 -0
- package/template/.cursor/rules/project-structure.mdc +34 -0
- package/template/.cursor/rules/security.mdc +25 -0
- package/template/.cursor/rules/testing.mdc +24 -0
- package/template/.cursor/rules/ui-conventions.mdc +29 -0
- package/template/.cursor/skills/add-api-route/SKILL.md +122 -0
- package/template/.cursor/skills/add-audit-log/SKILL.md +375 -0
- package/template/.cursor/skills/add-blog/SKILL.md +447 -0
- package/template/.cursor/skills/add-command-palette/SKILL.md +438 -0
- package/template/.cursor/skills/add-component/SKILL.md +158 -0
- package/template/.cursor/skills/add-crud-routes/SKILL.md +221 -0
- package/template/.cursor/skills/add-e2e-test/SKILL.md +227 -0
- package/template/.cursor/skills/add-error-boundary/SKILL.md +472 -0
- package/template/.cursor/skills/add-feature/SKILL.md +174 -0
- package/template/.cursor/skills/add-middleware/SKILL.md +135 -0
- package/template/.cursor/skills/add-page/SKILL.md +151 -0
- package/template/.cursor/skills/add-prisma-model/SKILL.md +148 -0
- package/template/.cursor/skills/add-protected-resource/SKILL.md +192 -0
- package/template/.cursor/skills/add-role/SKILL.md +156 -0
- package/template/.cursor/skills/add-server-action/SKILL.md +167 -0
- package/template/.cursor/skills/add-webhook/SKILL.md +192 -0
- package/template/.cursor/skills/build-complete-feature/SKILL.md +227 -0
- package/template/.cursor/skills/build-dashboard/SKILL.md +211 -0
- package/template/.cursor/skills/build-data-table/SKILL.md +283 -0
- package/template/.cursor/skills/build-form/SKILL.md +231 -0
- package/template/.cursor/skills/build-landing-page/SKILL.md +248 -0
- package/template/.cursor/skills/configure-ai/SKILL.md +617 -0
- package/template/.cursor/skills/configure-analytics/SKILL.md +413 -0
- package/template/.cursor/skills/configure-dark-mode/SKILL.md +309 -0
- package/template/.cursor/skills/configure-email/SKILL.md +170 -0
- package/template/.cursor/skills/configure-email-verification/SKILL.md +333 -0
- package/template/.cursor/skills/configure-feature-flags/SKILL.md +361 -0
- package/template/.cursor/skills/configure-i18n/SKILL.md +518 -0
- package/template/.cursor/skills/configure-jobs/SKILL.md +500 -0
- package/template/.cursor/skills/configure-magic-links/SKILL.md +385 -0
- package/template/.cursor/skills/configure-multi-tenancy/SKILL.md +611 -0
- package/template/.cursor/skills/configure-notifications/SKILL.md +569 -0
- package/template/.cursor/skills/configure-oauth/SKILL.md +217 -0
- package/template/.cursor/skills/configure-onboarding/SKILL.md +483 -0
- package/template/.cursor/skills/configure-payments/SKILL.md +243 -0
- package/template/.cursor/skills/configure-realtime/SKILL.md +733 -0
- package/template/.cursor/skills/configure-search/SKILL.md +581 -0
- package/template/.cursor/skills/configure-storage/SKILL.md +273 -0
- package/template/.cursor/skills/configure-two-factor/SKILL.md +518 -0
- package/template/.cursor/skills/create-execution-plan/SKILL.md +204 -0
- package/template/.cursor/skills/create-seed/SKILL.md +191 -0
- package/template/.cursor/skills/deploy-to-vercel/SKILL.md +300 -0
- package/template/.cursor/skills/design-tokens/SKILL.md +138 -0
- package/template/.cursor/skills/mars-capture-conversation-context/SKILL.md +119 -0
- package/template/.cursor/skills/setup-billing/SKILL.md +322 -0
- package/template/.cursor/skills/setup-project/SKILL.md +104 -0
- package/template/.cursor/skills/setup-teams/SKILL.md +682 -0
- package/template/.cursor/skills/test-api-route/SKILL.md +219 -0
- package/template/.cursor/skills/update-architecture-docs/SKILL.md +99 -0
- package/template/AGENTS.md +104 -0
- package/template/ARCHITECTURE.md +102 -0
- package/template/docs/QUALITY_SCORE.md +20 -0
- package/template/docs/design-docs/conversation-as-system-record.md +70 -0
- package/template/docs/design-docs/core-beliefs.md +43 -0
- package/template/docs/design-docs/index.md +8 -0
- package/template/docs/exec-plans/active/.gitkeep +0 -0
- package/template/docs/exec-plans/completed/.gitkeep +0 -0
- package/template/docs/exec-plans/tech-debt.md +7 -0
- package/template/docs/generated/.gitkeep +0 -0
- package/template/docs/product-specs/index.md +7 -0
- package/template/docs/references/index.md +18 -0
- package/template/e2e/api.spec.ts +20 -0
- package/template/e2e/auth.spec.ts +24 -0
- package/template/e2e/public.spec.ts +25 -0
- package/template/eslint.config.mjs +24 -0
- package/template/next-env.d.ts +6 -0
- package/template/next.config.ts +45 -0
- package/template/package.json +80 -0
- package/template/playwright.config.ts +31 -0
- package/template/postcss.config.mjs +8 -0
- package/template/prisma/generated/prisma/browser.ts +49 -0
- package/template/prisma/generated/prisma/client.ts +73 -0
- package/template/prisma/generated/prisma/commonInputTypes.ts +406 -0
- package/template/prisma/generated/prisma/enums.ts +15 -0
- package/template/prisma/generated/prisma/internal/class.ts +254 -0
- package/template/prisma/generated/prisma/internal/prismaNamespace.ts +1240 -0
- package/template/prisma/generated/prisma/internal/prismaNamespaceBrowser.ts +190 -0
- package/template/prisma/generated/prisma/models/Account.ts +1543 -0
- package/template/prisma/generated/prisma/models/File.ts +1529 -0
- package/template/prisma/generated/prisma/models/Session.ts +1415 -0
- package/template/prisma/generated/prisma/models/Subscription.ts +1455 -0
- package/template/prisma/generated/prisma/models/User.ts +2235 -0
- package/template/prisma/generated/prisma/models/VerificationToken.ts +1099 -0
- package/template/prisma/generated/prisma/models.ts +17 -0
- package/template/prisma/schema/auth.prisma +69 -0
- package/template/prisma/schema/base.prisma +8 -0
- package/template/prisma/schema/file.prisma +15 -0
- package/template/prisma/schema/subscription.prisma +17 -0
- package/template/prisma.config.ts +13 -0
- package/template/scripts/check-architecture.ts +221 -0
- package/template/scripts/check-doc-freshness.ts +242 -0
- package/template/scripts/ensure-db.mjs +291 -0
- package/template/scripts/generate-docs.ts +143 -0
- package/template/scripts/generate-env-example.ts +89 -0
- package/template/scripts/seed.ts +56 -0
- package/template/scripts/update-quality-score.ts +263 -0
- package/template/src/__tests__/architecture.test.ts +114 -0
- package/template/src/app/(auth)/forgotten-password/page.tsx +92 -0
- package/template/src/app/(auth)/layout.tsx +11 -0
- package/template/src/app/(auth)/register/page.tsx +162 -0
- package/template/src/app/(auth)/reset-password/page.tsx +109 -0
- package/template/src/app/(auth)/sign-in/page.tsx +122 -0
- package/template/src/app/(auth)/verify/[token]/page.tsx +87 -0
- package/template/src/app/(auth)/verify/page.tsx +56 -0
- package/template/src/app/(protected)/admin/page.tsx +108 -0
- package/template/src/app/(protected)/dashboard/loading.tsx +20 -0
- package/template/src/app/(protected)/dashboard/page.tsx +22 -0
- package/template/src/app/(protected)/layout.tsx +262 -0
- package/template/src/app/(protected)/settings/page.tsx +370 -0
- package/template/src/app/api/auth/forgot/route.ts +63 -0
- package/template/src/app/api/auth/login/route.ts +121 -0
- package/template/src/app/api/auth/logout/route.ts +19 -0
- package/template/src/app/api/auth/me/route.ts +30 -0
- package/template/src/app/api/auth/reset/route.ts +45 -0
- package/template/src/app/api/auth/signup/route.ts +85 -0
- package/template/src/app/api/auth/verify/route.ts +46 -0
- package/template/src/app/api/csrf/route.ts +12 -0
- package/template/src/app/api/health/route.ts +10 -0
- package/template/src/app/api/protected/admin/users/route.ts +24 -0
- package/template/src/app/api/protected/billing/checkout/route.ts +83 -0
- package/template/src/app/api/protected/billing/portal/route.ts +39 -0
- package/template/src/app/api/protected/files/[fileId]/route.ts +86 -0
- package/template/src/app/api/protected/files/upload/route.ts +64 -0
- package/template/src/app/api/protected/user/password/route.ts +63 -0
- package/template/src/app/api/protected/user/profile/route.ts +35 -0
- package/template/src/app/api/protected/user/sessions/[sessionId]/route.ts +33 -0
- package/template/src/app/api/protected/user/sessions/route.ts +22 -0
- package/template/src/app/api/readiness/route.ts +15 -0
- package/template/src/app/api/webhooks/stripe/route.ts +166 -0
- package/template/src/app/error.tsx +33 -0
- package/template/src/app/layout.tsx +29 -0
- package/template/src/app/not-found.tsx +20 -0
- package/template/src/app/page.tsx +136 -0
- package/template/src/app/privacy/page.tsx +178 -0
- package/template/src/app/providers.tsx +8 -0
- package/template/src/app/terms/page.tsx +139 -0
- package/template/src/config/app.config.ts +70 -0
- package/template/src/config/routes.ts +17 -0
- package/template/src/features/admin/index.ts +11 -0
- package/template/src/features/admin/permissions.ts +64 -0
- package/template/src/features/auth/context/AuthContext.tsx +96 -0
- package/template/src/features/auth/context/index.ts +2 -0
- package/template/src/features/auth/index.ts +3 -0
- package/template/src/features/auth/server/consent.ts +66 -0
- package/template/src/features/auth/server/session-revocation.ts +20 -0
- package/template/src/features/auth/server/sessions.ts +66 -0
- package/template/src/features/auth/server/user.ts +166 -0
- package/template/src/features/auth/types.ts +19 -0
- package/template/src/features/auth/validators.ts +29 -0
- package/template/src/features/billing/server/index.ts +66 -0
- package/template/src/features/billing/types.ts +43 -0
- package/template/src/features/uploads/server/index.ts +49 -0
- package/template/src/features/uploads/types.ts +26 -0
- package/template/src/lib/core/email/templates/base-layout.ts +122 -0
- package/template/src/lib/core/email/templates/index.ts +4 -0
- package/template/src/lib/core/email/templates/password-reset-email.ts +42 -0
- package/template/src/lib/core/email/templates/verification-email.ts +41 -0
- package/template/src/lib/core/email/templates/welcome-email.ts +40 -0
- package/template/src/lib/mars.ts +56 -0
- package/template/src/lib/prisma.ts +19 -0
- package/template/src/proxy.ts +92 -0
- package/template/src/styles/brand.css +15 -0
- package/template/src/styles/globals.css +7 -0
- package/template/tsconfig.json +59 -0
- package/template/vitest.config.ts +41 -0
- package/template/vitest.setup.ts +24 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Skill: Create Execution Plan
|
|
2
|
+
|
|
3
|
+
Create and manage execution plans in `docs/exec-plans/` to track multi-step implementation work with clear goals, tasks, and verification criteria.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
Use this skill when:
|
|
8
|
+
- Starting a large or multi-step implementation task
|
|
9
|
+
- The user asks to plan work, create a plan, or organise tasks
|
|
10
|
+
- A meta-skill needs to create a plan before executing
|
|
11
|
+
- You need to track progress across multiple related changes
|
|
12
|
+
|
|
13
|
+
## Prerequisites
|
|
14
|
+
|
|
15
|
+
- Read `docs/exec-plans/` to see existing plans and the directory structure.
|
|
16
|
+
- Read `docs/QUALITY_SCORE.md` to understand current quality grades.
|
|
17
|
+
|
|
18
|
+
## Plan Directory Structure
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
docs/exec-plans/
|
|
22
|
+
├── active/ # Plans currently being worked on
|
|
23
|
+
│ └── <plan-name>.md
|
|
24
|
+
├── completed/ # Finished plans (moved from active/)
|
|
25
|
+
│ └── <plan-name>.md
|
|
26
|
+
└── templates/ # (optional) Plan templates
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Step 1: Choose a Plan Name
|
|
30
|
+
|
|
31
|
+
Use kebab-case that describes the goal, not the method:
|
|
32
|
+
|
|
33
|
+
| Good | Bad |
|
|
34
|
+
|------|-----|
|
|
35
|
+
| `add-billing-system` | `stripe-integration` |
|
|
36
|
+
| `fix-auth-redirects` | `update-middleware` |
|
|
37
|
+
| `setup-team-management` | `prisma-models` |
|
|
38
|
+
|
|
39
|
+
## Step 2: Create the Plan File
|
|
40
|
+
|
|
41
|
+
```markdown
|
|
42
|
+
# Execution Plan: <Title>
|
|
43
|
+
|
|
44
|
+
**Status:** Active
|
|
45
|
+
**Priority:** P0 / P1 / P2
|
|
46
|
+
**Created:** <YYYY-MM-DD>
|
|
47
|
+
**Estimated effort:** S / M / L / XL
|
|
48
|
+
|
|
49
|
+
## Goal
|
|
50
|
+
|
|
51
|
+
<1-2 sentences describing the end state. What does "done" look like? Focus on user-visible outcomes.>
|
|
52
|
+
|
|
53
|
+
## Context
|
|
54
|
+
|
|
55
|
+
<Why is this work needed? What problem does it solve? Link to related issues, quality score entries, or design docs.>
|
|
56
|
+
|
|
57
|
+
## Tasks
|
|
58
|
+
|
|
59
|
+
- [ ] **1.1 <Task title>** — <Brief description of what to do and why>
|
|
60
|
+
- [ ] **1.2 <Task title>** — <Brief description>
|
|
61
|
+
- [ ] **2.1 <Task title>** — <Brief description (new section number = new phase)>
|
|
62
|
+
- [ ] **2.2 <Task title>** — <Brief description>
|
|
63
|
+
|
|
64
|
+
## Verification
|
|
65
|
+
|
|
66
|
+
- [ ] <Concrete, testable assertion about the end state>
|
|
67
|
+
- [ ] <Another testable assertion>
|
|
68
|
+
- [ ] <Build passes: `yarn build` succeeds>
|
|
69
|
+
- [ ] <Tests pass: `yarn test` succeeds>
|
|
70
|
+
|
|
71
|
+
## Quality Score Updates
|
|
72
|
+
|
|
73
|
+
After completion, update these entries in `docs/QUALITY_SCORE.md`:
|
|
74
|
+
|
|
75
|
+
| Domain | Current | Target | Notes |
|
|
76
|
+
|--------|---------|--------|-------|
|
|
77
|
+
| <domain> | <current grade> | <target grade> | <what changes> |
|
|
78
|
+
|
|
79
|
+
## Notes
|
|
80
|
+
|
|
81
|
+
<Any constraints, risks, open questions, or design decisions made during planning.>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Step 3: Writing Good Tasks
|
|
85
|
+
|
|
86
|
+
### Task granularity
|
|
87
|
+
|
|
88
|
+
Each task should be completable in a single focused session. If a task would take multiple hours, break it down.
|
|
89
|
+
|
|
90
|
+
### Task ordering
|
|
91
|
+
|
|
92
|
+
Number tasks with a phase prefix (`1.x`, `2.x`, `3.x`) where:
|
|
93
|
+
- **Phase 1** — Schema and data model changes
|
|
94
|
+
- **Phase 2** — Server-side logic (services, API routes)
|
|
95
|
+
- **Phase 3** — Client-side UI (pages, components)
|
|
96
|
+
- **Phase 4** — Testing and documentation
|
|
97
|
+
|
|
98
|
+
Tasks within a phase can be done in any order. Phases should be sequential.
|
|
99
|
+
|
|
100
|
+
### Task dependencies
|
|
101
|
+
|
|
102
|
+
If a task depends on another, note it:
|
|
103
|
+
|
|
104
|
+
```markdown
|
|
105
|
+
- [ ] **2.1 Create billing service** — Depends on 1.1. Server module in `src/features/billing/server/`.
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Step 4: Writing Verification Criteria
|
|
109
|
+
|
|
110
|
+
Verification items should be:
|
|
111
|
+
- **Specific** — Not "it works", but "navigating to `/billing` shows subscription status"
|
|
112
|
+
- **Testable** — Can be verified in under 2 minutes
|
|
113
|
+
- **User-centric** — Focus on observable behaviour, not implementation details
|
|
114
|
+
|
|
115
|
+
```markdown
|
|
116
|
+
## Verification
|
|
117
|
+
|
|
118
|
+
- [ ] `mars create test-app` produces a project that passes `yarn build`
|
|
119
|
+
- [ ] Navigating to `/billing` shows the current subscription status
|
|
120
|
+
- [ ] Clicking "Upgrade" creates a Stripe Checkout session and redirects
|
|
121
|
+
- [ ] Webhook processes `checkout.session.completed` and updates the DB
|
|
122
|
+
- [ ] Non-subscribed users see the pricing page instead of premium features
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Step 5: Update Progress
|
|
126
|
+
|
|
127
|
+
As work progresses, check off tasks and add notes:
|
|
128
|
+
|
|
129
|
+
```markdown
|
|
130
|
+
- [x] **1.1 Add Subscription model** — Done. Added `prisma/schema/billing.prisma`.
|
|
131
|
+
- [ ] **1.2 Add webhook event model** — In progress.
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Step 6: Complete the Plan
|
|
135
|
+
|
|
136
|
+
When all tasks and verification criteria are met:
|
|
137
|
+
|
|
138
|
+
1. Update the status to `Completed`:
|
|
139
|
+
|
|
140
|
+
```markdown
|
|
141
|
+
**Status:** Completed
|
|
142
|
+
**Completed:** <YYYY-MM-DD>
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
2. Move the file from `active/` to `completed/`:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
mv docs/exec-plans/active/<plan>.md docs/exec-plans/completed/<plan>.md
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
3. Update `docs/QUALITY_SCORE.md` with new grades.
|
|
152
|
+
|
|
153
|
+
## Step 7: Link from QUALITY_SCORE.md
|
|
154
|
+
|
|
155
|
+
When creating a plan that addresses quality score gaps, add a reference:
|
|
156
|
+
|
|
157
|
+
```markdown
|
|
158
|
+
| Dashboard | D | Empty placeholder page | → [exec-plan: add-dashboard](exec-plans/active/add-dashboard.md) |
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Templates for Common Plans
|
|
162
|
+
|
|
163
|
+
### Feature addition plan
|
|
164
|
+
|
|
165
|
+
```markdown
|
|
166
|
+
## Tasks
|
|
167
|
+
|
|
168
|
+
- [ ] **1.1 Prisma schema** — Add models to `prisma/schema/<name>.prisma`
|
|
169
|
+
- [ ] **1.2 Run db:push** — Sync schema to dev database
|
|
170
|
+
- [ ] **2.1 Feature directory** — Create `src/features/<name>/` with server/, components/, validation/
|
|
171
|
+
- [ ] **2.2 Server module** — Implement queries and mutations
|
|
172
|
+
- [ ] **2.3 Validation schemas** — Zod schemas for API inputs
|
|
173
|
+
- [ ] **3.1 API routes** — CRUD routes under `src/app/api/protected/<name>/`
|
|
174
|
+
- [ ] **3.2 Page** — Create page at `src/app/(protected)/<name>/page.tsx`
|
|
175
|
+
- [ ] **3.3 Components** — Feature-specific UI components
|
|
176
|
+
- [ ] **4.1 Tests** — API route tests with mocked Prisma and auth
|
|
177
|
+
- [ ] **4.2 E2E tests** — Playwright tests for critical user flows
|
|
178
|
+
- [ ] **4.3 Update docs** — Update ARCHITECTURE.md and QUALITY_SCORE.md
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Bug fix plan
|
|
182
|
+
|
|
183
|
+
```markdown
|
|
184
|
+
## Tasks
|
|
185
|
+
|
|
186
|
+
- [ ] **1.1 Reproduce** — Create a minimal reproduction of the issue
|
|
187
|
+
- [ ] **1.2 Root cause** — Identify why the bug occurs
|
|
188
|
+
- [ ] **2.1 Fix** — Implement the fix
|
|
189
|
+
- [ ] **2.2 Regression test** — Add test that would have caught this bug
|
|
190
|
+
- [ ] **3.1 Verify** — Confirm the fix in dev environment
|
|
191
|
+
- [ ] **3.2 Update quality score** — Update grades in QUALITY_SCORE.md
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Checklist
|
|
195
|
+
|
|
196
|
+
- [ ] Plan file created in `docs/exec-plans/active/`
|
|
197
|
+
- [ ] Title is descriptive and goal-oriented
|
|
198
|
+
- [ ] Status, priority, date, and effort estimate included
|
|
199
|
+
- [ ] Goal section describes the end state clearly
|
|
200
|
+
- [ ] Tasks are numbered with phase prefixes
|
|
201
|
+
- [ ] Each task has a title and brief description
|
|
202
|
+
- [ ] Verification criteria are specific and testable
|
|
203
|
+
- [ ] Quality Score update table included
|
|
204
|
+
- [ ] Plan linked from QUALITY_SCORE.md if addressing a gap
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Skill: Create a Database Seed
|
|
2
|
+
|
|
3
|
+
Create a Prisma seed script to populate the database with development data.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
Use this skill when the user asks to add seed data, test data, sample data, or wants to populate the database for development.
|
|
8
|
+
|
|
9
|
+
## Setup
|
|
10
|
+
|
|
11
|
+
### Step 1: Create the Seed File
|
|
12
|
+
|
|
13
|
+
Create `prisma/seed.ts`:
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { PrismaClient } from '@db';
|
|
17
|
+
import { PrismaPg } from '@prisma/adapter-pg';
|
|
18
|
+
import { hash } from 'bcryptjs';
|
|
19
|
+
|
|
20
|
+
const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL! });
|
|
21
|
+
const prisma = new PrismaClient({ adapter });
|
|
22
|
+
|
|
23
|
+
async function main() {
|
|
24
|
+
console.log('Seeding database...');
|
|
25
|
+
|
|
26
|
+
// Clean existing data (order matters for foreign keys)
|
|
27
|
+
await prisma.verificationToken.deleteMany();
|
|
28
|
+
await prisma.session.deleteMany();
|
|
29
|
+
await prisma.account.deleteMany();
|
|
30
|
+
await prisma.user.deleteMany();
|
|
31
|
+
|
|
32
|
+
// Create admin user
|
|
33
|
+
const adminPassword = await hash('admin123456', 12);
|
|
34
|
+
const admin = await prisma.user.create({
|
|
35
|
+
data: {
|
|
36
|
+
email: 'admin@example.com',
|
|
37
|
+
name: 'Admin User',
|
|
38
|
+
password: adminPassword,
|
|
39
|
+
role: 'admin',
|
|
40
|
+
emailVerified: new Date(),
|
|
41
|
+
termsAcceptedAt: new Date(),
|
|
42
|
+
privacyAcceptedAt: new Date(),
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
console.log(` Created admin: ${admin.email}`);
|
|
46
|
+
|
|
47
|
+
// Create regular users
|
|
48
|
+
const userPassword = await hash('user123456', 12);
|
|
49
|
+
const users = await Promise.all(
|
|
50
|
+
Array.from({ length: 5 }, (_, i) =>
|
|
51
|
+
prisma.user.create({
|
|
52
|
+
data: {
|
|
53
|
+
email: `user${i + 1}@example.com`,
|
|
54
|
+
name: `Test User ${i + 1}`,
|
|
55
|
+
password: userPassword,
|
|
56
|
+
role: 'user',
|
|
57
|
+
emailVerified: new Date(),
|
|
58
|
+
termsAcceptedAt: new Date(),
|
|
59
|
+
privacyAcceptedAt: new Date(),
|
|
60
|
+
},
|
|
61
|
+
}),
|
|
62
|
+
),
|
|
63
|
+
);
|
|
64
|
+
console.log(` Created ${users.length} users`);
|
|
65
|
+
|
|
66
|
+
// Seed feature-specific data here
|
|
67
|
+
// Example: create items for the first user
|
|
68
|
+
// await prisma.item.createMany({
|
|
69
|
+
// data: Array.from({ length: 10 }, (_, i) => ({
|
|
70
|
+
// name: `Item ${i + 1}`,
|
|
71
|
+
// userId: users[0].id,
|
|
72
|
+
// })),
|
|
73
|
+
// });
|
|
74
|
+
|
|
75
|
+
console.log('Seeding complete.');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
main()
|
|
79
|
+
.catch((error) => {
|
|
80
|
+
console.error('Seed error:', error);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
})
|
|
83
|
+
.finally(() => prisma.$disconnect());
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Step 2: Configure package.json
|
|
87
|
+
|
|
88
|
+
Add the seed command to `package.json`:
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"prisma": {
|
|
93
|
+
"schema": "prisma/schema",
|
|
94
|
+
"seed": "tsx prisma/seed.ts"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Step 3: Install tsx (if not already)
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
yarn add -D tsx
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Step 4: Run the Seed
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
yarn db:seed
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Or automatically after reset:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
npx prisma migrate reset # Runs seed automatically after reset
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Patterns
|
|
118
|
+
|
|
119
|
+
### Deterministic IDs (for testing)
|
|
120
|
+
|
|
121
|
+
Use fixed IDs so tests can reference specific records:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
const admin = await prisma.user.create({
|
|
125
|
+
data: {
|
|
126
|
+
id: 'seed-admin-001',
|
|
127
|
+
email: 'admin@example.com',
|
|
128
|
+
// ...
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Realistic Data with Helpers
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
function randomDate(start: Date, end: Date): Date {
|
|
137
|
+
return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function randomElement<T>(array: T[]): T {
|
|
141
|
+
return array[Math.floor(Math.random() * array.length)];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const statuses = ['draft', 'active', 'archived'] as const;
|
|
145
|
+
|
|
146
|
+
await prisma.item.createMany({
|
|
147
|
+
data: Array.from({ length: 50 }, (_, i) => ({
|
|
148
|
+
name: `Item ${i + 1}`,
|
|
149
|
+
status: randomElement(statuses),
|
|
150
|
+
createdAt: randomDate(new Date('2024-01-01'), new Date()),
|
|
151
|
+
userId: randomElement(users).id,
|
|
152
|
+
})),
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Conditional Seeding
|
|
157
|
+
|
|
158
|
+
Only seed data relevant to enabled features:
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import { appConfig } from '../src/config/app.config';
|
|
162
|
+
|
|
163
|
+
if (appConfig.features.billing) {
|
|
164
|
+
// Seed subscription plans, etc.
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (appConfig.features.blog) {
|
|
168
|
+
// Seed blog posts, categories, etc.
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Rules
|
|
173
|
+
|
|
174
|
+
- **Never use seed scripts in production.** Guard with an environment check if needed.
|
|
175
|
+
- **Clean data in reverse dependency order** (child tables first, then parent tables).
|
|
176
|
+
- **Use `createMany` for bulk inserts** -- significantly faster than individual `create` calls.
|
|
177
|
+
- **Hash passwords properly** -- use the same `bcryptjs` library as the auth system.
|
|
178
|
+
- **Don't seed secrets** -- use placeholder values for development only.
|
|
179
|
+
- **Make seeds idempotent** -- always delete existing data before inserting.
|
|
180
|
+
|
|
181
|
+
## Checklist
|
|
182
|
+
|
|
183
|
+
- [ ] Seed file at `prisma/seed.ts`
|
|
184
|
+
- [ ] `prisma.seed` configured in `package.json`
|
|
185
|
+
- [ ] `tsx` added as dev dependency
|
|
186
|
+
- [ ] Admin user with known credentials seeded
|
|
187
|
+
- [ ] Regular test users seeded
|
|
188
|
+
- [ ] Feature-specific data seeded
|
|
189
|
+
- [ ] Data cleaned before seeding (idempotent)
|
|
190
|
+
- [ ] Passwords hashed with bcryptjs
|
|
191
|
+
- [ ] `yarn db:seed` runs without errors
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
# Skill: Deploy to Vercel
|
|
2
|
+
|
|
3
|
+
Step-by-step guide for deploying a Mars application to Vercel, including CLI setup, environment variables, database provisioning, and post-deploy verification.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
Use this skill when the user asks to deploy to Vercel, set up hosting, go to production, configure deployment, or publish their application.
|
|
8
|
+
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
- A Vercel account at [vercel.com](https://vercel.com)
|
|
12
|
+
- The application builds locally with `yarn build`
|
|
13
|
+
- Git repository initialized and pushed to GitHub/GitLab/Bitbucket
|
|
14
|
+
|
|
15
|
+
## Step 1: Install Vercel CLI
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
yarn global add vercel
|
|
19
|
+
# or
|
|
20
|
+
npm i -g vercel
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Login to Vercel:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
vercel login
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Step 2: Link the Project
|
|
30
|
+
|
|
31
|
+
From the project root:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
vercel link
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
This creates `.vercel/project.json` with the project ID. Add `.vercel` to `.gitignore` if not already present.
|
|
38
|
+
|
|
39
|
+
## Step 3: Provision Database
|
|
40
|
+
|
|
41
|
+
### Option A: Vercel Postgres (recommended for simplicity)
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
vercel env pull .env.local
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
1. Go to your Vercel project dashboard → Storage → Create Database → Postgres
|
|
48
|
+
2. Vercel automatically adds `POSTGRES_URL`, `POSTGRES_PRISMA_URL`, etc. to your project env vars.
|
|
49
|
+
|
|
50
|
+
Update `prisma/schema/base.prisma` to use the Vercel Postgres URL:
|
|
51
|
+
|
|
52
|
+
```prisma
|
|
53
|
+
datasource db {
|
|
54
|
+
provider = "postgresql"
|
|
55
|
+
url = env("POSTGRES_PRISMA_URL")
|
|
56
|
+
directUrl = env("POSTGRES_URL_NON_POOLING")
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Option B: Neon (recommended for production)
|
|
61
|
+
|
|
62
|
+
1. Create a database at [neon.tech](https://neon.tech)
|
|
63
|
+
2. Copy the connection string
|
|
64
|
+
3. Set it in Vercel:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
vercel env add DATABASE_URL production
|
|
68
|
+
vercel env add DATABASE_URL preview
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Run Migrations
|
|
72
|
+
|
|
73
|
+
After database provisioning, push the schema:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Pull production env vars locally
|
|
77
|
+
vercel env pull .env.production.local
|
|
78
|
+
|
|
79
|
+
# Push schema to production database
|
|
80
|
+
DATABASE_URL="<production-url>" npx prisma db push
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Step 4: Provision KV Store (Rate Limiting)
|
|
84
|
+
|
|
85
|
+
Mars uses Upstash Redis for rate limiting in production.
|
|
86
|
+
|
|
87
|
+
### Option A: Vercel KV
|
|
88
|
+
|
|
89
|
+
1. Vercel Dashboard → Storage → Create Database → KV
|
|
90
|
+
2. Vercel automatically adds `KV_REST_API_URL` and `KV_REST_API_TOKEN`
|
|
91
|
+
|
|
92
|
+
### Option B: Upstash Directly
|
|
93
|
+
|
|
94
|
+
1. Create a database at [upstash.com](https://upstash.com)
|
|
95
|
+
2. Set environment variables:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
vercel env add UPSTASH_REDIS_REST_URL production
|
|
99
|
+
vercel env add UPSTASH_REDIS_REST_TOKEN production
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Step 5: Set Environment Variables
|
|
103
|
+
|
|
104
|
+
Required variables for a Mars app:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Authentication (REQUIRED)
|
|
108
|
+
vercel env add JWT_SECRET production # Generate: openssl rand -base64 32
|
|
109
|
+
vercel env add JWT_SECRET preview # Use a different secret for preview
|
|
110
|
+
|
|
111
|
+
# App URL (REQUIRED)
|
|
112
|
+
vercel env add APP_URL production # https://your-domain.com
|
|
113
|
+
vercel env add NEXT_PUBLIC_APP_URL production # Same as APP_URL
|
|
114
|
+
|
|
115
|
+
# Database (set during provisioning)
|
|
116
|
+
# POSTGRES_URL / DATABASE_URL — already set if using Vercel Postgres
|
|
117
|
+
|
|
118
|
+
# Rate Limiting (REQUIRED for production)
|
|
119
|
+
# UPSTASH_REDIS_REST_URL — already set if using Vercel KV
|
|
120
|
+
# UPSTASH_REDIS_REST_TOKEN — already set if using Vercel KV
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Optional variables based on enabled features:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Email (if appConfig.features.email is true)
|
|
127
|
+
vercel env add RESEND_API_KEY production
|
|
128
|
+
vercel env add EMAIL_FROM production # noreply@yourdomain.com
|
|
129
|
+
|
|
130
|
+
# Payments (if appConfig.features.billing is true)
|
|
131
|
+
vercel env add STRIPE_SECRET_KEY production
|
|
132
|
+
vercel env add STRIPE_WEBHOOK_SECRET production
|
|
133
|
+
vercel env add NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY production
|
|
134
|
+
|
|
135
|
+
# Storage (if appConfig.features.storage is true)
|
|
136
|
+
vercel env add BLOB_READ_WRITE_TOKEN production
|
|
137
|
+
|
|
138
|
+
# Error Reporting (optional)
|
|
139
|
+
vercel env add NEXT_PUBLIC_SENTRY_DSN production
|
|
140
|
+
vercel env add SENTRY_ORG production
|
|
141
|
+
vercel env add SENTRY_PROJECT production
|
|
142
|
+
|
|
143
|
+
# Cron Jobs (if using Vercel Cron)
|
|
144
|
+
vercel env add CRON_SECRET production # Generate: openssl rand -base64 32
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Step 6: Configure `vercel.json` (Optional)
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
"framework": "nextjs",
|
|
152
|
+
"buildCommand": "yarn build",
|
|
153
|
+
"installCommand": "yarn install --frozen-lockfile",
|
|
154
|
+
"regions": ["iad1"],
|
|
155
|
+
"headers": [
|
|
156
|
+
{
|
|
157
|
+
"source": "/api/(.*)",
|
|
158
|
+
"headers": [
|
|
159
|
+
{ "key": "X-Content-Type-Options", "value": "nosniff" },
|
|
160
|
+
{ "key": "X-Frame-Options", "value": "DENY" }
|
|
161
|
+
]
|
|
162
|
+
}
|
|
163
|
+
],
|
|
164
|
+
"crons": []
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Step 7: Deploy
|
|
169
|
+
|
|
170
|
+
### First Deploy (Preview)
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
vercel
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
This deploys to a preview URL. Test thoroughly before promoting.
|
|
177
|
+
|
|
178
|
+
### Production Deploy
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
vercel --prod
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Git Integration (Recommended)
|
|
185
|
+
|
|
186
|
+
Push to your default branch for automatic production deployments:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
git push origin main
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Vercel automatically deploys:
|
|
193
|
+
- `main` branch → Production
|
|
194
|
+
- Other branches → Preview deployments
|
|
195
|
+
|
|
196
|
+
## Step 8: Configure Custom Domain
|
|
197
|
+
|
|
198
|
+
1. Vercel Dashboard → Settings → Domains
|
|
199
|
+
2. Add your domain (e.g., `app.yourdomain.com`)
|
|
200
|
+
3. Update DNS records as shown by Vercel
|
|
201
|
+
4. Wait for SSL certificate provisioning
|
|
202
|
+
|
|
203
|
+
After domain is live, update:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
vercel env add APP_URL production # https://app.yourdomain.com
|
|
207
|
+
vercel env add NEXT_PUBLIC_APP_URL production # https://app.yourdomain.com
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Redeploy to pick up the new URL:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
vercel --prod
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Step 9: Post-Deploy Verification
|
|
217
|
+
|
|
218
|
+
Run through this checklist after each production deployment:
|
|
219
|
+
|
|
220
|
+
### Automated checks
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# Health check (if endpoint exists)
|
|
224
|
+
curl -f https://your-app.vercel.app/api/health
|
|
225
|
+
|
|
226
|
+
# Check the deployment is accessible
|
|
227
|
+
curl -s -o /dev/null -w "%{http_code}" https://your-app.vercel.app
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Manual verification
|
|
231
|
+
|
|
232
|
+
1. **Auth flow** — Register, login, logout, password reset
|
|
233
|
+
2. **CSRF protection** — API calls include CSRF token, reject without it
|
|
234
|
+
3. **Rate limiting** — Rapid requests get 429 responses
|
|
235
|
+
4. **Protected routes** — Unauthenticated access redirects to login
|
|
236
|
+
5. **Email delivery** — Test verification and password reset emails
|
|
237
|
+
6. **Database connectivity** — Data persists across requests
|
|
238
|
+
7. **Environment** — `process.env.NODE_ENV === 'production'` in server logs
|
|
239
|
+
|
|
240
|
+
### Monitoring
|
|
241
|
+
|
|
242
|
+
- Vercel Dashboard → Logs for runtime errors
|
|
243
|
+
- Vercel Dashboard → Analytics for performance metrics
|
|
244
|
+
- Vercel Dashboard → Speed Insights for Core Web Vitals
|
|
245
|
+
|
|
246
|
+
## Stripe Webhook Setup (If Billing Enabled)
|
|
247
|
+
|
|
248
|
+
After deployment, configure the production webhook:
|
|
249
|
+
|
|
250
|
+
1. Go to [Stripe Dashboard → Webhooks](https://dashboard.stripe.com/webhooks)
|
|
251
|
+
2. Add endpoint: `https://your-domain.com/api/webhooks/stripe`
|
|
252
|
+
3. Select events: `checkout.session.completed`, `customer.subscription.updated`, `customer.subscription.deleted`
|
|
253
|
+
4. Copy the webhook signing secret
|
|
254
|
+
5. Set it in Vercel:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
vercel env add STRIPE_WEBHOOK_SECRET production
|
|
258
|
+
vercel --prod # Redeploy
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Troubleshooting
|
|
262
|
+
|
|
263
|
+
| Issue | Cause | Fix |
|
|
264
|
+
|-------|-------|-----|
|
|
265
|
+
| Build fails | Missing env vars | Check Vercel build logs, add missing vars |
|
|
266
|
+
| 500 errors | Database not connected | Verify `DATABASE_URL` env var is set correctly |
|
|
267
|
+
| CSRF errors | `APP_URL` mismatch | Ensure `APP_URL` matches the actual deployment URL |
|
|
268
|
+
| Rate limiting disabled | Missing Upstash vars | Provision KV store and set `UPSTASH_*` variables |
|
|
269
|
+
| Emails not sending | Missing `RESEND_API_KEY` | Add the key and verify domain in Resend dashboard |
|
|
270
|
+
|
|
271
|
+
## Preview Deployments
|
|
272
|
+
|
|
273
|
+
Preview deployments use separate env vars. Set preview-specific values:
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
vercel env add JWT_SECRET preview
|
|
277
|
+
vercel env add APP_URL preview # Will be overridden by VERCEL_URL
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
For preview deployments, consider using `VERCEL_URL`:
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
const appUrl = process.env.APP_URL
|
|
284
|
+
?? (process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : 'http://localhost:3000');
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Checklist
|
|
288
|
+
|
|
289
|
+
- [ ] Vercel CLI installed and logged in
|
|
290
|
+
- [ ] Project linked with `vercel link`
|
|
291
|
+
- [ ] Database provisioned and schema pushed
|
|
292
|
+
- [ ] KV store provisioned for rate limiting
|
|
293
|
+
- [ ] All required environment variables set
|
|
294
|
+
- [ ] `JWT_SECRET` is unique per environment (production/preview)
|
|
295
|
+
- [ ] `APP_URL` matches the deployment URL
|
|
296
|
+
- [ ] Custom domain configured (optional)
|
|
297
|
+
- [ ] Stripe webhook configured (if billing enabled)
|
|
298
|
+
- [ ] Post-deploy verification completed
|
|
299
|
+
- [ ] Git integration working (push = deploy)
|
|
300
|
+
- [ ] Preview deployments tested
|