ship-create 1.7.2 → 1.8.0
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/create.mjs
CHANGED
|
@@ -55,6 +55,14 @@ const LANGUAGES = [
|
|
|
55
55
|
{ code: "th", name: "Thai (ภาษาไทย)", desc: "ข้อความ label และ copy ในระบบเป็นภาษาไทย" },
|
|
56
56
|
];
|
|
57
57
|
|
|
58
|
+
const REVENUE_MODELS = [
|
|
59
|
+
{ key: "SUBSCRIPTION", name: "Subscription", desc: "รายเดือน / รายปี — recurring revenue", descEn: "monthly or annual recurring payments" },
|
|
60
|
+
{ key: "ONE_TIME", name: "One-time payment", desc: "จ่ายครั้งเดียว เข้าถึงตลอด", descEn: "pay once, access forever" },
|
|
61
|
+
{ key: "FREEMIUM", name: "Freemium", desc: "ใช้ฟรีได้ + paid tier สำหรับ feature เพิ่ม", descEn: "free tier + paid upgrade for more features" },
|
|
62
|
+
{ key: "MARKETPLACE", name: "Marketplace fee", desc: "เก็บ % จาก transaction ระหว่าง buyer กับ seller", descEn: "take a % cut from each transaction" },
|
|
63
|
+
{ key: "FREE", name: "Free / not yet", desc: "ยังไม่มี monetization ตอนนี้", descEn: "no monetization planned yet" },
|
|
64
|
+
];
|
|
65
|
+
|
|
58
66
|
const I18N = {
|
|
59
67
|
en: {
|
|
60
68
|
sectionIdea: "── About your idea ────────────────────────────",
|
|
@@ -65,6 +73,7 @@ const I18N = {
|
|
|
65
73
|
qUserDefault: "small business owners",
|
|
66
74
|
qProblem: "What is the #1 problem they face today?",
|
|
67
75
|
qValue: "What makes them say 'I need this'? (the aha moment)",
|
|
76
|
+
qRevenue: "How will this make money?",
|
|
68
77
|
scaffolding: (slug) => `Scaffolding ./${slug} ...`,
|
|
69
78
|
installing: (pm) => `Installing packages with ${pm} ...`,
|
|
70
79
|
installFail: (slug, pm) => `${pm} install failed. Run it manually:\n cd ${slug} && ${pm} install`,
|
|
@@ -96,6 +105,7 @@ const I18N = {
|
|
|
96
105
|
qUserDefault: "เจ้าของธุรกิจขนาดเล็ก",
|
|
97
106
|
qProblem: "ปัญหาอันดับ 1 ที่พวกเขาเจออยู่ทุกวันคืออะไร?",
|
|
98
107
|
qValue: "อะไรทำให้พวกเขาบอกว่า 'ฉันต้องการสิ่งนี้!'? (จุด aha moment)",
|
|
108
|
+
qRevenue: "แผนหาเงินของโปรเจคนี้คืออะไร?",
|
|
99
109
|
scaffolding: (slug) => `กำลัง scaffold ./${slug} ...`,
|
|
100
110
|
installing: (pm) => `กำลังติดตั้ง packages ด้วย ${pm} ...`,
|
|
101
111
|
installFail: (slug, pm) => `${pm} install ล้มเหลว รันเองได้ที่:\n cd ${slug} && ${pm} install`,
|
|
@@ -299,7 +309,15 @@ function toKebabCase(str) {
|
|
|
299
309
|
|
|
300
310
|
// ─── Doc builders ─────────────────────────────────────────────────────────────
|
|
301
311
|
|
|
302
|
-
|
|
312
|
+
const REVENUE_SCREENS = {
|
|
313
|
+
SUBSCRIPTION: "Pricing page with tier comparison + Stripe subscription checkout",
|
|
314
|
+
ONE_TIME: "Product page with one-time payment CTA + Stripe checkout",
|
|
315
|
+
FREEMIUM: "Free vs paid tier comparison page + upgrade flow",
|
|
316
|
+
MARKETPLACE: "Transaction page showing platform fee + seller/buyer checkout",
|
|
317
|
+
FREE: "No payment screens needed for MVP",
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
function buildProjectMd(projectName, productTypeName, { targetUser, problem, valueProp, idea, uiLanguage, revenueModel }) {
|
|
303
321
|
return `# PROJECT.md
|
|
304
322
|
|
|
305
323
|
**Phase:** S — Structure
|
|
@@ -381,7 +399,9 @@ ${projectName} is a ${productTypeName.toLowerCase()} that helps **${targetUser}*
|
|
|
381
399
|
|
|
382
400
|
## 8. Revenue Model
|
|
383
401
|
|
|
384
|
-
- **Pricing model:**
|
|
402
|
+
- **Pricing model:** ${revenueModel ? revenueModel.name : "[fill in]"}
|
|
403
|
+
- **How it works:** ${revenueModel ? revenueModel.descEn : "[fill in]"}
|
|
404
|
+
- **Revenue screen to build:** ${revenueModel ? (REVENUE_SCREENS[revenueModel.key] || "[fill in]") : "[fill in]"}
|
|
385
405
|
- **Price point:** [fill in]
|
|
386
406
|
- **Revenue goal (Month 3):** [fill in]
|
|
387
407
|
|
|
@@ -510,9 +530,15 @@ async function main() {
|
|
|
510
530
|
// ── Interactive selections (no readline needed) ────────────────────────────
|
|
511
531
|
let productType, uiLanguage;
|
|
512
532
|
|
|
533
|
+
let revenueModel;
|
|
534
|
+
|
|
513
535
|
if (isTTY) {
|
|
514
|
-
productType
|
|
515
|
-
uiLanguage
|
|
536
|
+
productType = await selectInteractive("What type of system are you building?", PRODUCT_TYPES);
|
|
537
|
+
uiLanguage = await selectInteractive("UI language — what will your app display to users?", LANGUAGES);
|
|
538
|
+
revenueModel = await selectInteractive(
|
|
539
|
+
uiLanguage.code === "th" ? "แผนหาเงินของโปรเจคนี้คืออะไร?" : "How will this make money?",
|
|
540
|
+
REVENUE_MODELS.map(r => ({ ...r, desc: uiLanguage.code === "th" ? r.desc : r.descEn }))
|
|
541
|
+
);
|
|
516
542
|
}
|
|
517
543
|
|
|
518
544
|
// ── Text questions (readline) — switch language after uiLanguage is known ──
|
|
@@ -520,8 +546,9 @@ async function main() {
|
|
|
520
546
|
const nextLine = makeLineReader(rl);
|
|
521
547
|
|
|
522
548
|
if (!isTTY) {
|
|
523
|
-
productType
|
|
524
|
-
uiLanguage
|
|
549
|
+
productType = await selectFallback("What type of system are you building?", PRODUCT_TYPES, nextLine);
|
|
550
|
+
uiLanguage = await selectFallback("UI language — what will your app display to users?", LANGUAGES, nextLine);
|
|
551
|
+
revenueModel = await selectFallback("How will this make money?", REVENUE_MODELS, nextLine);
|
|
525
552
|
}
|
|
526
553
|
|
|
527
554
|
const t = I18N[uiLanguage.code] ?? I18N.en;
|
|
@@ -576,7 +603,7 @@ async function main() {
|
|
|
576
603
|
|
|
577
604
|
fs.writeFileSync(
|
|
578
605
|
path.join(docsDir, "PROJECT.md"),
|
|
579
|
-
buildProjectMd(projectNameRaw, productType.name, { targetUser, problem, valueProp, idea, uiLanguage: uiLanguage.name })
|
|
606
|
+
buildProjectMd(projectNameRaw, productType.name, { targetUser, problem, valueProp, idea, uiLanguage: uiLanguage.name, revenueModel })
|
|
580
607
|
);
|
|
581
608
|
|
|
582
609
|
fs.writeFileSync(
|
package/package.json
CHANGED
|
@@ -44,7 +44,16 @@ Rules for the diagram:
|
|
|
44
44
|
- Keep node labels short (3–5 words max)
|
|
45
45
|
|
|
46
46
|
### Step 3 — Build prototype
|
|
47
|
-
Generate a fresh theme from scratch based on the product type — **never reuse the default colors already in `app/globals.css`**. Overwrite the entire `:root` and `.dark` blocks with new values derived from `theme-guide.md` and the product context. Apply to `app/globals.css` and `app/layout.tsx`.
|
|
47
|
+
Generate a fresh theme from scratch based on the product type — **never reuse the default colors already in `app/globals.css`**. Overwrite the entire `:root` and `.dark` blocks with new values derived from `theme-guide.md` and the product context. Apply to `app/globals.css` and `app/layout.tsx`. Record the theme choice in `docs/DESIGN_SYSTEM.md`.
|
|
48
|
+
|
|
49
|
+
Build these screens (in priority order):
|
|
50
|
+
1. **Home screen** — replace `app/page.tsx` with the real entry point from `HUMAN_FLOW.md`
|
|
51
|
+
2. **Revenue screen** — read Section 8 of `PROJECT.md` for the revenue model, then build the matching screen:
|
|
52
|
+
- Subscription → pricing page with tier comparison + Stripe checkout stub
|
|
53
|
+
- One-time → product page with buy CTA + Stripe checkout stub
|
|
54
|
+
- Freemium → free vs paid tier comparison + upgrade CTA
|
|
55
|
+
- Marketplace fee → transaction page showing platform fee structure
|
|
56
|
+
- Free / not yet → skip, build the next most important screen instead
|
|
48
57
|
|
|
49
58
|
### Step 4 — Run
|
|
50
59
|
Run `npm run dev` (or `pnpm dev` if pnpm is available). Confirm the app compiles and is accessible at localhost:3000.
|