@pradip1995/create-storefront-app 0.2.2 → 0.3.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.
Files changed (53) hide show
  1. package/bin/create-storefront-app.js +149 -53
  2. package/lib/build-backend-package.js +54 -0
  3. package/lib/build-homepage-defaults.cjs +50 -0
  4. package/lib/deps.js +3 -1
  5. package/lib/docker-template-vars.js +32 -0
  6. package/lib/medusa-plugin-versions.json +55 -0
  7. package/lib/scaffold-backend.js +107 -0
  8. package/lib/scaffold-docker.js +82 -0
  9. package/lib/versions.js +4 -3
  10. package/package.json +3 -2
  11. package/templates/backend/.cursor/commands/seed-backend.md +16 -0
  12. package/templates/backend/.cursor/rules/medusa-backend.mdc +55 -0
  13. package/templates/backend/config/README.md +21 -0
  14. package/templates/backend/config/homepage-config.json +568 -0
  15. package/templates/backend/env.template +53 -0
  16. package/templates/backend/gitignore +8 -0
  17. package/templates/backend/medusa-config.full.ts +251 -0
  18. package/templates/backend/medusa-config.minimal.ts +141 -0
  19. package/templates/backend/scripts/build-dynamic-config-defaults.mjs +25 -0
  20. package/templates/backend/scripts/build-homepage-defaults.cjs +50 -0
  21. package/templates/backend/src/config/product-metadata-descriptors.ts +27 -0
  22. package/templates/backend/src/scripts/seed.ts +212 -0
  23. package/templates/backend/tsconfig.json +24 -0
  24. package/templates/docker/Makefile +86 -0
  25. package/templates/docker/backend/.dockerignore +8 -0
  26. package/templates/docker/backend/Dockerfile +30 -0
  27. package/templates/docker/data/README.md +12 -0
  28. package/templates/docker/data/dump.sql +3 -0
  29. package/templates/docker/docker/.env.example +36 -0
  30. package/templates/docker/docker/frontend.build.defaults +7 -0
  31. package/templates/docker/docker/gitignore +1 -0
  32. package/templates/docker/docker/postgres/01-create-postgres-role.sql +9 -0
  33. package/templates/docker/docker/postgres/docker-entrypoint-wrapper.sh +49 -0
  34. package/templates/docker/docker-compose.infra.yml +64 -0
  35. package/templates/docker/docker-compose.yml +138 -0
  36. package/templates/docker/storefront/.dockerignore +9 -0
  37. package/templates/docker/storefront/Dockerfile +53 -0
  38. package/templates/root/.cursor/commands/docker-dev.md +32 -0
  39. package/templates/root/.cursor/rules/monorepo-layout.mdc +55 -0
  40. package/templates/shared/.cursor/commands/change-theme-colors.md +28 -0
  41. package/templates/shared/.cursor/commands/fix-segment-issue.md +56 -0
  42. package/templates/shared/.cursor/commands/rebuild-storefront.md +19 -0
  43. package/templates/shared/.cursor/commands/update-home-sections.md +50 -0
  44. package/templates/shared/.cursor/rules/customize-sections.mdc +49 -0
  45. package/templates/shared/.cursor/rules/customize-theme.mdc +57 -0
  46. package/templates/shared/.cursor/rules/storefront-architecture.mdc +41 -0
  47. package/templates/shared/.cursor/skills/customize-storefront-theme/SKILL.md +47 -0
  48. package/templates/shared/.cursor/skills/fix-segment-issues/SKILL.md +68 -0
  49. package/templates/shared/.cursor/skills/update-storefront-sections/SKILL.md +52 -0
  50. package/templates/shared/README.md +100 -0
  51. package/templates/shared/root-gitignore +6 -0
  52. package/templates/shared/storefront-only-README.md +25 -0
  53. package/templates/shared/theme-overrides.css +16 -0
@@ -0,0 +1,251 @@
1
+ import path from "path"
2
+ import { createRequire } from "module"
3
+ import { loadEnv, defineConfig, Modules, ContainerRegistrationKeys } from "@medusajs/framework/utils"
4
+ import homepageConfig from "./config/homepage-config.json"
5
+ import { PRODUCT_METADATA_DESCRIPTORS } from "./src/config/product-metadata-descriptors"
6
+
7
+ const require = createRequire(import.meta.url)
8
+
9
+ loadEnv(process.env.NODE_ENV || "development", process.cwd())
10
+
11
+ const storefrontUrl = process.env.STOREFRONT_URL || "http://localhost:8000"
12
+ const defaultRegion = process.env.SEED_DEFAULT_REGION || "in"
13
+
14
+ module.exports = defineConfig({
15
+ projectConfig: {
16
+ databaseUrl: process.env.DATABASE_URL,
17
+ http: {
18
+ storeCors: process.env.STORE_CORS!,
19
+ adminCors: process.env.ADMIN_CORS!,
20
+ authCors: process.env.AUTH_CORS!,
21
+ jwtSecret: process.env.JWT_SECRET || "supersecret",
22
+ cookieSecret: process.env.COOKIE_SECRET || "supersecret",
23
+ },
24
+ cookieOptions: {
25
+ sameSite: "lax",
26
+ secure: process.env.NODE_ENV === "production",
27
+ },
28
+ },
29
+ plugins: [
30
+ { resolve: "medusa-product-helper", options: {} },
31
+ {
32
+ resolve: "stock-monitoring",
33
+ options: { low_stock_threshold: 10, slow_moving_days_threshold: 90 },
34
+ },
35
+ {
36
+ resolve: "medusa-invoice-sbl",
37
+ options: {
38
+ attachInvoiceToEmail: true,
39
+ guestJwtSecret: process.env.JWT_SECRET,
40
+ },
41
+ },
42
+ {
43
+ resolve: "medusa-dynamic-metadata",
44
+ options: {
45
+ entities: {
46
+ products: {
47
+ descriptors: PRODUCT_METADATA_DESCRIPTORS,
48
+ expose_client_helpers: true,
49
+ filterable: true,
50
+ },
51
+ categories: {
52
+ descriptors: [
53
+ { key: "category_image", label: "Category Image", type: "file" },
54
+ { key: "category_background_color", label: "Category Background Color", type: "text" },
55
+ ],
56
+ },
57
+ collections: {
58
+ descriptors: [
59
+ { key: "collection_icon", label: "Collection Icon", type: "file" },
60
+ {
61
+ key: "home_featured",
62
+ label: "Show on Home",
63
+ type: "select",
64
+ options: [
65
+ { value: "true", label: "Yes" },
66
+ { value: "false", label: "No" },
67
+ ],
68
+ },
69
+ ],
70
+ },
71
+ product_variants: {
72
+ descriptors: [{ key: "variant_image", label: "Variant Image", type: "file" }],
73
+ },
74
+ },
75
+ },
76
+ },
77
+ {
78
+ resolve: "medusa-review-rating",
79
+ options: { autoApprove: true, requireVerifiedPurchase: false, multiple_rating: true },
80
+ },
81
+ {
82
+ resolve: "medusa-plugin-dynamic-config",
83
+ options: { configs: { "homepage-config": homepageConfig } },
84
+ },
85
+ {
86
+ resolve: "medusa-contact-us",
87
+ options: {
88
+ default_status: "pending",
89
+ payload_fields: [
90
+ { key: "full_name", type: "text", required: true, label: "Full Name" },
91
+ { key: "email", type: "text", required: true, label: "Email" },
92
+ { key: "message", type: "textarea", required: true, label: "Message" },
93
+ ],
94
+ allowed_statuses: ["pending", "in_progress", "resolved", "closed"],
95
+ },
96
+ },
97
+ {
98
+ resolve: "order-management",
99
+ options: {
100
+ jwtSecret: process.env.JWT_SECRET,
101
+ storefrontUrl,
102
+ },
103
+ },
104
+ {
105
+ resolve: "customer-registration",
106
+ options: {
107
+ storefrontUrl,
108
+ registration: { identifier: "both", require_verification: true },
109
+ login: { identifier: "both" },
110
+ },
111
+ },
112
+ {
113
+ resolve: "medusa-shiprocket-fulfillment-sbl",
114
+ options: {
115
+ shiprocket: {
116
+ email: process.env.SHIPROCKET_EMAIL,
117
+ password: process.env.SHIPROCKET_PASSWORD,
118
+ pickupLocation: process.env.SHIPROCKET_PICKUP_LOCATION || "Primary",
119
+ },
120
+ webhookSecret: process.env.SHIPROCKET_WEBHOOK_SECRET,
121
+ },
122
+ },
123
+ { resolve: "medusa-notification-token-management", options: {} },
124
+ { resolve: "medusa-customer-file-upload", options: {} },
125
+ {
126
+ resolve: path.dirname(require.resolve("medusa-analytics/package.json")),
127
+ options: {},
128
+ },
129
+ { resolve: "medusa-export", options: {} },
130
+ { resolve: "medusa-payment-provider", options: {} },
131
+ ],
132
+ modules: {
133
+ [Modules.AUTH]: {
134
+ resolve: "@medusajs/medusa/auth",
135
+ dependencies: [Modules.CACHE, ContainerRegistrationKeys.LOGGER],
136
+ options: {
137
+ providers: [
138
+ { resolve: "@medusajs/medusa/auth-emailpass", id: "emailpass" },
139
+ { resolve: "customer-registration/providers/phonepass", id: "phonepass" },
140
+ ...(process.env.GOOGLE_CLIENT_ID
141
+ ? [
142
+ {
143
+ resolve: "@medusajs/auth-google",
144
+ id: "google",
145
+ options: {
146
+ clientId: process.env.GOOGLE_CLIENT_ID,
147
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET,
148
+ },
149
+ },
150
+ ]
151
+ : []),
152
+ ],
153
+ },
154
+ },
155
+ [Modules.FULFILLMENT]: {
156
+ resolve: "@medusajs/medusa/fulfillment",
157
+ options: {
158
+ providers: [
159
+ { resolve: "@medusajs/medusa/fulfillment-manual", id: "manual" },
160
+ ...(process.env.SHIPROCKET_EMAIL
161
+ ? [
162
+ {
163
+ resolve: "medusa-shiprocket-fulfillment-sbl",
164
+ id: "shiprocket",
165
+ },
166
+ ]
167
+ : []),
168
+ ],
169
+ },
170
+ },
171
+ ...(process.env.CASHFREE_CLIENT_ID
172
+ ? {
173
+ [Modules.PAYMENT]: {
174
+ resolve: "@medusajs/medusa/payment",
175
+ options: {
176
+ providers: [
177
+ {
178
+ resolve: "medusa-payment-provider/providers/cashfree",
179
+ id: "cashfree",
180
+ options: {
181
+ client_id: process.env.CASHFREE_CLIENT_ID,
182
+ client_secret: process.env.CASHFREE_CLIENT_SECRET,
183
+ environment:
184
+ process.env.CASHFREE_ENVIRONMENT === "production" ? "production" : "sandbox",
185
+ return_url: `${storefrontUrl}/${defaultRegion}/checkout/payment/callback`,
186
+ },
187
+ },
188
+ ],
189
+ },
190
+ },
191
+ }
192
+ : {}),
193
+ ...(process.env.SMTP_HOST
194
+ ? {
195
+ [Modules.NOTIFICATION]: {
196
+ resolve: "@medusajs/medusa/notification",
197
+ options: {
198
+ providers: [
199
+ {
200
+ resolve: "@tsc_tech/medusa-plugin-smtp/providers/smtp",
201
+ id: "smtp",
202
+ options: {
203
+ host: process.env.SMTP_HOST,
204
+ port: Number(process.env.SMTP_PORT) || 465,
205
+ secure: process.env.SMTP_SECURE === "true",
206
+ auth: {
207
+ user: process.env.SMTP_USER,
208
+ pass: process.env.SMTP_PASS,
209
+ },
210
+ from: process.env.SMTP_FROM || process.env.SMTP_USER,
211
+ },
212
+ },
213
+ ],
214
+ },
215
+ },
216
+ }
217
+ : {}),
218
+ file: {
219
+ resolve: "@medusajs/medusa/file",
220
+ options: {
221
+ providers: [
222
+ ...(process.env.AWS_BUCKET
223
+ ? [
224
+ {
225
+ resolve: "@medusajs/medusa/file-s3",
226
+ id: "s3",
227
+ options: {
228
+ file_url: process.env.AWS_FILE_URL,
229
+ access_key_id: process.env.AWS_ACCESS_KEY,
230
+ secret_access_key: process.env.AWS_SECRET_ACCESS_KEY,
231
+ region: process.env.AWS_REGION,
232
+ bucket: process.env.AWS_BUCKET,
233
+ prefix: "uploads",
234
+ },
235
+ },
236
+ ]
237
+ : [
238
+ {
239
+ resolve: "@medusajs/medusa/file-local",
240
+ id: "local",
241
+ options: {
242
+ upload_dir: "static",
243
+ backend_url: `${process.env.MEDUSA_BACKEND_URL || "http://localhost:9000"}/static`,
244
+ },
245
+ },
246
+ ]),
247
+ ],
248
+ },
249
+ },
250
+ },
251
+ })
@@ -0,0 +1,141 @@
1
+ import { loadEnv, defineConfig, Modules, ContainerRegistrationKeys } from "@medusajs/framework/utils"
2
+ import homepageConfig from "./config/homepage-config.json"
3
+ import { PRODUCT_METADATA_DESCRIPTORS } from "./src/config/product-metadata-descriptors"
4
+
5
+ loadEnv(process.env.NODE_ENV || "development", process.cwd())
6
+
7
+ module.exports = defineConfig({
8
+ projectConfig: {
9
+ databaseUrl: process.env.DATABASE_URL,
10
+ http: {
11
+ storeCors: process.env.STORE_CORS!,
12
+ adminCors: process.env.ADMIN_CORS!,
13
+ authCors: process.env.AUTH_CORS!,
14
+ jwtSecret: process.env.JWT_SECRET || "supersecret",
15
+ cookieSecret: process.env.COOKIE_SECRET || "supersecret",
16
+ },
17
+ cookieOptions: {
18
+ sameSite: "lax",
19
+ secure: process.env.NODE_ENV === "production",
20
+ },
21
+ },
22
+ plugins: [
23
+ { resolve: "medusa-product-helper", options: {} },
24
+ {
25
+ resolve: "medusa-dynamic-metadata",
26
+ options: {
27
+ entities: {
28
+ products: {
29
+ descriptors: PRODUCT_METADATA_DESCRIPTORS,
30
+ expose_client_helpers: true,
31
+ filterable: true,
32
+ },
33
+ categories: {
34
+ descriptors: [
35
+ { key: "category_image", label: "Category Image", type: "file" },
36
+ { key: "category_background_color", label: "Category Background Color", type: "text" },
37
+ ],
38
+ },
39
+ collections: {
40
+ descriptors: [
41
+ { key: "collection_icon", label: "Collection Icon", type: "file" },
42
+ {
43
+ key: "home_featured",
44
+ label: "Show on Home",
45
+ type: "select",
46
+ options: [
47
+ { value: "true", label: "Yes" },
48
+ { value: "false", label: "No" },
49
+ ],
50
+ },
51
+ ],
52
+ },
53
+ product_variants: {
54
+ descriptors: [{ key: "variant_image", label: "Variant Image", type: "file" }],
55
+ },
56
+ },
57
+ },
58
+ },
59
+ {
60
+ resolve: "medusa-review-rating",
61
+ options: {
62
+ autoApprove: true,
63
+ requireVerifiedPurchase: false,
64
+ multiple_rating: true,
65
+ },
66
+ },
67
+ {
68
+ resolve: "medusa-plugin-dynamic-config",
69
+ options: {
70
+ configs: {
71
+ "homepage-config": homepageConfig,
72
+ },
73
+ },
74
+ },
75
+ {
76
+ resolve: "medusa-contact-us",
77
+ options: {
78
+ default_status: "pending",
79
+ payload_fields: [
80
+ { key: "full_name", type: "text", required: true, label: "Full Name" },
81
+ { key: "email", type: "text", required: true, label: "Email" },
82
+ { key: "message", type: "textarea", required: true, label: "Message" },
83
+ ],
84
+ allowed_statuses: ["pending", "in_progress", "resolved", "closed"],
85
+ },
86
+ },
87
+ {
88
+ resolve: "customer-registration",
89
+ options: {
90
+ storefrontUrl: process.env.STOREFRONT_URL || "http://localhost:8000",
91
+ registration: { identifier: "both", require_verification: true },
92
+ login: { identifier: "both" },
93
+ },
94
+ },
95
+ ],
96
+ modules: {
97
+ [Modules.AUTH]: {
98
+ resolve: "@medusajs/medusa/auth",
99
+ dependencies: [Modules.CACHE, ContainerRegistrationKeys.LOGGER],
100
+ options: {
101
+ providers: [
102
+ { resolve: "@medusajs/medusa/auth-emailpass", id: "emailpass" },
103
+ { resolve: "customer-registration/providers/phonepass", id: "phonepass" },
104
+ ...(process.env.GOOGLE_CLIENT_ID
105
+ ? [
106
+ {
107
+ resolve: "@medusajs/auth-google",
108
+ id: "google",
109
+ options: {
110
+ clientId: process.env.GOOGLE_CLIENT_ID,
111
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET,
112
+ },
113
+ },
114
+ ]
115
+ : []),
116
+ ],
117
+ },
118
+ },
119
+ [Modules.FULFILLMENT]: {
120
+ resolve: "@medusajs/medusa/fulfillment",
121
+ options: {
122
+ providers: [{ resolve: "@medusajs/medusa/fulfillment-manual", id: "manual" }],
123
+ },
124
+ },
125
+ file: {
126
+ resolve: "@medusajs/medusa/file",
127
+ options: {
128
+ providers: [
129
+ {
130
+ resolve: "@medusajs/medusa/file-local",
131
+ id: "local",
132
+ options: {
133
+ upload_dir: "static",
134
+ backend_url: `${process.env.MEDUSA_BACKEND_URL || "http://localhost:9000"}/static`,
135
+ },
136
+ },
137
+ ],
138
+ },
139
+ },
140
+ },
141
+ })
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Regenerate config/homepage-config.defaults.json from config/homepage-config.json.
4
+ * Run after editing the schema structure in the backend.
5
+ */
6
+ import { readFileSync, writeFileSync } from "fs"
7
+ import { join, dirname } from "path"
8
+ import { fileURLToPath } from "url"
9
+ import { createRequire } from "module"
10
+
11
+ const __dirname = dirname(fileURLToPath(import.meta.url))
12
+ const backendRoot = join(__dirname, "..")
13
+ const require = createRequire(import.meta.url)
14
+ const { buildHomepageConfigDefaults } = require("./build-homepage-defaults.cjs")
15
+
16
+ const schemaPath = join(backendRoot, "config/homepage-config.json")
17
+ const schema = JSON.parse(readFileSync(schemaPath, "utf8"))
18
+ const defaults = buildHomepageConfigDefaults(schema)
19
+
20
+ writeFileSync(
21
+ join(backendRoot, "config/homepage-config.defaults.json"),
22
+ `${JSON.stringify(defaults, null, 2)}\n`
23
+ )
24
+
25
+ console.log("Wrote config/homepage-config.defaults.json")
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Build initial homepage-config values from schema structure defaultValue fields.
3
+ * Copied into each scaffolded backend at scripts/build-homepage-defaults.cjs
4
+ */
5
+
6
+ function buildDefaultsFromStructure(fields) {
7
+ const result = {}
8
+ for (const field of fields) {
9
+ const value = buildDefaultForField(field)
10
+ if (value !== undefined) {
11
+ result[field.id] = value
12
+ }
13
+ }
14
+ return result
15
+ }
16
+
17
+ function buildDefaultForField(field) {
18
+ if (field.defaultValue !== undefined) {
19
+ return field.defaultValue
20
+ }
21
+
22
+ if (field.type === "object" && field.children?.length) {
23
+ const nested = buildDefaultsFromStructure(field.children)
24
+ return Object.keys(nested).length > 0 ? nested : undefined
25
+ }
26
+
27
+ if (field.type === "array" && field.children?.length) {
28
+ const [itemSchema] = field.children
29
+ if (itemSchema?.type === "object" && itemSchema.children?.length) {
30
+ const itemDefaults = buildDefaultsFromStructure(itemSchema.children)
31
+ if (Object.keys(itemDefaults).length > 0) {
32
+ return [{ [itemSchema.id]: itemDefaults }]
33
+ }
34
+ }
35
+ return undefined
36
+ }
37
+
38
+ return undefined
39
+ }
40
+
41
+ function buildHomepageConfigDefaults(configSchema) {
42
+ if (!configSchema?.structure?.length) return {}
43
+ return buildDefaultsFromStructure(configSchema.structure)
44
+ }
45
+
46
+ module.exports = {
47
+ buildDefaultsFromStructure,
48
+ buildDefaultForField,
49
+ buildHomepageConfigDefaults,
50
+ }
@@ -0,0 +1,27 @@
1
+ /** Minimal product metadata for storefront filters and PDP specs */
2
+ export const PRODUCT_METADATA_DESCRIPTORS = [
3
+ {
4
+ key: "style",
5
+ label: "Style",
6
+ type: "select",
7
+ filterable: true,
8
+ options: [
9
+ { value: "casual", label: "Casual" },
10
+ { value: "formal", label: "Formal" },
11
+ { value: "festive", label: "Festive" },
12
+ ],
13
+ },
14
+ {
15
+ key: "fabric",
16
+ label: "Fabric",
17
+ type: "select",
18
+ filterable: true,
19
+ options: [
20
+ { value: "cotton", label: "Cotton" },
21
+ { value: "silk", label: "Silk" },
22
+ { value: "linen", label: "Linen" },
23
+ ],
24
+ },
25
+ { key: "size_fit", label: "Size & Fit", type: "textarea" },
26
+ { key: "material_care", label: "Material & Care", type: "textarea" },
27
+ ]