create-stackr 0.2.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 (274) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +642 -0
  3. package/bin/cli.js +12 -0
  4. package/dist/cli.d.ts +3 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +113 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/config/dependencies.d.ts +82 -0
  9. package/dist/config/dependencies.d.ts.map +1 -0
  10. package/dist/config/dependencies.js +82 -0
  11. package/dist/config/dependencies.js.map +1 -0
  12. package/dist/config/presets.d.ts +3 -0
  13. package/dist/config/presets.d.ts.map +1 -0
  14. package/dist/config/presets.js +174 -0
  15. package/dist/config/presets.js.map +1 -0
  16. package/dist/generators/index.d.ts +40 -0
  17. package/dist/generators/index.d.ts.map +1 -0
  18. package/dist/generators/index.js +130 -0
  19. package/dist/generators/index.js.map +1 -0
  20. package/dist/generators/onboarding.d.ts +8 -0
  21. package/dist/generators/onboarding.d.ts.map +1 -0
  22. package/dist/generators/onboarding.js +141 -0
  23. package/dist/generators/onboarding.js.map +1 -0
  24. package/dist/index.d.ts +3 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +65 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/prompts/features.d.ts +14 -0
  29. package/dist/prompts/features.d.ts.map +1 -0
  30. package/dist/prompts/features.js +96 -0
  31. package/dist/prompts/features.js.map +1 -0
  32. package/dist/prompts/index.d.ts +3 -0
  33. package/dist/prompts/index.d.ts.map +1 -0
  34. package/dist/prompts/index.js +93 -0
  35. package/dist/prompts/index.js.map +1 -0
  36. package/dist/prompts/onboarding.d.ts +6 -0
  37. package/dist/prompts/onboarding.d.ts.map +1 -0
  38. package/dist/prompts/onboarding.js +37 -0
  39. package/dist/prompts/onboarding.js.map +1 -0
  40. package/dist/prompts/orm.d.ts +3 -0
  41. package/dist/prompts/orm.d.ts.map +1 -0
  42. package/dist/prompts/orm.js +23 -0
  43. package/dist/prompts/orm.js.map +1 -0
  44. package/dist/prompts/packageManager.d.ts +2 -0
  45. package/dist/prompts/packageManager.d.ts.map +1 -0
  46. package/dist/prompts/packageManager.js +18 -0
  47. package/dist/prompts/packageManager.js.map +1 -0
  48. package/dist/prompts/platform.d.ts +3 -0
  49. package/dist/prompts/platform.d.ts.map +1 -0
  50. package/dist/prompts/platform.js +21 -0
  51. package/dist/prompts/platform.js.map +1 -0
  52. package/dist/prompts/preset.d.ts +4 -0
  53. package/dist/prompts/preset.d.ts.map +1 -0
  54. package/dist/prompts/preset.js +165 -0
  55. package/dist/prompts/preset.js.map +1 -0
  56. package/dist/prompts/project.d.ts +2 -0
  57. package/dist/prompts/project.d.ts.map +1 -0
  58. package/dist/prompts/project.js +27 -0
  59. package/dist/prompts/project.js.map +1 -0
  60. package/dist/prompts/sdks.d.ts +2 -0
  61. package/dist/prompts/sdks.d.ts.map +1 -0
  62. package/dist/prompts/sdks.js +46 -0
  63. package/dist/prompts/sdks.js.map +1 -0
  64. package/dist/types/index.d.ts +77 -0
  65. package/dist/types/index.d.ts.map +1 -0
  66. package/dist/types/index.js +25 -0
  67. package/dist/types/index.js.map +1 -0
  68. package/dist/utils/cleanup.d.ts +5 -0
  69. package/dist/utils/cleanup.d.ts.map +1 -0
  70. package/dist/utils/cleanup.js +38 -0
  71. package/dist/utils/cleanup.js.map +1 -0
  72. package/dist/utils/copy.d.ts +10 -0
  73. package/dist/utils/copy.d.ts.map +1 -0
  74. package/dist/utils/copy.js +53 -0
  75. package/dist/utils/copy.js.map +1 -0
  76. package/dist/utils/errors.d.ts +33 -0
  77. package/dist/utils/errors.d.ts.map +1 -0
  78. package/dist/utils/errors.js +136 -0
  79. package/dist/utils/errors.js.map +1 -0
  80. package/dist/utils/git.d.ts +5 -0
  81. package/dist/utils/git.d.ts.map +1 -0
  82. package/dist/utils/git.js +33 -0
  83. package/dist/utils/git.js.map +1 -0
  84. package/dist/utils/logger.d.ts +9 -0
  85. package/dist/utils/logger.d.ts.map +1 -0
  86. package/dist/utils/logger.js +22 -0
  87. package/dist/utils/logger.js.map +1 -0
  88. package/dist/utils/package.d.ts +16 -0
  89. package/dist/utils/package.d.ts.map +1 -0
  90. package/dist/utils/package.js +86 -0
  91. package/dist/utils/package.js.map +1 -0
  92. package/dist/utils/system-validation.d.ts +9 -0
  93. package/dist/utils/system-validation.d.ts.map +1 -0
  94. package/dist/utils/system-validation.js +31 -0
  95. package/dist/utils/system-validation.js.map +1 -0
  96. package/dist/utils/template.d.ts +20 -0
  97. package/dist/utils/template.d.ts.map +1 -0
  98. package/dist/utils/template.js +234 -0
  99. package/dist/utils/template.js.map +1 -0
  100. package/dist/utils/validation.d.ts +8 -0
  101. package/dist/utils/validation.d.ts.map +1 -0
  102. package/dist/utils/validation.js +94 -0
  103. package/dist/utils/validation.js.map +1 -0
  104. package/package.json +96 -0
  105. package/templates/base/backend/.dockerignore.ejs +62 -0
  106. package/templates/base/backend/.env.example.ejs +116 -0
  107. package/templates/base/backend/Dockerfile.ejs +142 -0
  108. package/templates/base/backend/controllers/event-queue/index.ts +20 -0
  109. package/templates/base/backend/controllers/event-queue/workers/user.ts +39 -0
  110. package/templates/base/backend/controllers/rest-api/index.ts +48 -0
  111. package/templates/base/backend/controllers/rest-api/plugins/auth.ts +152 -0
  112. package/templates/base/backend/controllers/rest-api/plugins/config.ts +64 -0
  113. package/templates/base/backend/controllers/rest-api/plugins/error-handler.ts +118 -0
  114. package/templates/base/backend/controllers/rest-api/routes/auth.ts.ejs +180 -0
  115. package/templates/base/backend/controllers/rest-api/routes/device-sessions.ts +197 -0
  116. package/templates/base/backend/controllers/rest-api/routes/oauth-web.ts.ejs +375 -0
  117. package/templates/base/backend/controllers/rest-api/server.ts.ejs +87 -0
  118. package/templates/base/backend/domain/device-session/repository.drizzle.ts +209 -0
  119. package/templates/base/backend/domain/device-session/repository.prisma.ts +248 -0
  120. package/templates/base/backend/domain/device-session/schema.ts +72 -0
  121. package/templates/base/backend/domain/session/repository.drizzle.ts +72 -0
  122. package/templates/base/backend/domain/session/repository.prisma.ts +72 -0
  123. package/templates/base/backend/domain/session/schema.ts +29 -0
  124. package/templates/base/backend/domain/user/repository.drizzle.ts +127 -0
  125. package/templates/base/backend/domain/user/repository.prisma.ts +115 -0
  126. package/templates/base/backend/domain/user/schema.ts +14 -0
  127. package/templates/base/backend/drizzle/schema.drizzle.ts +111 -0
  128. package/templates/base/backend/drizzle.config.drizzle.ts +13 -0
  129. package/templates/base/backend/lib/auth.drizzle.ts.ejs +104 -0
  130. package/templates/base/backend/lib/auth.prisma.ts.ejs +97 -0
  131. package/templates/base/backend/lib/constants.ts.ejs +29 -0
  132. package/templates/base/backend/package.json.ejs +50 -0
  133. package/templates/base/backend/prisma/schema.prisma.ejs +102 -0
  134. package/templates/base/backend/prisma.config.prisma.ts +12 -0
  135. package/templates/base/backend/tsconfig.json +39 -0
  136. package/templates/base/backend/utils/db.drizzle.ts +41 -0
  137. package/templates/base/backend/utils/db.prisma.ts +51 -0
  138. package/templates/base/backend/utils/email.ts.ejs +35 -0
  139. package/templates/base/backend/utils/errors.ts +348 -0
  140. package/templates/base/backend/utils/redis.ts.ejs +279 -0
  141. package/templates/base/mobile/.env.example.ejs +35 -0
  142. package/templates/base/mobile/.gitignore.ejs +167 -0
  143. package/templates/base/mobile/app/+not-found.tsx +85 -0
  144. package/templates/base/mobile/app/_layout.tsx.ejs +71 -0
  145. package/templates/base/mobile/app.json.ejs +88 -0
  146. package/templates/base/mobile/assets/images/adaptive-icon.png +0 -0
  147. package/templates/base/mobile/assets/images/favicon.png +0 -0
  148. package/templates/base/mobile/assets/images/icon.png +0 -0
  149. package/templates/base/mobile/assets/images/onboarding_page_1.png +0 -0
  150. package/templates/base/mobile/assets/images/onboarding_page_2.png +0 -0
  151. package/templates/base/mobile/assets/images/onboarding_page_3.png +0 -0
  152. package/templates/base/mobile/assets/images/paywall_image.png +0 -0
  153. package/templates/base/mobile/assets/images/splash.png +0 -0
  154. package/templates/base/mobile/eas.json.ejs +49 -0
  155. package/templates/base/mobile/metro.config.js +9 -0
  156. package/templates/base/mobile/package.json.ejs +53 -0
  157. package/templates/base/mobile/src/components/ui/Button.tsx +131 -0
  158. package/templates/base/mobile/src/components/ui/Card.tsx +68 -0
  159. package/templates/base/mobile/src/components/ui/IconSymbol.tsx +90 -0
  160. package/templates/base/mobile/src/components/ui/Input.tsx +142 -0
  161. package/templates/base/mobile/src/components/ui/LoadingSpinner.tsx +98 -0
  162. package/templates/base/mobile/src/components/ui/OnboardingLayout.tsx +356 -0
  163. package/templates/base/mobile/src/components/ui/PaywallLayout.tsx +311 -0
  164. package/templates/base/mobile/src/components/ui/Skeleton.tsx +58 -0
  165. package/templates/base/mobile/src/components/ui/index.ts +6 -0
  166. package/templates/base/mobile/src/constants/Theme.ts +163 -0
  167. package/templates/base/mobile/src/context/ThemeContext.tsx +157 -0
  168. package/templates/base/mobile/src/lib/auth-client.ts.ejs +51 -0
  169. package/templates/base/mobile/src/services/api.ts.ejs +71 -0
  170. package/templates/base/mobile/src/services/errorService.ts +179 -0
  171. package/templates/base/mobile/src/services/sdkInitializer.ts.ejs +36 -0
  172. package/templates/base/mobile/src/store/index.ts.ejs +18 -0
  173. package/templates/base/mobile/src/store/ui.store.ts +100 -0
  174. package/templates/base/mobile/src/utils/formatters.ts +105 -0
  175. package/templates/base/mobile/src/utils/logger.ts +73 -0
  176. package/templates/base/mobile/src/utils/responsive.ts +234 -0
  177. package/templates/base/mobile/tsconfig.json +32 -0
  178. package/templates/base/web/.env.example.ejs +26 -0
  179. package/templates/base/web/components.json +22 -0
  180. package/templates/base/web/eslint.config.mjs +18 -0
  181. package/templates/base/web/next.config.ts +7 -0
  182. package/templates/base/web/package.json.ejs +35 -0
  183. package/templates/base/web/postcss.config.mjs +7 -0
  184. package/templates/base/web/public/.gitkeep +0 -0
  185. package/templates/base/web/public/file.svg +1 -0
  186. package/templates/base/web/public/globe.svg +1 -0
  187. package/templates/base/web/public/next.svg +1 -0
  188. package/templates/base/web/public/vercel.svg +1 -0
  189. package/templates/base/web/public/window.svg +1 -0
  190. package/templates/base/web/src/app/favicon.ico +0 -0
  191. package/templates/base/web/src/app/globals.css +152 -0
  192. package/templates/base/web/src/app/layout.tsx.ejs +54 -0
  193. package/templates/base/web/src/app/page.tsx.ejs +92 -0
  194. package/templates/base/web/src/components/auth/auth-hydrator.tsx.ejs +19 -0
  195. package/templates/base/web/src/components/auth/protected-route.tsx.ejs +109 -0
  196. package/templates/base/web/src/components/providers/device-session-setup.tsx.ejs +56 -0
  197. package/templates/base/web/src/components/providers/theme-provider.tsx +17 -0
  198. package/templates/base/web/src/components/theme-toggle.tsx +34 -0
  199. package/templates/base/web/src/components/ui/button.tsx +62 -0
  200. package/templates/base/web/src/components/ui/card.tsx +92 -0
  201. package/templates/base/web/src/components/ui/input.tsx +21 -0
  202. package/templates/base/web/src/components/ui/label.tsx +24 -0
  203. package/templates/base/web/src/components/ui/skeleton.tsx +13 -0
  204. package/templates/base/web/src/components/ui/spinner.tsx +20 -0
  205. package/templates/base/web/src/hooks/use-device-session.ts.ejs +40 -0
  206. package/templates/base/web/src/hooks/use-session.ts.ejs +56 -0
  207. package/templates/base/web/src/lib/auth/actions.ts.ejs +334 -0
  208. package/templates/base/web/src/lib/auth/config.ts.ejs +65 -0
  209. package/templates/base/web/src/lib/auth/cookies.ts.ejs +74 -0
  210. package/templates/base/web/src/lib/auth/index.ts.ejs +40 -0
  211. package/templates/base/web/src/lib/auth/oauth.ts.ejs +72 -0
  212. package/templates/base/web/src/lib/auth/pkce.ts.ejs +48 -0
  213. package/templates/base/web/src/lib/auth/sessions.ts.ejs +135 -0
  214. package/templates/base/web/src/lib/auth/user-agent.ts.ejs +47 -0
  215. package/templates/base/web/src/lib/device/actions.ts.ejs +148 -0
  216. package/templates/base/web/src/lib/device/id.ts.ejs +74 -0
  217. package/templates/base/web/src/lib/utils.ts +6 -0
  218. package/templates/base/web/src/proxy.ts.ejs +66 -0
  219. package/templates/base/web/src/store/auth.store.ts.ejs +89 -0
  220. package/templates/base/web/src/store/deviceSession.store.ts.ejs +141 -0
  221. package/templates/base/web/tsconfig.json +34 -0
  222. package/templates/features/mobile/auth/app/(auth)/_layout.tsx +16 -0
  223. package/templates/features/mobile/auth/app/(auth)/login.tsx +86 -0
  224. package/templates/features/mobile/auth/app/(auth)/register.tsx +86 -0
  225. package/templates/features/mobile/auth/components/auth/LoginForm.tsx.ejs +349 -0
  226. package/templates/features/mobile/auth/components/auth/RegisterForm.tsx.ejs +407 -0
  227. package/templates/features/mobile/auth/components/auth/index.ts +2 -0
  228. package/templates/features/mobile/auth/hooks/index.ts.ejs +1 -0
  229. package/templates/features/mobile/auth/hooks/useAuth.ts.ejs +367 -0
  230. package/templates/features/mobile/auth/services/deviceSession.ts +370 -0
  231. package/templates/features/mobile/auth/store/deviceSession.store.ts +326 -0
  232. package/templates/features/mobile/onboarding/app/(onboarding)/_layout.tsx.ejs +11 -0
  233. package/templates/features/mobile/onboarding/app/(onboarding)/page-1.tsx.ejs +52 -0
  234. package/templates/features/mobile/onboarding/app/(onboarding)/page-2.tsx.ejs +52 -0
  235. package/templates/features/mobile/onboarding/app/(onboarding)/page-3.tsx.ejs +60 -0
  236. package/templates/features/mobile/paywall/app/paywall.tsx +550 -0
  237. package/templates/features/mobile/tabs/app/(tabs)/_layout.tsx +26 -0
  238. package/templates/features/mobile/tabs/app/(tabs)/index.tsx +565 -0
  239. package/templates/features/web/.gitkeep +0 -0
  240. package/templates/features/web/auth/app/(app)/dashboard/dashboard-client.tsx.ejs +166 -0
  241. package/templates/features/web/auth/app/(app)/dashboard/page.tsx.ejs +24 -0
  242. package/templates/features/web/auth/app/(app)/layout.tsx.ejs +43 -0
  243. package/templates/features/web/auth/app/(app)/settings/sessions/page.tsx.ejs +29 -0
  244. package/templates/features/web/auth/app/(app)/settings/sessions/sessions-client.tsx.ejs +77 -0
  245. package/templates/features/web/auth/app/(auth)/forgot-password/page.tsx.ejs +127 -0
  246. package/templates/features/web/auth/app/(auth)/layout.tsx.ejs +32 -0
  247. package/templates/features/web/auth/app/(auth)/login/page.tsx.ejs +35 -0
  248. package/templates/features/web/auth/app/(auth)/register/page.tsx.ejs +19 -0
  249. package/templates/features/web/auth/app/(auth)/reset-password/page.tsx.ejs +40 -0
  250. package/templates/features/web/auth/app/(auth)/verify-email/page.tsx.ejs +198 -0
  251. package/templates/features/web/auth/app/auth/callback/route.ts.ejs +152 -0
  252. package/templates/features/web/auth/components/auth/login-form.tsx.ejs +100 -0
  253. package/templates/features/web/auth/components/auth/oauth-buttons.tsx.ejs +126 -0
  254. package/templates/features/web/auth/components/auth/password-reset-form.tsx.ejs +103 -0
  255. package/templates/features/web/auth/components/auth/register-form.tsx.ejs +139 -0
  256. package/templates/features/web/auth/components/settings/session-card.tsx.ejs +132 -0
  257. package/templates/integrations/mobile/adjust/services/adjustService.ts.ejs +163 -0
  258. package/templates/integrations/mobile/adjust/store/adjust.store.ts +243 -0
  259. package/templates/integrations/mobile/att/services/attService.ts +84 -0
  260. package/templates/integrations/mobile/att/services/trackingPermissions.ts +208 -0
  261. package/templates/integrations/mobile/att/store/att.store.ts +162 -0
  262. package/templates/integrations/mobile/revenuecat/services/revenuecatService.ts.ejs +174 -0
  263. package/templates/integrations/mobile/revenuecat/store/revenuecat.store.ts +286 -0
  264. package/templates/integrations/mobile/scate/services/scateService.ts.ejs +85 -0
  265. package/templates/integrations/mobile/scate/store/scate.store.ts +125 -0
  266. package/templates/integrations/web/.gitkeep +0 -0
  267. package/templates/shared/.env.example.ejs +21 -0
  268. package/templates/shared/.gitignore.ejs +145 -0
  269. package/templates/shared/README.md.ejs +134 -0
  270. package/templates/shared/docker-compose.prod.yml.ejs +120 -0
  271. package/templates/shared/docker-compose.yml.ejs +129 -0
  272. package/templates/shared/scripts/docker-dev.sh.ejs +395 -0
  273. package/templates/shared/scripts/docker-prod.sh.ejs +542 -0
  274. package/templates/shared/scripts/setup.sh.ejs +979 -0
@@ -0,0 +1,979 @@
1
+ #!/bin/bash
2
+
3
+ # Full-Stack Auth Boilerplate Setup Script
4
+ # This script sets up the development environment
5
+
6
+ set -e # Exit on any error
7
+
8
+ echo "🚀 Setting up Full-Stack Auth Boilerplate..."
9
+ echo "================================================"
10
+
11
+ # Colors for output
12
+ RED='\033[0;31m'
13
+ GREEN='\033[0;32m'
14
+ YELLOW='\033[1;33m'
15
+ BLUE='\033[0;34m'
16
+ NC='\033[0m' # No Color
17
+
18
+ # Function to print colored output
19
+ print_status() {
20
+ echo -e "${GREEN}✓${NC} $1"
21
+ }
22
+
23
+ print_info() {
24
+ echo -e "${BLUE}ℹ${NC} $1"
25
+ }
26
+
27
+ print_warning() {
28
+ echo -e "${YELLOW}⚠${NC} $1"
29
+ }
30
+
31
+ print_error() {
32
+ echo -e "${RED}✗${NC} $1"
33
+ }
34
+
35
+ # =============================================================================
36
+ # Configuration Functions
37
+ # =============================================================================
38
+
39
+ # Generate secure random password
40
+ generate_password() {
41
+ local length=${1:-16}
42
+ # Use openssl for secure random password generation
43
+ if command -v openssl &> /dev/null; then
44
+ openssl rand -base64 32 | tr -d "=+/" | cut -c1-${length}
45
+ else
46
+ # Fallback to /dev/urandom if openssl is not available
47
+ LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c${length}
48
+ fi
49
+ }
50
+
51
+ # Generate JWT secret (longer and more secure)
52
+ generate_jwt_secret() {
53
+ if command -v openssl &> /dev/null; then
54
+ openssl rand -hex 32
55
+ else
56
+ LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c64
57
+ fi
58
+ }
59
+
60
+ # Prompt for input with default value
61
+ prompt_with_default() {
62
+ local prompt="$1"
63
+ local default="$2"
64
+ local secure="$3" # If set to "secure", hide input
65
+ local user_input
66
+
67
+ if [ "$secure" = "secure" ]; then
68
+ printf "${BLUE}${prompt}${NC} [${YELLOW}${default}${NC}]: "
69
+ read -s user_input
70
+ echo # Add newline since -s doesn't echo one
71
+ else
72
+ printf "${BLUE}${prompt}${NC} [${YELLOW}${default}${NC}]: "
73
+ read user_input
74
+ fi
75
+
76
+ # Return default if input is empty
77
+ echo "${user_input:-$default}"
78
+ }
79
+
80
+ # Validate password strength (basic check)
81
+ validate_password() {
82
+ local password="$1"
83
+ local min_length=8
84
+
85
+ if [ ${#password} -lt ${min_length} ]; then
86
+ print_warning "Password should be at least ${min_length} characters long"
87
+ return 1
88
+ fi
89
+
90
+ return 0
91
+ }
92
+
93
+ # Display configuration summary
94
+ display_config_summary() {
95
+ echo ""
96
+ echo "📋 Configuration Summary:"
97
+ echo "=========================="
98
+ echo "Database User: $DB_CONFIG_USER"
99
+ echo "Database Name: $DB_CONFIG_NAME"
100
+ <% if (backend.eventQueue) { %>
101
+ echo "Redis Password: $REDIS_CONFIG_PASSWORD"
102
+ <% } %>
103
+ echo "JWT Secret: [Hidden - 64 characters]"
104
+ echo ""
105
+ }
106
+
107
+ # Collect all configuration from user
108
+ collect_configuration() {
109
+ print_info "Let's configure your credentials securely..."
110
+ echo ""
111
+
112
+ # Generate secure defaults
113
+ local default_db_password=$(generate_password 12)
114
+ <% if (backend.eventQueue) { %>
115
+ local default_redis_password=$(generate_password 16)
116
+ <% } %>
117
+ local default_jwt_secret=$(generate_jwt_secret)
118
+ <% if (features.authentication.enabled) { %>
119
+ local default_auth_secret=$(generate_jwt_secret)
120
+ <% } %>
121
+
122
+ # Database configuration
123
+ echo "🗄️ Database Configuration:"
124
+ DB_CONFIG_USER=$(prompt_with_default "Database username" "postgres")
125
+ DB_CONFIG_PASSWORD=$(prompt_with_default "Database password" "$default_db_password" "secure")
126
+ DB_CONFIG_NAME=$(prompt_with_default "Database name" "auth_boilerplate")
127
+
128
+ # Validate database password
129
+ while ! validate_password "$DB_CONFIG_PASSWORD"; do
130
+ DB_CONFIG_PASSWORD=$(prompt_with_default "Please enter a stronger database password" "$default_db_password" "secure")
131
+ done
132
+
133
+ <% if (backend.eventQueue) { %>
134
+ echo ""
135
+ echo "🔄 Redis Configuration:"
136
+ REDIS_CONFIG_PASSWORD=$(prompt_with_default "Redis password" "$default_redis_password" "secure")
137
+
138
+ # Validate Redis password
139
+ while ! validate_password "$REDIS_CONFIG_PASSWORD"; do
140
+ REDIS_CONFIG_PASSWORD=$(prompt_with_default "Please enter a stronger Redis password" "$default_redis_password" "secure")
141
+ done
142
+
143
+ <% } %>
144
+ echo ""
145
+ echo "🔐 Security Configuration:"
146
+ JWT_CONFIG_SECRET=$(prompt_with_default "JWT secret (leave empty for secure auto-generated)" "$default_jwt_secret")
147
+ <% if (features.authentication.enabled) { %>
148
+ AUTH_CONFIG_SECRET=$(prompt_with_default "BetterAuth secret (leave empty for secure auto-generated)" "$default_auth_secret")
149
+ <% } %>
150
+
151
+ # Global variables for use in other functions
152
+ <% if (backend.eventQueue && features.authentication.enabled) { %>
153
+ export DB_CONFIG_USER DB_CONFIG_PASSWORD DB_CONFIG_NAME REDIS_CONFIG_PASSWORD JWT_CONFIG_SECRET AUTH_CONFIG_SECRET
154
+ <% } else if (backend.eventQueue) { %>
155
+ export DB_CONFIG_USER DB_CONFIG_PASSWORD DB_CONFIG_NAME REDIS_CONFIG_PASSWORD JWT_CONFIG_SECRET
156
+ <% } else if (features.authentication.enabled) { %>
157
+ export DB_CONFIG_USER DB_CONFIG_PASSWORD DB_CONFIG_NAME JWT_CONFIG_SECRET AUTH_CONFIG_SECRET
158
+ <% } else { %>
159
+ export DB_CONFIG_USER DB_CONFIG_PASSWORD DB_CONFIG_NAME JWT_CONFIG_SECRET
160
+ <% } %>
161
+
162
+ display_config_summary
163
+
164
+ # Confirm configuration
165
+ echo ""
166
+ read -p "Proceed with this configuration? (y/n): " -n 1 -r
167
+ echo
168
+ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
169
+ print_info "Configuration cancelled. Re-run the script to try again."
170
+ exit 0
171
+ fi
172
+ }
173
+
174
+ # Get the project directory name for volume prefix
175
+ get_project_name() {
176
+ basename "$(pwd)"
177
+ }
178
+
179
+ # Check if Docker volumes exist for this project
180
+ has_existing_volumes() {
181
+ local project_name=$(get_project_name)
182
+ local dev_volume="${project_name}_postgres_data"
183
+ local prod_volume="${project_name}_postgres_prod_data"
184
+
185
+ # Check if docker is running
186
+ if ! docker info > /dev/null 2>&1; then
187
+ return 1
188
+ fi
189
+
190
+ # Check if any volumes exist
191
+ if docker volume ls --format "{{.Name}}" 2>/dev/null | grep -q "^${dev_volume}$" || \
192
+ docker volume ls --format "{{.Name}}" 2>/dev/null | grep -q "^${prod_volume}$"; then
193
+ return 0
194
+ fi
195
+
196
+ return 1
197
+ }
198
+
199
+ # List existing volumes for this project
200
+ list_existing_volumes() {
201
+ local project_name=$(get_project_name)
202
+ docker volume ls --format "{{.Name}}" 2>/dev/null | grep "^${project_name}_" || echo "None"
203
+ }
204
+
205
+ # Remove all Docker volumes for this project
206
+ remove_project_volumes() {
207
+ local project_name=$(get_project_name)
208
+
209
+ print_warning "This will DELETE all Docker volumes and their data!"
210
+ echo ""
211
+ print_info "Volumes to be removed:"
212
+ list_existing_volumes | sed 's/^/ /'
213
+ echo ""
214
+
215
+ read -p "Are you absolutely sure? Type 'DELETE' to confirm: " -r
216
+ echo
217
+
218
+ if [ "$REPLY" = "DELETE" ]; then
219
+ print_info "Stopping any running containers..."
220
+ docker-compose down 2>/dev/null || true
221
+ docker-compose -f docker-compose.prod.yml down 2>/dev/null || true
222
+
223
+ print_info "Removing volumes..."
224
+ docker volume ls --format "{{.Name}}" 2>/dev/null | grep "^${project_name}_" | while read volume; do
225
+ docker volume rm "$volume" 2>/dev/null && print_status "Removed: $volume" || print_warning "Could not remove: $volume"
226
+ done
227
+
228
+ print_status "Volume cleanup complete"
229
+ return 0
230
+ else
231
+ print_info "Volume removal cancelled"
232
+ return 1
233
+ fi
234
+ }
235
+
236
+ # Check if existing configuration is present (env files OR volumes)
237
+ has_existing_configuration() {
238
+ local has_env_files=false
239
+ local has_volumes=false
240
+
241
+ # Check if both env files exist
242
+ if [ -f "backend/.env" ] && [ -f ".env" ]; then
243
+ # Check if backend/.env contains configured DATABASE_URL (not placeholder)
244
+ if ! grep -q "postgresql://username:password@" backend/.env 2>/dev/null; then
245
+ # Check if root .env contains configured credentials (not empty values)
246
+ if grep -q "DB_USER=" .env 2>/dev/null && grep -q "DB_PASSWORD=" .env 2>/dev/null; then
247
+ has_env_files=true
248
+ fi
249
+ fi
250
+ fi
251
+
252
+ # Check if Docker volumes exist
253
+ if has_existing_volumes; then
254
+ has_volumes=true
255
+ fi
256
+
257
+ # Return true if either exists
258
+ if [ "$has_env_files" = true ] || [ "$has_volumes" = true ]; then
259
+ return 0
260
+ fi
261
+
262
+ return 1
263
+ }
264
+
265
+ # Load existing credentials from .env files
266
+ load_existing_credentials() {
267
+ if [ ! -f ".env" ]; then
268
+ print_error "Root .env file not found. Cannot load existing configuration."
269
+ return 1
270
+ fi
271
+
272
+ # Source the root .env file to get variables
273
+ set -a # Export all variables
274
+ source .env 2>/dev/null || {
275
+ print_error "Failed to load existing configuration from .env file."
276
+ return 1
277
+ }
278
+ set +a # Stop auto-exporting
279
+
280
+ # Map to our expected variable names
281
+ DB_CONFIG_USER="${DB_USER:-postgres}"
282
+ DB_CONFIG_PASSWORD="${DB_PASSWORD}"
283
+ DB_CONFIG_NAME="${DB_NAME:-auth_boilerplate}"
284
+ <% if (backend.eventQueue) { %>
285
+ REDIS_CONFIG_PASSWORD="${REDIS_PASSWORD}"
286
+ <% } %>
287
+ JWT_CONFIG_SECRET="${JWT_SECRET}"
288
+
289
+ # Export for use in other functions
290
+ <% if (backend.eventQueue) { %>
291
+ export DB_CONFIG_USER DB_CONFIG_PASSWORD DB_CONFIG_NAME REDIS_CONFIG_PASSWORD JWT_CONFIG_SECRET
292
+ <% } else { %>
293
+ export DB_CONFIG_USER DB_CONFIG_PASSWORD DB_CONFIG_NAME JWT_CONFIG_SECRET
294
+ <% } %>
295
+
296
+ return 0
297
+ }
298
+
299
+ # Display existing configuration summary
300
+ display_existing_config_summary() {
301
+ echo ""
302
+ echo "📋 Existing Configuration Found:"
303
+ echo "================================="
304
+ echo "Database User: $DB_CONFIG_USER"
305
+ echo "Database Name: $DB_CONFIG_NAME"
306
+ echo "Database Password: [Hidden - ${#DB_CONFIG_PASSWORD} characters]"
307
+ <% if (backend.eventQueue) { %>
308
+ echo "Redis Password: [Hidden - ${#REDIS_CONFIG_PASSWORD} characters]"
309
+ <% } %>
310
+ echo "JWT Secret: [Hidden - ${#JWT_CONFIG_SECRET} characters]"
311
+ echo ""
312
+ }
313
+
314
+ # Detect if credentials in .env match what would be in volumes
315
+ # Returns 0 if mismatch detected, 1 if they match or can't determine
316
+ detect_credential_mismatch() {
317
+ # If no volumes exist, no mismatch possible
318
+ if ! has_existing_volumes; then
319
+ return 1
320
+ fi
321
+
322
+ # If no .env files exist, we can't check for mismatch
323
+ if [ ! -f ".env" ]; then
324
+ print_warning "Docker volumes exist but no .env file found"
325
+ print_warning "This suggests volumes may contain different credentials"
326
+ return 0
327
+ fi
328
+
329
+ # Try to test database connection with current credentials
330
+ # This is a simple heuristic - if DB is running and connection fails,
331
+ # credentials likely don't match
332
+ if docker ps --format "{{.Names}}" 2>/dev/null | grep -q "database"; then
333
+ print_info "Testing database connection with current credentials..."
334
+ source .env 2>/dev/null
335
+
336
+ # Try to connect - if it fails, credentials don't match
337
+ if ! docker-compose exec -T database psql -U "${DB_USER}" -d "${DB_NAME}" -c "SELECT 1" > /dev/null 2>&1; then
338
+ return 0 # Mismatch detected
339
+ fi
340
+ fi
341
+
342
+ return 1 # No mismatch or can't determine
343
+ }
344
+
345
+ # Check if Docker is installed
346
+ check_docker() {
347
+ if ! command -v docker &> /dev/null; then
348
+ print_error "Docker is not installed. Please install Docker first."
349
+ print_info "Visit: https://docs.docker.com/get-docker/"
350
+ exit 1
351
+ fi
352
+
353
+ if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then
354
+ print_error "Docker Compose is not installed. Please install Docker Compose first."
355
+ print_info "Visit: https://docs.docker.com/compose/install/"
356
+ exit 1
357
+ fi
358
+
359
+ print_status "Docker and Docker Compose are installed"
360
+ }
361
+
362
+ # Check if Bun is installed (for backend and mobile development)
363
+ check_bun() {
364
+ if ! command -v bun &> /dev/null; then
365
+ print_warning "Bun is not installed. Required for backend and mobile development."
366
+ print_info "Visit: https://bun.sh/"
367
+ else
368
+ BUN_VERSION=$(bun --version)
369
+ print_status "Bun is installed: v$BUN_VERSION"
370
+ fi
371
+ }
372
+
373
+ # Create environment files from configuration
374
+ setup_env_files() {
375
+ # Check if we should skip file creation (when using existing config)
376
+ if has_existing_configuration && [ -f "backend/.env" ] && [ -f ".env" ]; then
377
+ # Check if user chose to skip (option 1) by seeing if files weren't modified recently
378
+ local skip_file_creation=false
379
+
380
+ # If both env files exist and contain non-placeholder values, ask before overwriting
381
+ if grep -q "postgresql://${DB_CONFIG_USER}:${DB_CONFIG_PASSWORD}@" backend/.env 2>/dev/null; then
382
+ skip_file_creation=true
383
+ fi
384
+
385
+ if [ "$skip_file_creation" = true ]; then
386
+ print_status "Using existing environment files (credentials match current configuration)"
387
+ <% if (platforms.includes('web')) { %>
388
+ # Still check if web/.env.local needs to be created
389
+ if [ -d "web" ] && [ ! -f "web/.env.local" ]; then
390
+ print_info "Creating web/.env.local..."
391
+ cat > web/.env.local << EOF
392
+ # =============================================================================
393
+ # Web App Environment Configuration
394
+ # =============================================================================
395
+
396
+ # Public URL of the web app (used for OAuth callbacks)
397
+ NEXT_PUBLIC_APP_URL=http://localhost:3000
398
+
399
+ # Backend API URL (server-side only, used by server actions)
400
+ BACKEND_URL=http://localhost:8080
401
+ EOF
402
+ print_status "Created web/.env.local"
403
+ fi
404
+ <% } %>
405
+ return 0
406
+ fi
407
+ fi
408
+
409
+ print_info "Setting up environment files with your configuration..."
410
+
411
+ # Build DATABASE_URL using configured values
412
+ local database_url="postgresql://${DB_CONFIG_USER}:${DB_CONFIG_PASSWORD}@localhost:5432/${DB_CONFIG_NAME}?schema=public"
413
+
414
+ # Backend environment file - create/overwrite with new config
415
+ print_info "Creating backend/.env with configured values..."
416
+ cat > backend/.env << EOF
417
+ # Environment Configuration
418
+ NODE_ENV=development
419
+ LOG_LEVEL=debug
420
+
421
+ # Server Configuration
422
+ API_HOST=0.0.0.0
423
+ API_PORT=8080
424
+
425
+ # Database Configuration
426
+ DATABASE_URL="${database_url}"
427
+
428
+ # JWT Configuration
429
+ JWT_SECRET=${JWT_CONFIG_SECRET}
430
+ <% if (features.authentication.enabled) { %>
431
+ # =============================================================================
432
+ # BetterAuth Configuration
433
+ # =============================================================================
434
+ # IMPORTANT: Change this in production! Use a secure random string.
435
+ BETTER_AUTH_SECRET=${AUTH_CONFIG_SECRET}
436
+ BETTER_AUTH_URL=http://localhost:8080
437
+
438
+ # Trusted Origins for BetterAuth (includes mobile deep link scheme)
439
+ TRUSTED_ORIGINS=http://localhost:3000,http://localhost:8081,<%= appScheme %>://
440
+ <% if (features.authentication.providers.google) { %>
441
+ # =============================================================================
442
+ # Google OAuth Configuration
443
+ # =============================================================================
444
+ # Get credentials at: https://console.cloud.google.com/
445
+ GOOGLE_WEB_CLIENT_ID=YOUR_GOOGLE_WEB_CLIENT_ID
446
+ GOOGLE_CLIENT_SECRET=YOUR_GOOGLE_CLIENT_SECRET
447
+ <% } %>
448
+ <% if (features.authentication.providers.apple) { %>
449
+ # =============================================================================
450
+ # Apple Sign In Configuration
451
+ # =============================================================================
452
+ # Get credentials at: https://developer.apple.com/
453
+ APPLE_SERVICE_ID=YOUR_APPLE_SERVICE_ID
454
+ APPLE_BUNDLE_ID=com.yourcompany.yourapp
455
+ APPLE_CLIENT_SECRET=YOUR_APPLE_CLIENT_SECRET
456
+ <% } %>
457
+ <% if (features.authentication.providers.github) { %>
458
+ # =============================================================================
459
+ # GitHub OAuth Configuration
460
+ # =============================================================================
461
+ # Get credentials at: https://github.com/settings/developers
462
+ GITHUB_CLIENT_ID=YOUR_GITHUB_CLIENT_ID
463
+ GITHUB_CLIENT_SECRET=YOUR_GITHUB_CLIENT_SECRET
464
+ <% } %>
465
+ <% } %>
466
+ # Redis Configuration
467
+ REDIS_HOST=localhost
468
+ REDIS_PORT=6379
469
+ REDIS_PASSWORD=${REDIS_CONFIG_PASSWORD}
470
+ <% if (backend.eventQueue) { %>
471
+ # BullMQ Configuration (Event Queue)
472
+ BULLMQ_QUEUE_NAME=<%= projectName.toLowerCase().replace(/[^a-z0-9]/g, '_') %>_queue
473
+ BULLMQ_MAX_RETRIES=3
474
+ BULLMQ_BACKOFF_DELAY=5000
475
+ <% } %>
476
+ # CORS Configuration
477
+ ALLOWED_ORIGINS=http://localhost:3000,http://localhost:8081,https://yourdomain.com
478
+
479
+ # Rate Limiting
480
+ RATE_LIMIT_WINDOW_MS=900000
481
+ RATE_LIMIT_MAX_REQUESTS=100
482
+ <% if (features.authentication.emailVerification || features.authentication.passwordReset) { %>
483
+ # =============================================================================
484
+ # Email Configuration (Required for email verification/password reset)
485
+ # =============================================================================
486
+ SMTP_HOST=smtp.gmail.com
487
+ SMTP_PORT=587
488
+ SMTP_USER=your-email@gmail.com
489
+ SMTP_PASS=your-app-password
490
+ EMAIL_FROM=noreply@<%= projectName.toLowerCase().replace(/[^a-z0-9]/g, '') %>.com
491
+ <% } %>
492
+ EOF
493
+ print_status "Created backend/.env with configured values"
494
+
495
+ # Root environment file for Docker - always overwrite with new config
496
+ print_info "Creating root .env with configured values..."
497
+ cat > .env << EOF
498
+ # Database Configuration
499
+ DB_USER=${DB_CONFIG_USER}
500
+ DB_PASSWORD=${DB_CONFIG_PASSWORD}
501
+ DB_NAME=${DB_CONFIG_NAME}
502
+
503
+ # JWT Configuration
504
+ JWT_SECRET=${JWT_CONFIG_SECRET}
505
+ <% if (backend.eventQueue) { %>
506
+
507
+ # Redis Configuration
508
+ REDIS_PASSWORD=${REDIS_CONFIG_PASSWORD}
509
+ <% } %>
510
+
511
+ # Logging
512
+ LOG_LEVEL=debug
513
+ EOF
514
+ print_status "Created root .env file with configured values"
515
+ <% if (platforms.includes('web')) { %>
516
+
517
+ # Web app environment file
518
+ if [ -d "web" ]; then
519
+ print_info "Creating web/.env.local..."
520
+ cat > web/.env.local << EOF
521
+ # =============================================================================
522
+ # Web App Environment Configuration
523
+ # =============================================================================
524
+
525
+ # Public URL of the web app (used for OAuth callbacks)
526
+ NEXT_PUBLIC_APP_URL=http://localhost:3000
527
+
528
+ # Backend API URL (server-side only, used by server actions)
529
+ BACKEND_URL=http://localhost:8080
530
+ EOF
531
+ print_status "Created web/.env.local"
532
+ fi
533
+ <% } %>
534
+ }
535
+
536
+ # Install backend dependencies
537
+ install_backend_deps() {
538
+ if [ -d "backend" ]; then
539
+ print_info "Installing backend dependencies..."
540
+ cd backend
541
+
542
+ if [ -f "package.json" ]; then
543
+ bun install
544
+ print_status "Backend dependencies installed"
545
+ else
546
+ print_warning "No package.json found in backend directory"
547
+ fi
548
+
549
+ cd ..
550
+ else
551
+ print_warning "Backend directory not found"
552
+ fi
553
+ }
554
+
555
+ <% if (platforms.includes('mobile')) { %>
556
+ # Install mobile dependencies
557
+ install_mobile_deps() {
558
+ if [ -d "mobile" ]; then
559
+ print_info "Installing mobile dependencies..."
560
+ cd mobile
561
+
562
+ if [ -f "package.json" ]; then
563
+ bun install
564
+ print_status "Mobile dependencies installed"
565
+ else
566
+ print_warning "No package.json found in mobile directory"
567
+ fi
568
+
569
+ cd ..
570
+ else
571
+ print_warning "Mobile directory not found"
572
+ fi
573
+ }
574
+ <% } %>
575
+ <% if (platforms.includes('web')) { %>
576
+ # Install web dependencies
577
+ install_web_deps() {
578
+ if [ -d "web" ]; then
579
+ print_info "Installing web dependencies..."
580
+ cd web
581
+
582
+ if [ -f "package.json" ]; then
583
+ <%= packageManager %> install
584
+ print_status "Web dependencies installed"
585
+ else
586
+ print_warning "No package.json found in web directory"
587
+ fi
588
+
589
+ cd ..
590
+ else
591
+ print_warning "Web directory not found"
592
+ fi
593
+ }
594
+ <% } %>
595
+
596
+ # Setup database<% if (backend.eventQueue) { %> and Redis<% } %>
597
+ setup_database() {
598
+ # Check if volumes exist but credentials might be different
599
+ if has_existing_volumes; then
600
+ print_warning "⚠️ Existing Docker volumes detected!"
601
+ print_warning "If these volumes contain data with different credentials,"
602
+ print_warning "PostgreSQL will skip initialization and use the existing credentials."
603
+ print_warning "This may cause authentication failures if credentials don't match."
604
+ echo ""
605
+ print_info "Existing volumes:"
606
+ list_existing_volumes | sed 's/^/ /'
607
+ echo ""
608
+ read -p "Continue with database setup? (y/N): " -n 1 -r
609
+ echo
610
+ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
611
+ print_info "Database setup skipped"
612
+ return 0
613
+ fi
614
+ fi
615
+
616
+ print_info "Setting up database<% if (backend.eventQueue) { %> and Redis<% } %> with Docker..."
617
+
618
+ # Start database<% if (backend.eventQueue) { %> and Redis services<% } else { %> service<% } %>
619
+ <% if (backend.eventQueue) { %>
620
+ docker-compose up -d database redis
621
+ <% } else { %>
622
+ docker-compose up -d database
623
+ <% } %>
624
+
625
+ print_info "Waiting for services to be ready..."
626
+ sleep 15
627
+
628
+ # Run database migrations
629
+ if [ -d "backend" ] && [ -f "backend/package.json" ]; then
630
+ print_info "Running database migrations..."
631
+ cd backend
632
+
633
+ <% if (backend.orm === 'prisma') { %>
634
+ # Generate Prisma client
635
+ bun prisma generate
636
+
637
+ # Push schema to database
638
+ bun prisma db push
639
+ <% } else if (backend.orm === 'drizzle') { %>
640
+ # Generate Drizzle migrations
641
+ bun run db:generate
642
+
643
+ # Push schema to database
644
+ bun run db:push
645
+ <% } %>
646
+
647
+ print_status "Database<% if (backend.eventQueue) { %> and Redis<% } %> setup complete"
648
+ cd ..
649
+ else
650
+ print_warning "Cannot run migrations - backend not found or invalid"
651
+ fi
652
+ }
653
+
654
+ # Make scripts executable
655
+ make_scripts_executable() {
656
+ print_info "Making scripts executable..."
657
+ chmod +x scripts/*.sh 2>/dev/null || true
658
+ print_status "Scripts are now executable"
659
+ }
660
+
661
+ # Print next steps
662
+ print_next_steps() {
663
+ echo ""
664
+ echo "🎉 Setup complete! Next steps:"
665
+ echo "================================================"
666
+ echo ""
667
+ echo "📦 Start the development environment:"
668
+ echo " ./scripts/docker-dev.sh"
669
+ echo ""
670
+ echo "🌐 Access your services:"
671
+ echo " Backend API: http://localhost:8080"
672
+ echo " Database: localhost:5432"
673
+ <% if (backend.eventQueue) { %>
674
+ echo " Redis: localhost:6379"
675
+ <% } %>
676
+ echo ""
677
+ <% if (platforms.includes('mobile')) { %>
678
+ echo "📱 For mobile development:"
679
+ echo " cd mobile && <%= packageManager %> start"
680
+ echo ""
681
+ <% } %>
682
+ <% if (platforms.includes('web')) { %>
683
+ echo "🌐 For web development:"
684
+ echo " cd web && <%= packageManager %> run dev"
685
+ echo ""
686
+ <% } %>
687
+ echo "🐳 Docker commands:"
688
+ echo " docker-compose logs -f backend # View backend logs"
689
+ echo " docker-compose down # Stop all services"
690
+ echo ""
691
+ echo "📚 Documentation:"
692
+ echo " - Main README.md for overview"
693
+ echo " - backend/README.md for backend setup"
694
+ echo " - mobile/README.md for mobile setup"
695
+ echo ""
696
+ }
697
+
698
+ # Main execution
699
+ main() {
700
+ echo "Starting setup process..."
701
+ echo ""
702
+
703
+ check_docker
704
+ check_bun
705
+
706
+ # Check for existing configuration
707
+ if has_existing_configuration; then
708
+ # Determine what exists
709
+ local has_env_files=false
710
+ local has_volumes=false
711
+
712
+ if [ -f "backend/.env" ] && [ -f ".env" ]; then
713
+ if ! grep -q "postgresql://username:password@" backend/.env 2>/dev/null; then
714
+ if grep -q "DB_USER=" .env 2>/dev/null && grep -q "DB_PASSWORD=" .env 2>/dev/null; then
715
+ has_env_files=true
716
+ fi
717
+ fi
718
+ fi
719
+
720
+ if has_existing_volumes; then
721
+ has_volumes=true
722
+ fi
723
+
724
+ # Show status
725
+ echo ""
726
+ echo "⚠️ Existing Setup Detected:"
727
+ echo "============================"
728
+ if [ "$has_env_files" = true ]; then
729
+ echo " .env files: FOUND"
730
+ else
731
+ echo " .env files: NOT FOUND"
732
+ fi
733
+
734
+ if [ "$has_volumes" = true ]; then
735
+ echo " Docker volumes: FOUND"
736
+ echo ""
737
+ print_info "Existing volumes:"
738
+ list_existing_volumes | sed 's/^/ /'
739
+ else
740
+ echo " Docker volumes: NOT FOUND"
741
+ fi
742
+ echo ""
743
+
744
+ # Check for credential mismatch
745
+ if [ "$has_env_files" = true ] && [ "$has_volumes" = true ]; then
746
+ if detect_credential_mismatch; then
747
+ print_warning "⚠️ CREDENTIAL MISMATCH DETECTED!"
748
+ print_warning "Your .env files may contain different credentials than your Docker volumes."
749
+ print_warning "This will cause authentication failures!"
750
+ echo ""
751
+ fi
752
+ fi
753
+
754
+ # Load existing credentials if available
755
+ if [ "$has_env_files" = true ]; then
756
+ if load_existing_credentials; then
757
+ display_existing_config_summary
758
+ fi
759
+ fi
760
+
761
+ # Present options based on what exists
762
+ echo "🔧 Setup Options:"
763
+ echo "================="
764
+
765
+ if [ "$has_env_files" = true ] && [ "$has_volumes" = false ]; then
766
+ # Scenario A: Only .env exists, no volumes - safe to reuse or regenerate
767
+ echo "1. Use existing .env configuration"
768
+ echo "2. Reconfigure - Enter new credentials"
769
+ echo "3. Auto-generate - Generate new secure defaults"
770
+ echo "4. Exit setup"
771
+
772
+ elif [ "$has_env_files" = false ] && [ "$has_volumes" = true ]; then
773
+ # Scenario B: Only volumes exist, no .env - need to either reset volumes or exit
774
+ print_warning "Docker volumes exist but no .env files found!"
775
+ print_warning "Cannot proceed without resetting volumes or restoring .env files."
776
+ echo ""
777
+ echo "1. Reset everything - DELETE volumes and create new setup"
778
+ echo "2. Exit (manually restore your .env files, then re-run setup)"
779
+
780
+ else
781
+ # Scenario C: Both exist - most common scenario
782
+ echo "1. Keep everything - Use existing configuration (RECOMMENDED if working)"
783
+ echo "2. Reset everything - DELETE volumes and create new setup"
784
+ echo "3. Reconfigure credentials only (⚠️ DANGER: May cause mismatch)"
785
+ echo "4. Exit setup"
786
+ fi
787
+
788
+ echo ""
789
+ read -p "Choose option: " -n 1 -r
790
+ echo
791
+ echo ""
792
+
793
+ case $REPLY in
794
+ 1)
795
+ if [ "$has_env_files" = false ] && [ "$has_volumes" = true ]; then
796
+ # Scenario B, Option 1: Reset volumes
797
+ print_info "Resetting everything..."
798
+ if remove_project_volumes; then
799
+ print_info "Now generating new credentials..."
800
+ DB_CONFIG_USER="postgres"
801
+ DB_CONFIG_PASSWORD=$(generate_password 12)
802
+ DB_CONFIG_NAME="auth_boilerplate"
803
+ <% if (backend.eventQueue) { %>
804
+ REDIS_CONFIG_PASSWORD=$(generate_password 16)
805
+ <% } %>
806
+ JWT_CONFIG_SECRET=$(generate_jwt_secret)
807
+ <% if (backend.eventQueue) { %>
808
+ export DB_CONFIG_USER DB_CONFIG_PASSWORD DB_CONFIG_NAME REDIS_CONFIG_PASSWORD JWT_CONFIG_SECRET
809
+ <% } else { %>
810
+ export DB_CONFIG_USER DB_CONFIG_PASSWORD DB_CONFIG_NAME JWT_CONFIG_SECRET
811
+ <% } %>
812
+ else
813
+ print_error "Setup cancelled - volumes were not removed"
814
+ exit 1
815
+ fi
816
+ else
817
+ # Scenarios A & C, Option 1: Keep/use existing
818
+ print_status "Using existing configuration"
819
+ if [ "$has_env_files" = false ]; then
820
+ print_error "Cannot proceed - no .env files to use"
821
+ exit 1
822
+ fi
823
+ fi
824
+ ;;
825
+ 2)
826
+ if [ "$has_env_files" = false ] && [ "$has_volumes" = true ]; then
827
+ # Scenario B, Option 2: Exit
828
+ print_info "Setup cancelled. Please restore your .env files."
829
+ exit 0
830
+ elif [ "$has_volumes" = true ]; then
831
+ # Scenario C, Option 2: Reset everything
832
+ print_info "Resetting everything (volumes + credentials)..."
833
+ if remove_project_volumes; then
834
+ print_info "Now generating new credentials..."
835
+ DB_CONFIG_USER="postgres"
836
+ DB_CONFIG_PASSWORD=$(generate_password 12)
837
+ DB_CONFIG_NAME="auth_boilerplate"
838
+ <% if (backend.eventQueue) { %>
839
+ REDIS_CONFIG_PASSWORD=$(generate_password 16)
840
+ <% } %>
841
+ JWT_CONFIG_SECRET=$(generate_jwt_secret)
842
+ <% if (backend.eventQueue) { %>
843
+ export DB_CONFIG_USER DB_CONFIG_PASSWORD DB_CONFIG_NAME REDIS_CONFIG_PASSWORD JWT_CONFIG_SECRET
844
+ <% } else { %>
845
+ export DB_CONFIG_USER DB_CONFIG_PASSWORD DB_CONFIG_NAME JWT_CONFIG_SECRET
846
+ <% } %>
847
+ else
848
+ print_error "Setup cancelled - volumes were not removed"
849
+ exit 1
850
+ fi
851
+ else
852
+ # Scenario A, Option 2: Reconfigure
853
+ print_info "Reconfiguring credentials..."
854
+ collect_configuration
855
+ fi
856
+ ;;
857
+ 3)
858
+ if [ "$has_env_files" = false ] && [ "$has_volumes" = true ]; then
859
+ # Scenario B: No option 3
860
+ print_info "Invalid option. Exiting."
861
+ exit 0
862
+ elif [ "$has_volumes" = true ]; then
863
+ # Scenario C, Option 3: Dangerous reconfigure
864
+ print_warning "⚠️ WARNING: Changing credentials without resetting volumes!"
865
+ print_warning "This WILL cause authentication failures if volumes already exist."
866
+ print_warning "Only proceed if you know what you're doing."
867
+ echo ""
868
+ read -p "Continue anyway? (y/N): " -n 1 -r
869
+ echo
870
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
871
+ print_info "Reconfiguring credentials..."
872
+ collect_configuration
873
+ else
874
+ print_info "Cancelled. Using existing configuration."
875
+ fi
876
+ else
877
+ # Scenario A, Option 3: Auto-generate
878
+ print_info "Generating new secure auto-generated credentials..."
879
+ DB_CONFIG_USER="postgres"
880
+ DB_CONFIG_PASSWORD=$(generate_password 12)
881
+ DB_CONFIG_NAME="auth_boilerplate"
882
+ <% if (backend.eventQueue) { %>
883
+ REDIS_CONFIG_PASSWORD=$(generate_password 16)
884
+ <% } %>
885
+ JWT_CONFIG_SECRET=$(generate_jwt_secret)
886
+ <% if (backend.eventQueue) { %>
887
+ export DB_CONFIG_USER DB_CONFIG_PASSWORD DB_CONFIG_NAME REDIS_CONFIG_PASSWORD JWT_CONFIG_SECRET
888
+ <% } else { %>
889
+ export DB_CONFIG_USER DB_CONFIG_PASSWORD DB_CONFIG_NAME JWT_CONFIG_SECRET
890
+ <% } %>
891
+
892
+ echo "Generated new secure credentials:"
893
+ echo "- Database: ${DB_CONFIG_USER} / [hidden]"
894
+ <% if (backend.eventQueue) { %>
895
+ echo "- Redis: [hidden password]"
896
+ <% } %>
897
+ echo "- JWT: [hidden secret]"
898
+ fi
899
+ ;;
900
+ 4)
901
+ if [ "$has_env_files" = false ] && [ "$has_volumes" = true ]; then
902
+ # Scenario B: No option 4
903
+ print_info "Invalid option. Exiting."
904
+ else
905
+ # Scenarios A & C: Exit
906
+ print_info "Setup cancelled"
907
+ fi
908
+ exit 0
909
+ ;;
910
+ *)
911
+ if [ "$has_env_files" = false ] && [ "$has_volumes" = true ]; then
912
+ print_info "Invalid option. Exiting."
913
+ exit 0
914
+ else
915
+ print_info "Invalid option. Using existing configuration."
916
+ fi
917
+ ;;
918
+ esac
919
+ else
920
+ # No existing configuration - ask for initial setup
921
+ print_info "No existing configuration found. Let's set up credentials."
922
+ echo ""
923
+ read -p "Configure custom credentials? (y/n - 'n' uses secure defaults): " -n 1 -r
924
+ echo
925
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
926
+ collect_configuration
927
+ else
928
+ print_info "Using secure auto-generated credentials..."
929
+ # Generate secure defaults without prompts
930
+ DB_CONFIG_USER="postgres"
931
+ DB_CONFIG_PASSWORD=$(generate_password 12)
932
+ DB_CONFIG_NAME="auth_boilerplate"
933
+ <% if (backend.eventQueue) { %>
934
+ REDIS_CONFIG_PASSWORD=$(generate_password 16)
935
+ <% } %>
936
+ JWT_CONFIG_SECRET=$(generate_jwt_secret)
937
+ <% if (backend.eventQueue) { %>
938
+ export DB_CONFIG_USER DB_CONFIG_PASSWORD DB_CONFIG_NAME REDIS_CONFIG_PASSWORD JWT_CONFIG_SECRET
939
+ <% } else { %>
940
+ export DB_CONFIG_USER DB_CONFIG_PASSWORD DB_CONFIG_NAME JWT_CONFIG_SECRET
941
+ <% } %>
942
+
943
+ echo "Generated secure credentials:"
944
+ echo "- Database: ${DB_CONFIG_USER} / [hidden]"
945
+ <% if (backend.eventQueue) { %>
946
+ echo "- Redis: [hidden password]"
947
+ <% } %>
948
+ echo "- JWT: [hidden secret]"
949
+ fi
950
+ fi
951
+
952
+ setup_env_files
953
+ make_scripts_executable
954
+
955
+ # Ask if user wants to install dependencies
956
+ read -p "Install dependencies? (y/n): " -n 1 -r
957
+ echo
958
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
959
+ install_backend_deps
960
+ <% if (platforms.includes('mobile')) { %>
961
+ install_mobile_deps
962
+ <% } %>
963
+ <% if (platforms.includes('web')) { %>
964
+ install_web_deps
965
+ <% } %>
966
+ fi
967
+
968
+ # Ask if user wants to setup database<% if (backend.eventQueue) { %> and Redis<% } %>
969
+ read -p "Setup database<% if (backend.eventQueue) { %> and Redis<% } %> with Docker? (y/n): " -n 1 -r
970
+ echo
971
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
972
+ setup_database
973
+ fi
974
+
975
+ print_next_steps
976
+ }
977
+
978
+ # Run main function
979
+ main "$@"