@juho0719/cckit 0.2.4 → 0.2.5
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/assets/skills/plan-viewer/SKILL.md +162 -0
- package/assets/skills/plan-viewer/scripts/frame-template.html +266 -0
- package/assets/skills/plan-viewer/scripts/helper.js +84 -0
- package/assets/skills/plan-viewer/scripts/server.js +334 -0
- package/assets/skills/plan-viewer/scripts/start-server.sh +122 -0
- package/assets/skills/plan-viewer/scripts/stop-server.sh +27 -0
- package/assets/skills/plan-viewer/spec-reviewer-prompt.md +47 -0
- package/assets/skills/plan-viewer/visual-guide.md +234 -0
- package/assets/skills/scaffold/SKILL.md +119 -0
- package/assets/skills/scaffold/presets.md +94 -0
- package/assets/skills/scaffold/scripts/common.sh +73 -0
- package/assets/skills/scaffold/scripts/monorepo.sh +449 -0
- package/assets/skills/scaffold/scripts/nextjs-fullstack.sh +305 -0
- package/package.json +1 -1
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
source "$SCRIPT_DIR/common.sh"
|
|
6
|
+
|
|
7
|
+
# ── Defaults ──────────────────────────────────────────────────────────────────
|
|
8
|
+
DB="sqlite"
|
|
9
|
+
UI="shadcn"
|
|
10
|
+
PM="bun"
|
|
11
|
+
|
|
12
|
+
# ── Usage ─────────────────────────────────────────────────────────────────────
|
|
13
|
+
usage() {
|
|
14
|
+
error "사용법: bash nextjs-fullstack.sh <project-name> [--db sqlite|postgres] [--ui shadcn|none] [--pm bun|npm|pnpm]"
|
|
15
|
+
exit 1
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if [ $# -lt 1 ]; then
|
|
19
|
+
usage
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
PROJECT_ARG="$1"
|
|
23
|
+
shift
|
|
24
|
+
|
|
25
|
+
# ── Flag parsing ───────────────────────────────────────────────────────────────
|
|
26
|
+
while [ $# -gt 0 ]; do
|
|
27
|
+
case "$1" in
|
|
28
|
+
--db)
|
|
29
|
+
DB="$2"; shift 2 ;;
|
|
30
|
+
--ui)
|
|
31
|
+
UI="$2"; shift 2 ;;
|
|
32
|
+
--pm)
|
|
33
|
+
PM="$2"; shift 2 ;;
|
|
34
|
+
*)
|
|
35
|
+
error "알 수 없는 옵션: $1"; usage ;;
|
|
36
|
+
esac
|
|
37
|
+
done
|
|
38
|
+
|
|
39
|
+
# ── Package manager helpers ────────────────────────────────────────────────────
|
|
40
|
+
case "$PM" in
|
|
41
|
+
bun)
|
|
42
|
+
PKG_X="bunx"
|
|
43
|
+
PKG_ADD="bun add"
|
|
44
|
+
PKG_ADD_DEV="bun add -d"
|
|
45
|
+
PKG_RUN="bun run"
|
|
46
|
+
CREATE_FLAG="--use-bun"
|
|
47
|
+
;;
|
|
48
|
+
npm)
|
|
49
|
+
PKG_X="npx"
|
|
50
|
+
PKG_ADD="npm install"
|
|
51
|
+
PKG_ADD_DEV="npm install --save-dev"
|
|
52
|
+
PKG_RUN="npm run"
|
|
53
|
+
CREATE_FLAG="--use-npm"
|
|
54
|
+
;;
|
|
55
|
+
pnpm)
|
|
56
|
+
PKG_X="pnpm dlx"
|
|
57
|
+
PKG_ADD="pnpm add"
|
|
58
|
+
PKG_ADD_DEV="pnpm add -D"
|
|
59
|
+
PKG_RUN="pnpm run"
|
|
60
|
+
CREATE_FLAG="--use-pnpm"
|
|
61
|
+
;;
|
|
62
|
+
*)
|
|
63
|
+
error "지원하지 않는 패키지 매니저: $PM (bun|npm|pnpm)"; exit 1 ;;
|
|
64
|
+
esac
|
|
65
|
+
|
|
66
|
+
# ── Prerequisite check ─────────────────────────────────────────────────────────
|
|
67
|
+
step "사전 조건 확인"
|
|
68
|
+
check_command "$PM" "https://bun.sh / https://npmjs.com / https://pnpm.io"
|
|
69
|
+
check_command git "https://git-scm.com"
|
|
70
|
+
check_command node "https://nodejs.org"
|
|
71
|
+
|
|
72
|
+
# ── Resolve target directory ───────────────────────────────────────────────────
|
|
73
|
+
resolve_target_dir "$PROJECT_ARG"
|
|
74
|
+
|
|
75
|
+
# ── create-next-app ────────────────────────────────────────────────────────────
|
|
76
|
+
step "create-next-app 실행"
|
|
77
|
+
if [ "$INIT_IN_PLACE" = true ]; then
|
|
78
|
+
$PKG_X create-next-app@latest . --typescript --tailwind --eslint --app --src-dir --import-alias "@/*" $CREATE_FLAG --yes
|
|
79
|
+
else
|
|
80
|
+
$PKG_X create-next-app@latest "$PROJECT_NAME" --typescript --tailwind --eslint --app --src-dir --import-alias "@/*" $CREATE_FLAG --yes
|
|
81
|
+
fi
|
|
82
|
+
success "create-next-app 완료"
|
|
83
|
+
|
|
84
|
+
cd "$TARGET_DIR"
|
|
85
|
+
|
|
86
|
+
# ── Drizzle installation ───────────────────────────────────────────────────────
|
|
87
|
+
if [ "$DB" = "sqlite" ]; then
|
|
88
|
+
step "Drizzle ORM + better-sqlite3 설치"
|
|
89
|
+
$PKG_ADD drizzle-orm better-sqlite3
|
|
90
|
+
$PKG_ADD_DEV drizzle-kit @types/better-sqlite3
|
|
91
|
+
success "Drizzle (sqlite) 설치 완료"
|
|
92
|
+
elif [ "$DB" = "postgres" ]; then
|
|
93
|
+
step "Drizzle ORM + pg 설치"
|
|
94
|
+
$PKG_ADD drizzle-orm pg
|
|
95
|
+
$PKG_ADD_DEV drizzle-kit @types/pg
|
|
96
|
+
success "Drizzle (postgres) 설치 완료"
|
|
97
|
+
else
|
|
98
|
+
error "지원하지 않는 DB: $DB (sqlite|postgres)"; exit 1
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# ── DB schema & index ─────────────────────────────────────────────────────────
|
|
102
|
+
step "DB 디렉토리 및 기본 스키마 생성"
|
|
103
|
+
mkdir -p src/lib/db
|
|
104
|
+
mkdir -p src/lib/db/migrations
|
|
105
|
+
|
|
106
|
+
if [ "$DB" = "sqlite" ]; then
|
|
107
|
+
cat > src/lib/db/schema.ts <<'EOF'
|
|
108
|
+
import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core'
|
|
109
|
+
|
|
110
|
+
export const users = sqliteTable('users', {
|
|
111
|
+
id: int('id').primaryKey({ autoIncrement: true }),
|
|
112
|
+
name: text('name').notNull(),
|
|
113
|
+
email: text('email').notNull().unique(),
|
|
114
|
+
createdAt: int('created_at', { mode: 'timestamp' })
|
|
115
|
+
.$defaultFn(() => new Date())
|
|
116
|
+
.notNull(),
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
export type User = typeof users.$inferSelect
|
|
120
|
+
export type NewUser = typeof users.$inferInsert
|
|
121
|
+
EOF
|
|
122
|
+
|
|
123
|
+
cat > src/lib/db/index.ts <<'EOF'
|
|
124
|
+
import Database from 'better-sqlite3'
|
|
125
|
+
import { drizzle } from 'drizzle-orm/better-sqlite3'
|
|
126
|
+
import * as schema from './schema'
|
|
127
|
+
|
|
128
|
+
const sqlite = new Database(process.env.DATABASE_URL ?? 'sqlite.db')
|
|
129
|
+
sqlite.pragma('journal_mode = WAL')
|
|
130
|
+
|
|
131
|
+
export const db = drizzle(sqlite, { schema })
|
|
132
|
+
EOF
|
|
133
|
+
|
|
134
|
+
elif [ "$DB" = "postgres" ]; then
|
|
135
|
+
cat > src/lib/db/schema.ts <<'EOF'
|
|
136
|
+
import { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core'
|
|
137
|
+
|
|
138
|
+
export const users = pgTable('users', {
|
|
139
|
+
id: serial('id').primaryKey(),
|
|
140
|
+
name: text('name').notNull(),
|
|
141
|
+
email: text('email').notNull().unique(),
|
|
142
|
+
createdAt: timestamp('created_at').defaultNow().notNull(),
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
export type User = typeof users.$inferSelect
|
|
146
|
+
export type NewUser = typeof users.$inferInsert
|
|
147
|
+
EOF
|
|
148
|
+
|
|
149
|
+
cat > src/lib/db/index.ts <<EOF
|
|
150
|
+
import { Pool } from 'pg'
|
|
151
|
+
import { drizzle } from 'drizzle-orm/node-postgres'
|
|
152
|
+
import * as schema from './schema'
|
|
153
|
+
|
|
154
|
+
const pool = new Pool({
|
|
155
|
+
connectionString: process.env.DATABASE_URL,
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
export const db = drizzle(pool, { schema })
|
|
159
|
+
EOF
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
success "DB 파일 생성 완료"
|
|
163
|
+
|
|
164
|
+
# ── drizzle.config.ts ─────────────────────────────────────────────────────────
|
|
165
|
+
step "drizzle.config.ts 생성"
|
|
166
|
+
if [ "$DB" = "sqlite" ]; then
|
|
167
|
+
cat > drizzle.config.ts <<'EOF'
|
|
168
|
+
import type { Config } from 'drizzle-kit'
|
|
169
|
+
|
|
170
|
+
export default {
|
|
171
|
+
schema: './src/lib/db/schema.ts',
|
|
172
|
+
out: './src/lib/db/migrations',
|
|
173
|
+
dialect: 'sqlite',
|
|
174
|
+
dbCredentials: {
|
|
175
|
+
url: process.env.DATABASE_URL ?? 'sqlite.db',
|
|
176
|
+
},
|
|
177
|
+
} satisfies Config
|
|
178
|
+
EOF
|
|
179
|
+
elif [ "$DB" = "postgres" ]; then
|
|
180
|
+
cat > drizzle.config.ts <<'EOF'
|
|
181
|
+
import type { Config } from 'drizzle-kit'
|
|
182
|
+
|
|
183
|
+
export default {
|
|
184
|
+
schema: './src/lib/db/schema.ts',
|
|
185
|
+
out: './src/lib/db/migrations',
|
|
186
|
+
dialect: 'postgresql',
|
|
187
|
+
dbCredentials: {
|
|
188
|
+
url: process.env.DATABASE_URL!,
|
|
189
|
+
},
|
|
190
|
+
} satisfies Config
|
|
191
|
+
EOF
|
|
192
|
+
fi
|
|
193
|
+
success "drizzle.config.ts 생성 완료"
|
|
194
|
+
|
|
195
|
+
# ── .env.local ────────────────────────────────────────────────────────────────
|
|
196
|
+
step ".env.local 생성"
|
|
197
|
+
if [ "$DB" = "sqlite" ]; then
|
|
198
|
+
ENV_DB_LINE="DATABASE_URL=sqlite.db"
|
|
199
|
+
elif [ "$DB" = "postgres" ]; then
|
|
200
|
+
ENV_DB_LINE="DATABASE_URL=postgresql://localhost:5432/${PROJECT_NAME}"
|
|
201
|
+
fi
|
|
202
|
+
|
|
203
|
+
if [ ! -f ".env.local" ]; then
|
|
204
|
+
echo "$ENV_DB_LINE" > .env.local
|
|
205
|
+
success ".env.local 생성 완료"
|
|
206
|
+
else
|
|
207
|
+
if ! grep -q "^DATABASE_URL=" .env.local; then
|
|
208
|
+
echo "" >> .env.local
|
|
209
|
+
echo "$ENV_DB_LINE" >> .env.local
|
|
210
|
+
success ".env.local에 DATABASE_URL 추가 완료"
|
|
211
|
+
else
|
|
212
|
+
info ".env.local에 이미 DATABASE_URL 존재 — 건너뜀"
|
|
213
|
+
fi
|
|
214
|
+
fi
|
|
215
|
+
|
|
216
|
+
# ── .gitignore ────────────────────────────────────────────────────────────────
|
|
217
|
+
step ".gitignore 업데이트"
|
|
218
|
+
if [ "$DB" = "sqlite" ]; then
|
|
219
|
+
if ! grep -q "sqlite.db" .gitignore 2>/dev/null; then
|
|
220
|
+
cat >> .gitignore <<'EOF'
|
|
221
|
+
|
|
222
|
+
# SQLite
|
|
223
|
+
*.db
|
|
224
|
+
*.db-shm
|
|
225
|
+
*.db-wal
|
|
226
|
+
EOF
|
|
227
|
+
success ".gitignore에 sqlite.db 패턴 추가"
|
|
228
|
+
else
|
|
229
|
+
info ".gitignore에 이미 sqlite.db 패턴 존재 — 건너뜀"
|
|
230
|
+
fi
|
|
231
|
+
fi
|
|
232
|
+
|
|
233
|
+
# ── package.json scripts ───────────────────────────────────────────────────────
|
|
234
|
+
step "package.json에 Drizzle 스크립트 추가"
|
|
235
|
+
node -e "
|
|
236
|
+
const fs = require('fs');
|
|
237
|
+
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
|
238
|
+
pkg.scripts = {
|
|
239
|
+
...pkg.scripts,
|
|
240
|
+
'db:generate': 'drizzle-kit generate',
|
|
241
|
+
'db:migrate': 'drizzle-kit migrate',
|
|
242
|
+
'db:push': 'drizzle-kit push',
|
|
243
|
+
'db:studio': 'drizzle-kit studio',
|
|
244
|
+
};
|
|
245
|
+
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
|
|
246
|
+
"
|
|
247
|
+
success "package.json 스크립트 추가 완료"
|
|
248
|
+
|
|
249
|
+
# ── shadcn/ui ─────────────────────────────────────────────────────────────────
|
|
250
|
+
if [ "$UI" = "shadcn" ]; then
|
|
251
|
+
step "shadcn/ui 초기화"
|
|
252
|
+
printf '\n' | $PKG_X shadcn@latest init --yes
|
|
253
|
+
success "shadcn/ui 초기화 완료"
|
|
254
|
+
|
|
255
|
+
step "기본 shadcn/ui 컴포넌트 설치 (button, input, card)"
|
|
256
|
+
$PKG_X shadcn@latest add button input card --yes
|
|
257
|
+
success "shadcn/ui 컴포넌트 설치 완료"
|
|
258
|
+
elif [ "$UI" = "none" ]; then
|
|
259
|
+
info "UI 라이브러리 건너뜀 (--ui none)"
|
|
260
|
+
else
|
|
261
|
+
error "지원하지 않는 UI: $UI (shadcn|none)"; exit 1
|
|
262
|
+
fi
|
|
263
|
+
|
|
264
|
+
# ── Initial DB migration ───────────────────────────────────────────────────────
|
|
265
|
+
step "초기 DB 마이그레이션 생성"
|
|
266
|
+
$PKG_RUN db:generate
|
|
267
|
+
success "마이그레이션 파일 생성 완료"
|
|
268
|
+
|
|
269
|
+
# ── Git commit ────────────────────────────────────────────────────────────────
|
|
270
|
+
step "Git 커밋"
|
|
271
|
+
COMMIT_MSG="chore: add"
|
|
272
|
+
[ "$UI" = "shadcn" ] && COMMIT_MSG="$COMMIT_MSG shadcn/ui +"
|
|
273
|
+
COMMIT_MSG="$COMMIT_MSG drizzle ${DB} setup"
|
|
274
|
+
git_init_commit "$COMMIT_MSG"
|
|
275
|
+
|
|
276
|
+
# ── Summary ───────────────────────────────────────────────────────────────────
|
|
277
|
+
echo ""
|
|
278
|
+
echo -e "${GREEN}${BOLD}✓ 프로젝트 초기화 완료: ${PROJECT_NAME}${RESET}"
|
|
279
|
+
echo ""
|
|
280
|
+
echo -e " ${BOLD}옵션:${RESET} DB=${DB} UI=${UI} PM=${PM}"
|
|
281
|
+
echo ""
|
|
282
|
+
echo -e " ${BOLD}주요 구조:${RESET}"
|
|
283
|
+
echo -e " src/"
|
|
284
|
+
echo -e " app/ — Next.js App Router"
|
|
285
|
+
echo -e " ${CYAN}lib/db/${RESET} — Drizzle ORM"
|
|
286
|
+
echo -e " index.ts — DB 연결"
|
|
287
|
+
echo -e " schema.ts — 테이블 스키마"
|
|
288
|
+
echo -e " migrations/ — 마이그레이션 파일"
|
|
289
|
+
if [ "$UI" = "shadcn" ]; then
|
|
290
|
+
echo -e " ${CYAN}components/ui/${RESET} — shadcn/ui 컴포넌트"
|
|
291
|
+
fi
|
|
292
|
+
echo ""
|
|
293
|
+
echo -e " ${BOLD}DB 명령어:${RESET}"
|
|
294
|
+
echo -e " $PKG_RUN db:generate — 스키마 변경 후 마이그레이션 생성"
|
|
295
|
+
echo -e " $PKG_RUN db:migrate — 마이그레이션 적용"
|
|
296
|
+
echo -e " $PKG_RUN db:push — 마이그레이션 없이 스키마 직접 적용"
|
|
297
|
+
echo -e " $PKG_RUN db:studio — Drizzle Studio (DB GUI)"
|
|
298
|
+
echo ""
|
|
299
|
+
echo -e " ${BOLD}개발 시작:${RESET}"
|
|
300
|
+
if [ "$INIT_IN_PLACE" = false ]; then
|
|
301
|
+
echo -e " cd ${PROJECT_NAME}"
|
|
302
|
+
fi
|
|
303
|
+
echo -e " $PKG_RUN db:migrate — 첫 마이그레이션 적용"
|
|
304
|
+
echo -e " $PKG_RUN dev — 개발 서버 시작"
|
|
305
|
+
echo ""
|
package/package.json
CHANGED