@c0x12c/spartan-ai-toolkit 1.0.1
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/.claude-plugin/marketplace.json +16 -0
- package/.claude-plugin/plugin.json +12 -0
- package/README.md +300 -0
- package/VERSION +1 -0
- package/agents/idea-killer.md +72 -0
- package/agents/micronaut-backend-expert.md +45 -0
- package/agents/research-planner.md +70 -0
- package/agents/solution-architect-cto.md +49 -0
- package/bin/cli.js +589 -0
- package/claude-md/00-header.md +39 -0
- package/claude-md/01-core.md +94 -0
- package/claude-md/05-database.md +20 -0
- package/claude-md/11-backend-micronaut.md +36 -0
- package/claude-md/20-frontend-react.md +23 -0
- package/claude-md/30-project-mgmt.md +91 -0
- package/claude-md/40-product.md +36 -0
- package/claude-md/50-ops.md +34 -0
- package/claude-md/60-research.md +75 -0
- package/claude-md/90-footer.md +21 -0
- package/commands/spartan/brainstorm.md +134 -0
- package/commands/spartan/brownfield.md +157 -0
- package/commands/spartan/careful.md +94 -0
- package/commands/spartan/content.md +17 -0
- package/commands/spartan/context-save.md +161 -0
- package/commands/spartan/daily.md +42 -0
- package/commands/spartan/debug.md +156 -0
- package/commands/spartan/deep-dive.md +55 -0
- package/commands/spartan/deploy.md +207 -0
- package/commands/spartan/e2e.md +264 -0
- package/commands/spartan/env-setup.md +166 -0
- package/commands/spartan/fe-review.md +134 -0
- package/commands/spartan/figma-to-code.md +244 -0
- package/commands/spartan/forensics.md +46 -0
- package/commands/spartan/freeze.md +84 -0
- package/commands/spartan/full-run.md +78 -0
- package/commands/spartan/fundraise.md +53 -0
- package/commands/spartan/gsd-upgrade.md +376 -0
- package/commands/spartan/guard.md +42 -0
- package/commands/spartan/init-project.md +178 -0
- package/commands/spartan/interview.md +154 -0
- package/commands/spartan/kickoff.md +52 -0
- package/commands/spartan/kotlin-service.md +109 -0
- package/commands/spartan/lean-canvas.md +222 -0
- package/commands/spartan/map-codebase.md +72 -0
- package/commands/spartan/migration.md +82 -0
- package/commands/spartan/next-app.md +317 -0
- package/commands/spartan/next-feature.md +197 -0
- package/commands/spartan/outreach.md +16 -0
- package/commands/spartan/phase.md +119 -0
- package/commands/spartan/pitch.md +18 -0
- package/commands/spartan/pr-ready.md +200 -0
- package/commands/spartan/project.md +106 -0
- package/commands/spartan/quickplan.md +122 -0
- package/commands/spartan/research.md +19 -0
- package/commands/spartan/review.md +102 -0
- package/commands/spartan/teardown.md +161 -0
- package/commands/spartan/testcontainer.md +97 -0
- package/commands/spartan/think.md +221 -0
- package/commands/spartan/unfreeze.md +13 -0
- package/commands/spartan/update.md +81 -0
- package/commands/spartan/validate.md +193 -0
- package/commands/spartan/workstreams.md +109 -0
- package/commands/spartan/write.md +16 -0
- package/commands/spartan.md +222 -0
- package/frameworks/00-framework-comparison-guide.md +317 -0
- package/frameworks/01-lean-canvas.md +196 -0
- package/frameworks/02-design-sprint.md +304 -0
- package/frameworks/03-foundation-sprint.md +337 -0
- package/frameworks/04-business-model-canvas.md +391 -0
- package/frameworks/05-customer-development.md +426 -0
- package/frameworks/06-jobs-to-be-done.md +358 -0
- package/frameworks/07-mom-test.md +392 -0
- package/frameworks/08-value-proposition-canvas.md +488 -0
- package/frameworks/09-javelin-board.md +428 -0
- package/frameworks/10-build-measure-learn.md +467 -0
- package/frameworks/11-mvp-approaches.md +533 -0
- package/frameworks/think-before-build.md +593 -0
- package/lib/assembler.js +52 -0
- package/lib/packs.js +16 -0
- package/lib/resolver.js +144 -0
- package/lib/resolver.test.js +140 -0
- package/package.json +48 -0
- package/packs/backend-micronaut.yaml +34 -0
- package/packs/backend-nodejs.yaml +15 -0
- package/packs/backend-python.yaml +15 -0
- package/packs/core.yaml +25 -0
- package/packs/database.yaml +21 -0
- package/packs/frontend-react.yaml +23 -0
- package/packs/ops.yaml +16 -0
- package/packs/packs.compiled.json +281 -0
- package/packs/product.yaml +20 -0
- package/packs/project-mgmt.yaml +21 -0
- package/packs/research.yaml +39 -0
- package/packs/shared-backend.yaml +14 -0
- package/rules/backend-micronaut/API_DESIGN.md +250 -0
- package/rules/backend-micronaut/CONTROLLERS.md +755 -0
- package/rules/backend-micronaut/KOTLIN.md +483 -0
- package/rules/backend-micronaut/RETROFIT_PLACEMENT.md +258 -0
- package/rules/backend-micronaut/SERVICES_AND_BEANS.md +673 -0
- package/rules/core/NAMING_CONVENTIONS.md +208 -0
- package/rules/database/ORM_AND_REPO.md +393 -0
- package/rules/database/SCHEMA.md +146 -0
- package/rules/database/TRANSACTIONS.md +311 -0
- package/rules/frontend-react/FRONTEND.md +344 -0
- package/rules/shared-backend/ARCHITECTURE.md +46 -0
- package/skills/api-endpoint-creator/SKILL.md +560 -0
- package/skills/api-endpoint-creator/error-handling-guide.md +244 -0
- package/skills/api-endpoint-creator/examples.md +522 -0
- package/skills/api-endpoint-creator/testing-patterns.md +302 -0
- package/skills/article-writing/SKILL.md +95 -0
- package/skills/backend-api-design/SKILL.md +187 -0
- package/skills/brainstorm/SKILL.md +85 -0
- package/skills/competitive-teardown/SKILL.md +105 -0
- package/skills/content-engine/SKILL.md +101 -0
- package/skills/database-patterns/SKILL.md +145 -0
- package/skills/database-table-creator/SKILL.md +588 -0
- package/skills/database-table-creator/examples.md +552 -0
- package/skills/database-table-creator/migration-template.sql +68 -0
- package/skills/database-table-creator/validation-checklist.md +337 -0
- package/skills/deep-research/SKILL.md +94 -0
- package/skills/idea-validation/SKILL.md +115 -0
- package/skills/investor-materials/SKILL.md +115 -0
- package/skills/investor-outreach/SKILL.md +98 -0
- package/skills/kotlin-best-practices/SKILL.md +145 -0
- package/skills/market-research/SKILL.md +113 -0
- package/skills/security-checklist/SKILL.md +150 -0
- package/skills/startup-pipeline/SKILL.md +125 -0
- package/skills/testing-strategies/SKILL.md +156 -0
- package/skills/ui-ux-pro-max/SKILL.md +377 -0
- package/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/skills/ui-ux-pro-max/data/styles.csv +68 -0
- package/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/skills/ui-ux-pro-max/scripts/core.py +253 -0
- package/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/skills/ui-ux-pro-max/scripts/search.py +114 -0
- package/templates/competitor-analysis.md +60 -0
- package/templates/content/AGENT_TEMPLATE.md +47 -0
- package/templates/content/COMMAND_TEMPLATE.md +27 -0
- package/templates/content/RULE_TEMPLATE.md +40 -0
- package/templates/content/SKILL_TEMPLATE.md +41 -0
- package/templates/idea-canvas.md +47 -0
- package/templates/prd-template.md +84 -0
- package/templates/project-readme.md +35 -0
- package/templates/user-interview.md +69 -0
- package/templates/validation-checklist.md +108 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spartan:next-app
|
|
3
|
+
description: Scaffold a complete new Next.js application from scratch — App Router, TypeScript, Tailwind, testing setup, API client layer, auth scaffolding, and CI config.
|
|
4
|
+
argument-hint: "[app name] [brief description]"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# New Next.js App: {{ args[0] }}
|
|
8
|
+
Description: {{ args[1] }}
|
|
9
|
+
|
|
10
|
+
Scaffolding a **production-ready** Next.js application. This is more complete than
|
|
11
|
+
`/spartan:next-feature` — use this for a brand-new frontend project.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Step 1: Clarify before building
|
|
16
|
+
|
|
17
|
+
Ask:
|
|
18
|
+
1. **Auth**: None / NextAuth.js / custom JWT / Clerk / Auth0?
|
|
19
|
+
2. **State management**: Server-only (preferred) / Zustand / React Query for client state?
|
|
20
|
+
3. **Connects to which BE service(s)?** (Kotlin service names/URLs)
|
|
21
|
+
4. **Deploy target**: Railway / Vercel / AWS / Docker+K8s?
|
|
22
|
+
5. **Database** (if any — for full-stack Next.js with Prisma): Yes / No, using separate BE
|
|
23
|
+
|
|
24
|
+
**Auto mode on?** → Use defaults: No auth, Server-only state, Railway deploy, no DB (separate BE). Proceed immediately.
|
|
25
|
+
**Auto mode off?** → Wait for answers.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Step 2: Bootstrap with create-next-app
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx create-next-app@latest {{ args[0] }} \
|
|
33
|
+
--typescript \
|
|
34
|
+
--tailwind \
|
|
35
|
+
--app \
|
|
36
|
+
--src-dir \
|
|
37
|
+
--import-alias "@/*" \
|
|
38
|
+
--no-eslint # we configure this ourselves
|
|
39
|
+
|
|
40
|
+
cd {{ args[0] }}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Step 3: Install core dependencies
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Testing
|
|
49
|
+
npm install -D vitest @vitejs/plugin-react jsdom
|
|
50
|
+
npm install -D @testing-library/react @testing-library/user-event @testing-library/jest-dom
|
|
51
|
+
|
|
52
|
+
# API + validation
|
|
53
|
+
npm install zod
|
|
54
|
+
|
|
55
|
+
# Auth (if NextAuth chosen)
|
|
56
|
+
npm install next-auth@beta # v5 for App Router
|
|
57
|
+
|
|
58
|
+
# Dev tooling
|
|
59
|
+
npm install -D eslint-config-next @typescript-eslint/eslint-plugin prettier
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Step 4: Configure project structure
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
src/
|
|
68
|
+
├── app/ # App Router
|
|
69
|
+
│ ├── (auth)/ # Route group — auth pages
|
|
70
|
+
│ │ ├── login/page.tsx
|
|
71
|
+
│ │ └── layout.tsx
|
|
72
|
+
│ ├── (dashboard)/ # Route group — protected pages
|
|
73
|
+
│ │ ├── layout.tsx # ← auth check here
|
|
74
|
+
│ │ └── [feature]/
|
|
75
|
+
│ ├── api/ # API routes (only when server actions aren't enough)
|
|
76
|
+
│ ├── globals.css
|
|
77
|
+
│ └── layout.tsx # Root layout
|
|
78
|
+
├── components/
|
|
79
|
+
│ ├── ui/ # Shared primitives (Button, Input, Card...)
|
|
80
|
+
│ └── [feature]/ # Feature-specific components
|
|
81
|
+
├── lib/
|
|
82
|
+
│ ├── api/ # BE API client functions
|
|
83
|
+
│ │ ├── client.ts # Base fetch wrapper
|
|
84
|
+
│ │ └── [service].api.ts # Per-service functions
|
|
85
|
+
│ ├── auth/ # Auth utilities
|
|
86
|
+
│ └── utils.ts # cn(), formatDate(), etc.
|
|
87
|
+
├── hooks/ # Custom React hooks (client-side)
|
|
88
|
+
├── types/ # Shared TypeScript types
|
|
89
|
+
│ └── api.types.ts # Mirror Kotlin DTOs here
|
|
90
|
+
└── middleware.ts # Auth + route protection
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Step 5: Create base API client
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
// src/lib/api/client.ts
|
|
99
|
+
const BASE_URL = process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:8080'
|
|
100
|
+
|
|
101
|
+
type ApiError = {
|
|
102
|
+
message: string
|
|
103
|
+
code: string
|
|
104
|
+
status: number
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export class ApiClient {
|
|
108
|
+
private static async request<T>(
|
|
109
|
+
path: string,
|
|
110
|
+
options?: RequestInit & { tags?: string[] }
|
|
111
|
+
): Promise<T> {
|
|
112
|
+
const res = await fetch(`${BASE_URL}${path}`, {
|
|
113
|
+
...options,
|
|
114
|
+
headers: {
|
|
115
|
+
'Content-Type': 'application/json',
|
|
116
|
+
...options?.headers,
|
|
117
|
+
},
|
|
118
|
+
next: options?.tags ? { tags: options.tags } : undefined,
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
if (!res.ok) {
|
|
122
|
+
const error: ApiError = await res.json().catch(() => ({
|
|
123
|
+
message: 'Unknown error',
|
|
124
|
+
code: 'UNKNOWN',
|
|
125
|
+
status: res.status,
|
|
126
|
+
}))
|
|
127
|
+
throw new Error(error.message)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return res.json()
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
static get<T>(path: string, tags?: string[]) {
|
|
134
|
+
return this.request<T>(path, { tags })
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
static post<T>(path: string, body: unknown) {
|
|
138
|
+
return this.request<T>(path, {
|
|
139
|
+
method: 'POST',
|
|
140
|
+
body: JSON.stringify(body),
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
static put<T>(path: string, body: unknown) {
|
|
145
|
+
return this.request<T>(path, {
|
|
146
|
+
method: 'PUT',
|
|
147
|
+
body: JSON.stringify(body),
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
static delete<T>(path: string) {
|
|
152
|
+
return this.request<T>(path, { method: 'DELETE' })
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Step 6: Configure Vitest
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
// vitest.config.ts
|
|
163
|
+
import { defineConfig } from 'vitest/config'
|
|
164
|
+
import react from '@vitejs/plugin-react'
|
|
165
|
+
import path from 'path'
|
|
166
|
+
|
|
167
|
+
export default defineConfig({
|
|
168
|
+
plugins: [react()],
|
|
169
|
+
test: {
|
|
170
|
+
environment: 'jsdom',
|
|
171
|
+
globals: true,
|
|
172
|
+
setupFiles: ['./src/test/setup.ts'],
|
|
173
|
+
},
|
|
174
|
+
resolve: {
|
|
175
|
+
alias: {
|
|
176
|
+
'@': path.resolve(__dirname, './src'),
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
})
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
// src/test/setup.ts
|
|
184
|
+
import '@testing-library/jest-dom'
|
|
185
|
+
import { vi } from 'vitest'
|
|
186
|
+
|
|
187
|
+
// Mock Next.js navigation
|
|
188
|
+
vi.mock('next/navigation', () => ({
|
|
189
|
+
useRouter: () => ({ push: vi.fn(), replace: vi.fn(), back: vi.fn() }),
|
|
190
|
+
usePathname: () => '/',
|
|
191
|
+
useSearchParams: () => new URLSearchParams(),
|
|
192
|
+
}))
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Add to `package.json`:
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"scripts": {
|
|
199
|
+
"test": "vitest",
|
|
200
|
+
"test:run": "vitest run",
|
|
201
|
+
"test:coverage": "vitest run --coverage"
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Step 7: Environment variables
|
|
209
|
+
|
|
210
|
+
Create `.env.local`:
|
|
211
|
+
```bash
|
|
212
|
+
NEXT_PUBLIC_API_URL=http://localhost:8080
|
|
213
|
+
# NEXTAUTH_URL=http://localhost:3000
|
|
214
|
+
# NEXTAUTH_SECRET= # generate: openssl rand -base64 32
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Create `.env.example` (commit this):
|
|
218
|
+
```bash
|
|
219
|
+
NEXT_PUBLIC_API_URL=http://localhost:8080
|
|
220
|
+
# NEXTAUTH_URL=https://your-domain.com
|
|
221
|
+
# NEXTAUTH_SECRET=your-secret-here
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Step 8: Deploy configuration
|
|
227
|
+
|
|
228
|
+
**Railway** (`railway.toml`):
|
|
229
|
+
```toml
|
|
230
|
+
[build]
|
|
231
|
+
builder = "nixpacks"
|
|
232
|
+
|
|
233
|
+
[deploy]
|
|
234
|
+
startCommand = "npm start"
|
|
235
|
+
healthcheckPath = "/api/health"
|
|
236
|
+
healthcheckTimeout = 30
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Create `src/app/api/health/route.ts`:
|
|
240
|
+
```typescript
|
|
241
|
+
export function GET() {
|
|
242
|
+
return Response.json({ status: 'ok', timestamp: new Date().toISOString() })
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**Docker** (`Dockerfile`):
|
|
247
|
+
```dockerfile
|
|
248
|
+
FROM node:20-alpine AS deps
|
|
249
|
+
WORKDIR /app
|
|
250
|
+
COPY package*.json ./
|
|
251
|
+
RUN npm ci
|
|
252
|
+
|
|
253
|
+
FROM node:20-alpine AS builder
|
|
254
|
+
WORKDIR /app
|
|
255
|
+
COPY --from=deps /app/node_modules ./node_modules
|
|
256
|
+
COPY . .
|
|
257
|
+
RUN npm run build
|
|
258
|
+
|
|
259
|
+
FROM node:20-alpine AS runner
|
|
260
|
+
WORKDIR /app
|
|
261
|
+
ENV NODE_ENV=production
|
|
262
|
+
COPY --from=builder /app/.next/standalone ./
|
|
263
|
+
COPY --from=builder /app/.next/static ./.next/static
|
|
264
|
+
COPY --from=builder /app/public ./public
|
|
265
|
+
EXPOSE 3000
|
|
266
|
+
CMD ["node", "server.js"]
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Add to `next.config.ts`: `output: 'standalone'`
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Step 9: First test — smoke test
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
// src/app/page.test.tsx
|
|
277
|
+
import { render, screen } from '@testing-library/react'
|
|
278
|
+
import { describe, it, expect } from 'vitest'
|
|
279
|
+
import Home from './page'
|
|
280
|
+
|
|
281
|
+
describe('Home page', () => {
|
|
282
|
+
it('renders without crashing', () => {
|
|
283
|
+
render(<Home />)
|
|
284
|
+
expect(document.body).toBeDefined()
|
|
285
|
+
})
|
|
286
|
+
})
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Run: `npm test` — must be green before moving on.
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## Step 10: GitHub Actions CI
|
|
294
|
+
|
|
295
|
+
```yaml
|
|
296
|
+
# .github/workflows/ci.yml
|
|
297
|
+
name: CI
|
|
298
|
+
|
|
299
|
+
on: [push, pull_request]
|
|
300
|
+
|
|
301
|
+
jobs:
|
|
302
|
+
test:
|
|
303
|
+
runs-on: ubuntu-latest
|
|
304
|
+
steps:
|
|
305
|
+
- uses: actions/checkout@v4
|
|
306
|
+
- uses: actions/setup-node@v4
|
|
307
|
+
with:
|
|
308
|
+
node-version: '20'
|
|
309
|
+
cache: 'npm'
|
|
310
|
+
- run: npm ci
|
|
311
|
+
- run: npm run test:run
|
|
312
|
+
- run: npm run build
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
After scaffolding complete:
|
|
316
|
+
"✅ App scaffolded. Run `npm run dev` to start. First test is green.
|
|
317
|
+
Use `/spartan:next-feature [name]` to build individual features."
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spartan:next-feature
|
|
3
|
+
description: Scaffold a new Next.js feature following App Router conventions — pages, components, server actions, types, and tests.
|
|
4
|
+
argument-hint: "[feature name] [brief description]"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Next.js Feature: {{ args[0] }}
|
|
8
|
+
Description: {{ args[1] }}
|
|
9
|
+
|
|
10
|
+
You are scaffolding a new Next.js feature following **App Router** conventions for the Spartan frontend.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Step 1: Clarify before building
|
|
15
|
+
|
|
16
|
+
Ask the user:
|
|
17
|
+
1. Is this a **page** (new route), a **component** (reusable UI), or a **feature** (page + components + logic)?
|
|
18
|
+
2. Does it need **data fetching** from the Kotlin BE? If yes, which API endpoints?
|
|
19
|
+
3. Is any part **interactive** (needs `'use client'`)? What interactions?
|
|
20
|
+
4. Any **auth/access control** requirements?
|
|
21
|
+
|
|
22
|
+
**Auto mode on?** → Infer answers from the feature name and codebase context. Assume "feature" type, check existing API patterns, proceed immediately.
|
|
23
|
+
**Auto mode off?** → Wait for answers, then proceed.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Step 2: Map the directory structure
|
|
28
|
+
|
|
29
|
+
Based on answers, propose this structure under `app/` or `components/`:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
# For a new PAGE feature:
|
|
33
|
+
app/[feature-name]/
|
|
34
|
+
page.tsx ← Server Component (data fetching here)
|
|
35
|
+
page.test.tsx ← Tests
|
|
36
|
+
layout.tsx ← Only if needs own layout
|
|
37
|
+
loading.tsx ← Loading UI (Suspense boundary)
|
|
38
|
+
error.tsx ← Error boundary
|
|
39
|
+
_components/ ← Feature-local components
|
|
40
|
+
FeatureCard.tsx
|
|
41
|
+
FeatureCard.test.tsx
|
|
42
|
+
_actions/ ← Server Actions for mutations
|
|
43
|
+
createFeature.ts
|
|
44
|
+
updateFeature.ts
|
|
45
|
+
_types/ ← TypeScript types
|
|
46
|
+
feature.types.ts
|
|
47
|
+
|
|
48
|
+
# For a reusable COMPONENT:
|
|
49
|
+
components/[ComponentName]/
|
|
50
|
+
[ComponentName].tsx
|
|
51
|
+
[ComponentName].test.tsx
|
|
52
|
+
[ComponentName].stories.tsx ← If using Storybook
|
|
53
|
+
index.ts ← Re-export
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Step 3: Create types first
|
|
59
|
+
|
|
60
|
+
In `_types/feature.types.ts`:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// Mirror the Kotlin DTO structure from BE
|
|
64
|
+
export interface FeatureDto {
|
|
65
|
+
id: string
|
|
66
|
+
// ... fields from BE response
|
|
67
|
+
createdAt: string // ISO string from BE
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// For API responses — always typed
|
|
71
|
+
export interface ApiResponse<T> {
|
|
72
|
+
data: T
|
|
73
|
+
message?: string
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// For form/mutation input
|
|
77
|
+
export interface CreateFeatureInput {
|
|
78
|
+
// ...
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Step 4: Create API client
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
// lib/api/feature.api.ts
|
|
88
|
+
|
|
89
|
+
import { FeatureDto, CreateFeatureInput } from '@/app/[feature]/_types/feature.types'
|
|
90
|
+
|
|
91
|
+
export async function getFeature(id: string): Promise<FeatureDto> {
|
|
92
|
+
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/v1/features/${id}`, {
|
|
93
|
+
next: { revalidate: 60 }, // ISR: revalidate every 60s
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
if (!res.ok) {
|
|
97
|
+
throw new Error(`Failed to fetch feature: ${res.status}`)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return res.json()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export async function createFeature(input: CreateFeatureInput): Promise<FeatureDto> {
|
|
104
|
+
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/v1/features`, {
|
|
105
|
+
method: 'POST',
|
|
106
|
+
headers: { 'Content-Type': 'application/json' },
|
|
107
|
+
body: JSON.stringify(input),
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
if (!res.ok) {
|
|
111
|
+
const error = await res.json()
|
|
112
|
+
throw new Error(error.message || 'Failed to create feature')
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return res.json()
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Step 5: Create Server Component page
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
// app/[feature-name]/page.tsx
|
|
125
|
+
import { getFeature } from '@/lib/api/feature.api'
|
|
126
|
+
import { FeatureCard } from './_components/FeatureCard'
|
|
127
|
+
|
|
128
|
+
// Metadata for SEO
|
|
129
|
+
export const metadata = {
|
|
130
|
+
title: '[Feature Name] | Spartan',
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
interface PageProps {
|
|
134
|
+
params: { id: string }
|
|
135
|
+
searchParams: { [key: string]: string | undefined }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export default async function FeaturePage({ params }: PageProps) {
|
|
139
|
+
// Data fetching directly in Server Component
|
|
140
|
+
const feature = await getFeature(params.id)
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<main>
|
|
144
|
+
<FeatureCard feature={feature} />
|
|
145
|
+
</main>
|
|
146
|
+
)
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Step 6: Write tests FIRST (TDD)
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
// page.test.tsx — Server Component test
|
|
156
|
+
import { render, screen } from '@testing-library/react'
|
|
157
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
158
|
+
import FeaturePage from './page'
|
|
159
|
+
|
|
160
|
+
// Mock the API call
|
|
161
|
+
vi.mock('@/lib/api/feature.api', () => ({
|
|
162
|
+
getFeature: vi.fn()
|
|
163
|
+
}))
|
|
164
|
+
|
|
165
|
+
describe('FeaturePage', () => {
|
|
166
|
+
it('renders feature data when loaded', async () => {
|
|
167
|
+
// given
|
|
168
|
+
const mockFeature = { id: '1', name: 'Test Feature' }
|
|
169
|
+
vi.mocked(getFeature).mockResolvedValue(mockFeature)
|
|
170
|
+
|
|
171
|
+
// when
|
|
172
|
+
const page = await FeaturePage({ params: { id: '1' }, searchParams: {} })
|
|
173
|
+
render(page)
|
|
174
|
+
|
|
175
|
+
// then
|
|
176
|
+
expect(screen.getByText('Test Feature')).toBeInTheDocument()
|
|
177
|
+
})
|
|
178
|
+
})
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Step 7: Environment variables check
|
|
184
|
+
|
|
185
|
+
Ensure these are set in `.env.local` (and in Railway env vars):
|
|
186
|
+
```
|
|
187
|
+
NEXT_PUBLIC_API_URL=http://localhost:8080 # local
|
|
188
|
+
# Railway: set to production BE service URL
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
After scaffolding, run:
|
|
192
|
+
```bash
|
|
193
|
+
npm run dev
|
|
194
|
+
npm test -- --watch [feature-name]
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Say: "Feature scaffolded. First failing test written. Say **'go'** to implement."
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spartan:outreach
|
|
3
|
+
description: Draft personalized investor outreach emails — cold, warm intro, and follow-up
|
|
4
|
+
argument-hint: "[investor name or context]"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Outreach: {{ args[0] | default: "investor email" }}
|
|
8
|
+
|
|
9
|
+
Draft investor communication.
|
|
10
|
+
|
|
11
|
+
## Steps
|
|
12
|
+
|
|
13
|
+
1. Use the `investor-outreach` skill
|
|
14
|
+
2. If investor name is given, search for their thesis, portfolio, recent activity
|
|
15
|
+
3. Personalize the email based on real data
|
|
16
|
+
4. If no investor info is available, create a template and flag what needs personalizing
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spartan:phase
|
|
3
|
+
description: Manage project phases — discuss requirements, plan tasks, execute work, verify results. This is the Spartan wrapper for GSD phase commands. Use after /spartan:project new.
|
|
4
|
+
argument-hint: "[discuss | plan | execute | verify] [phase number]"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Phase {{ args[1] | default: "?" }}: {{ args[0] | default: "discuss" }}
|
|
8
|
+
|
|
9
|
+
You are managing a phase in the current GSD project.
|
|
10
|
+
The user does NOT need to know about `/gsd:*` commands — everything runs through `/spartan:*`.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
{% if args[0] == "discuss" %}
|
|
15
|
+
## Discuss Phase {{ args[1] | default: "N" }}
|
|
16
|
+
|
|
17
|
+
Gathering requirements for this phase. But first — Office Hours.
|
|
18
|
+
|
|
19
|
+
**MANDATORY: Ask these 3 forcing questions BEFORE gathering requirements:**
|
|
20
|
+
|
|
21
|
+
1. **"What pain are we actually solving?"** (not the feature — the underlying pain)
|
|
22
|
+
2. **"What's the narrowest version we can ship to learn?"** (force MVP thinking)
|
|
23
|
+
3. **"What assumption are we making that could be wrong?"** (surface hidden risks)
|
|
24
|
+
|
|
25
|
+
**Auto mode on?** → Still ask these 3 questions. They prevent building the wrong thing.
|
|
26
|
+
|
|
27
|
+
Only after the user answers all 3 → proceed:
|
|
28
|
+
|
|
29
|
+
**Run:** `/gsd:discuss-phase {{ args[1] | default: "N" }}`
|
|
30
|
+
|
|
31
|
+
After discussion, decompose requirements into work units (WUs) per GSD v5:
|
|
32
|
+
- Each WU: max 3 files, max half-day, one commit
|
|
33
|
+
- Group into waves by dependency
|
|
34
|
+
|
|
35
|
+
Then tell the user:
|
|
36
|
+
"Requirements gathered and decomposed into [N] work units across [N] waves. Next step: `/spartan:phase plan {{ args[1] | default: "N" }}`"
|
|
37
|
+
|
|
38
|
+
{% elif args[0] == "plan" %}
|
|
39
|
+
## Plan Phase {{ args[1] | default: "N" }}
|
|
40
|
+
|
|
41
|
+
Generating the execution plan with wave-parallel tasks.
|
|
42
|
+
|
|
43
|
+
**Before planning, check `.memory/index.md`** for relevant patterns, decisions, and knowledge from previous phases.
|
|
44
|
+
|
|
45
|
+
**Run:** `/gsd:plan-phase {{ args[1] | default: "N" }}`
|
|
46
|
+
|
|
47
|
+
The plan should include:
|
|
48
|
+
- Work units grouped into waves
|
|
49
|
+
- Wave 1 = independent tasks (can run in parallel tabs)
|
|
50
|
+
- Wave 2+ = depends on previous wave
|
|
51
|
+
- Each task has: files to touch, test to write first, commit message
|
|
52
|
+
|
|
53
|
+
Then tell the user:
|
|
54
|
+
"Plan ready with [N] waves. Next step: `/spartan:phase execute {{ args[1] | default: "N" }}`"
|
|
55
|
+
|
|
56
|
+
If the user has multiple Claude Code tabs available, suggest:
|
|
57
|
+
"Wave 1 has [N] independent tasks — you can run them in parallel tabs for speed."
|
|
58
|
+
|
|
59
|
+
{% elif args[0] == "execute" %}
|
|
60
|
+
## Execute Phase {{ args[1] | default: "N" }}
|
|
61
|
+
|
|
62
|
+
Running the planned tasks wave by wave.
|
|
63
|
+
|
|
64
|
+
**Run:** `/gsd:execute-phase {{ args[1] | default: "N" }}`
|
|
65
|
+
|
|
66
|
+
During execution:
|
|
67
|
+
- Follow TDD: test first → implement → verify
|
|
68
|
+
- Respect safety guardrails if active (careful/freeze/guard)
|
|
69
|
+
- After each wave, verify all tests pass before starting next wave
|
|
70
|
+
- Capture new knowledge to `.memory/` as you go
|
|
71
|
+
|
|
72
|
+
After execution, tell the user:
|
|
73
|
+
"Phase {{ args[1] | default: "N" }} executed. [N] commits made. Next step: `/spartan:phase verify {{ args[1] | default: "N" }}`"
|
|
74
|
+
|
|
75
|
+
{% elif args[0] == "verify" %}
|
|
76
|
+
## Verify Phase {{ args[1] | default: "N" }}
|
|
77
|
+
|
|
78
|
+
Running acceptance criteria checks and UAT.
|
|
79
|
+
|
|
80
|
+
**Run:** `/gsd:verify-work {{ args[1] | default: "N" }}`
|
|
81
|
+
|
|
82
|
+
After verification:
|
|
83
|
+
1. Check all acceptance criteria from the discuss phase
|
|
84
|
+
2. Run full test suite
|
|
85
|
+
3. Extract decisions made → `.memory/decisions/`
|
|
86
|
+
4. Extract patterns discovered → `.memory/patterns/`
|
|
87
|
+
5. Update `.memory/index.md`
|
|
88
|
+
|
|
89
|
+
Then tell the user:
|
|
90
|
+
- If passed: "Phase {{ args[1] | default: "N" }} verified ✅. Next: `/spartan:phase discuss [N+1]` for the next phase, or `/spartan:project milestone-complete` if milestone is done."
|
|
91
|
+
- If failed: "Phase {{ args[1] | default: "N" }} has [N] issues. Fix them, then re-run `/spartan:phase verify {{ args[1] | default: "N" }}`."
|
|
92
|
+
|
|
93
|
+
{% else %}
|
|
94
|
+
## Unknown action: {{ args[0] }}
|
|
95
|
+
|
|
96
|
+
Available actions:
|
|
97
|
+
- `/spartan:phase discuss N` — Gather requirements (starts with Office Hours)
|
|
98
|
+
- `/spartan:phase plan N` — Generate wave-parallel execution plan
|
|
99
|
+
- `/spartan:phase execute N` — Execute tasks wave by wave
|
|
100
|
+
- `/spartan:phase verify N` — Run acceptance criteria + UAT
|
|
101
|
+
|
|
102
|
+
Example: `/spartan:phase discuss 1`
|
|
103
|
+
{% endif %}
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Phase Lifecycle (for reference)
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
/spartan:phase discuss N ← Office Hours → requirements → decompose
|
|
111
|
+
↓
|
|
112
|
+
/spartan:phase plan N ← Wave-parallel plan from .memory/ context
|
|
113
|
+
↓
|
|
114
|
+
/spartan:phase execute N ← TDD, wave by wave, safety guardrails
|
|
115
|
+
↓
|
|
116
|
+
/spartan:phase verify N ← UAT + capture knowledge to .memory/
|
|
117
|
+
↓
|
|
118
|
+
[next phase or milestone complete]
|
|
119
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spartan:pitch
|
|
3
|
+
description: Create investor-facing materials — deck outline, one-pager, memo, or financial model
|
|
4
|
+
argument-hint: "[what you need: deck, one-pager, memo, model]"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Pitch: {{ args[0] | default: "deck outline" }}
|
|
8
|
+
|
|
9
|
+
Create investor materials.
|
|
10
|
+
|
|
11
|
+
## Steps
|
|
12
|
+
|
|
13
|
+
1. Use the `investor-materials` skill
|
|
14
|
+
2. Check for existing research in the project's `02-research/` and `03-validation/` folders
|
|
15
|
+
3. Use that data as the source of truth
|
|
16
|
+
4. Save to the project's `04-build/` folder
|
|
17
|
+
|
|
18
|
+
If there's no prior research, warn that the materials will be weaker without data.
|