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.
- package/LICENSE +21 -0
- package/README.md +642 -0
- package/bin/cli.js +12 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +113 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/dependencies.d.ts +82 -0
- package/dist/config/dependencies.d.ts.map +1 -0
- package/dist/config/dependencies.js +82 -0
- package/dist/config/dependencies.js.map +1 -0
- package/dist/config/presets.d.ts +3 -0
- package/dist/config/presets.d.ts.map +1 -0
- package/dist/config/presets.js +174 -0
- package/dist/config/presets.js.map +1 -0
- package/dist/generators/index.d.ts +40 -0
- package/dist/generators/index.d.ts.map +1 -0
- package/dist/generators/index.js +130 -0
- package/dist/generators/index.js.map +1 -0
- package/dist/generators/onboarding.d.ts +8 -0
- package/dist/generators/onboarding.d.ts.map +1 -0
- package/dist/generators/onboarding.js +141 -0
- package/dist/generators/onboarding.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +65 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/features.d.ts +14 -0
- package/dist/prompts/features.d.ts.map +1 -0
- package/dist/prompts/features.js +96 -0
- package/dist/prompts/features.js.map +1 -0
- package/dist/prompts/index.d.ts +3 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +93 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/onboarding.d.ts +6 -0
- package/dist/prompts/onboarding.d.ts.map +1 -0
- package/dist/prompts/onboarding.js +37 -0
- package/dist/prompts/onboarding.js.map +1 -0
- package/dist/prompts/orm.d.ts +3 -0
- package/dist/prompts/orm.d.ts.map +1 -0
- package/dist/prompts/orm.js +23 -0
- package/dist/prompts/orm.js.map +1 -0
- package/dist/prompts/packageManager.d.ts +2 -0
- package/dist/prompts/packageManager.d.ts.map +1 -0
- package/dist/prompts/packageManager.js +18 -0
- package/dist/prompts/packageManager.js.map +1 -0
- package/dist/prompts/platform.d.ts +3 -0
- package/dist/prompts/platform.d.ts.map +1 -0
- package/dist/prompts/platform.js +21 -0
- package/dist/prompts/platform.js.map +1 -0
- package/dist/prompts/preset.d.ts +4 -0
- package/dist/prompts/preset.d.ts.map +1 -0
- package/dist/prompts/preset.js +165 -0
- package/dist/prompts/preset.js.map +1 -0
- package/dist/prompts/project.d.ts +2 -0
- package/dist/prompts/project.d.ts.map +1 -0
- package/dist/prompts/project.js +27 -0
- package/dist/prompts/project.js.map +1 -0
- package/dist/prompts/sdks.d.ts +2 -0
- package/dist/prompts/sdks.d.ts.map +1 -0
- package/dist/prompts/sdks.js +46 -0
- package/dist/prompts/sdks.js.map +1 -0
- package/dist/types/index.d.ts +77 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +25 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/cleanup.d.ts +5 -0
- package/dist/utils/cleanup.d.ts.map +1 -0
- package/dist/utils/cleanup.js +38 -0
- package/dist/utils/cleanup.js.map +1 -0
- package/dist/utils/copy.d.ts +10 -0
- package/dist/utils/copy.d.ts.map +1 -0
- package/dist/utils/copy.js +53 -0
- package/dist/utils/copy.js.map +1 -0
- package/dist/utils/errors.d.ts +33 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +136 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/git.d.ts +5 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +33 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/logger.d.ts +9 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +22 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/package.d.ts +16 -0
- package/dist/utils/package.d.ts.map +1 -0
- package/dist/utils/package.js +86 -0
- package/dist/utils/package.js.map +1 -0
- package/dist/utils/system-validation.d.ts +9 -0
- package/dist/utils/system-validation.d.ts.map +1 -0
- package/dist/utils/system-validation.js +31 -0
- package/dist/utils/system-validation.js.map +1 -0
- package/dist/utils/template.d.ts +20 -0
- package/dist/utils/template.d.ts.map +1 -0
- package/dist/utils/template.js +234 -0
- package/dist/utils/template.js.map +1 -0
- package/dist/utils/validation.d.ts +8 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +94 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +96 -0
- package/templates/base/backend/.dockerignore.ejs +62 -0
- package/templates/base/backend/.env.example.ejs +116 -0
- package/templates/base/backend/Dockerfile.ejs +142 -0
- package/templates/base/backend/controllers/event-queue/index.ts +20 -0
- package/templates/base/backend/controllers/event-queue/workers/user.ts +39 -0
- package/templates/base/backend/controllers/rest-api/index.ts +48 -0
- package/templates/base/backend/controllers/rest-api/plugins/auth.ts +152 -0
- package/templates/base/backend/controllers/rest-api/plugins/config.ts +64 -0
- package/templates/base/backend/controllers/rest-api/plugins/error-handler.ts +118 -0
- package/templates/base/backend/controllers/rest-api/routes/auth.ts.ejs +180 -0
- package/templates/base/backend/controllers/rest-api/routes/device-sessions.ts +197 -0
- package/templates/base/backend/controllers/rest-api/routes/oauth-web.ts.ejs +375 -0
- package/templates/base/backend/controllers/rest-api/server.ts.ejs +87 -0
- package/templates/base/backend/domain/device-session/repository.drizzle.ts +209 -0
- package/templates/base/backend/domain/device-session/repository.prisma.ts +248 -0
- package/templates/base/backend/domain/device-session/schema.ts +72 -0
- package/templates/base/backend/domain/session/repository.drizzle.ts +72 -0
- package/templates/base/backend/domain/session/repository.prisma.ts +72 -0
- package/templates/base/backend/domain/session/schema.ts +29 -0
- package/templates/base/backend/domain/user/repository.drizzle.ts +127 -0
- package/templates/base/backend/domain/user/repository.prisma.ts +115 -0
- package/templates/base/backend/domain/user/schema.ts +14 -0
- package/templates/base/backend/drizzle/schema.drizzle.ts +111 -0
- package/templates/base/backend/drizzle.config.drizzle.ts +13 -0
- package/templates/base/backend/lib/auth.drizzle.ts.ejs +104 -0
- package/templates/base/backend/lib/auth.prisma.ts.ejs +97 -0
- package/templates/base/backend/lib/constants.ts.ejs +29 -0
- package/templates/base/backend/package.json.ejs +50 -0
- package/templates/base/backend/prisma/schema.prisma.ejs +102 -0
- package/templates/base/backend/prisma.config.prisma.ts +12 -0
- package/templates/base/backend/tsconfig.json +39 -0
- package/templates/base/backend/utils/db.drizzle.ts +41 -0
- package/templates/base/backend/utils/db.prisma.ts +51 -0
- package/templates/base/backend/utils/email.ts.ejs +35 -0
- package/templates/base/backend/utils/errors.ts +348 -0
- package/templates/base/backend/utils/redis.ts.ejs +279 -0
- package/templates/base/mobile/.env.example.ejs +35 -0
- package/templates/base/mobile/.gitignore.ejs +167 -0
- package/templates/base/mobile/app/+not-found.tsx +85 -0
- package/templates/base/mobile/app/_layout.tsx.ejs +71 -0
- package/templates/base/mobile/app.json.ejs +88 -0
- package/templates/base/mobile/assets/images/adaptive-icon.png +0 -0
- package/templates/base/mobile/assets/images/favicon.png +0 -0
- package/templates/base/mobile/assets/images/icon.png +0 -0
- package/templates/base/mobile/assets/images/onboarding_page_1.png +0 -0
- package/templates/base/mobile/assets/images/onboarding_page_2.png +0 -0
- package/templates/base/mobile/assets/images/onboarding_page_3.png +0 -0
- package/templates/base/mobile/assets/images/paywall_image.png +0 -0
- package/templates/base/mobile/assets/images/splash.png +0 -0
- package/templates/base/mobile/eas.json.ejs +49 -0
- package/templates/base/mobile/metro.config.js +9 -0
- package/templates/base/mobile/package.json.ejs +53 -0
- package/templates/base/mobile/src/components/ui/Button.tsx +131 -0
- package/templates/base/mobile/src/components/ui/Card.tsx +68 -0
- package/templates/base/mobile/src/components/ui/IconSymbol.tsx +90 -0
- package/templates/base/mobile/src/components/ui/Input.tsx +142 -0
- package/templates/base/mobile/src/components/ui/LoadingSpinner.tsx +98 -0
- package/templates/base/mobile/src/components/ui/OnboardingLayout.tsx +356 -0
- package/templates/base/mobile/src/components/ui/PaywallLayout.tsx +311 -0
- package/templates/base/mobile/src/components/ui/Skeleton.tsx +58 -0
- package/templates/base/mobile/src/components/ui/index.ts +6 -0
- package/templates/base/mobile/src/constants/Theme.ts +163 -0
- package/templates/base/mobile/src/context/ThemeContext.tsx +157 -0
- package/templates/base/mobile/src/lib/auth-client.ts.ejs +51 -0
- package/templates/base/mobile/src/services/api.ts.ejs +71 -0
- package/templates/base/mobile/src/services/errorService.ts +179 -0
- package/templates/base/mobile/src/services/sdkInitializer.ts.ejs +36 -0
- package/templates/base/mobile/src/store/index.ts.ejs +18 -0
- package/templates/base/mobile/src/store/ui.store.ts +100 -0
- package/templates/base/mobile/src/utils/formatters.ts +105 -0
- package/templates/base/mobile/src/utils/logger.ts +73 -0
- package/templates/base/mobile/src/utils/responsive.ts +234 -0
- package/templates/base/mobile/tsconfig.json +32 -0
- package/templates/base/web/.env.example.ejs +26 -0
- package/templates/base/web/components.json +22 -0
- package/templates/base/web/eslint.config.mjs +18 -0
- package/templates/base/web/next.config.ts +7 -0
- package/templates/base/web/package.json.ejs +35 -0
- package/templates/base/web/postcss.config.mjs +7 -0
- package/templates/base/web/public/.gitkeep +0 -0
- package/templates/base/web/public/file.svg +1 -0
- package/templates/base/web/public/globe.svg +1 -0
- package/templates/base/web/public/next.svg +1 -0
- package/templates/base/web/public/vercel.svg +1 -0
- package/templates/base/web/public/window.svg +1 -0
- package/templates/base/web/src/app/favicon.ico +0 -0
- package/templates/base/web/src/app/globals.css +152 -0
- package/templates/base/web/src/app/layout.tsx.ejs +54 -0
- package/templates/base/web/src/app/page.tsx.ejs +92 -0
- package/templates/base/web/src/components/auth/auth-hydrator.tsx.ejs +19 -0
- package/templates/base/web/src/components/auth/protected-route.tsx.ejs +109 -0
- package/templates/base/web/src/components/providers/device-session-setup.tsx.ejs +56 -0
- package/templates/base/web/src/components/providers/theme-provider.tsx +17 -0
- package/templates/base/web/src/components/theme-toggle.tsx +34 -0
- package/templates/base/web/src/components/ui/button.tsx +62 -0
- package/templates/base/web/src/components/ui/card.tsx +92 -0
- package/templates/base/web/src/components/ui/input.tsx +21 -0
- package/templates/base/web/src/components/ui/label.tsx +24 -0
- package/templates/base/web/src/components/ui/skeleton.tsx +13 -0
- package/templates/base/web/src/components/ui/spinner.tsx +20 -0
- package/templates/base/web/src/hooks/use-device-session.ts.ejs +40 -0
- package/templates/base/web/src/hooks/use-session.ts.ejs +56 -0
- package/templates/base/web/src/lib/auth/actions.ts.ejs +334 -0
- package/templates/base/web/src/lib/auth/config.ts.ejs +65 -0
- package/templates/base/web/src/lib/auth/cookies.ts.ejs +74 -0
- package/templates/base/web/src/lib/auth/index.ts.ejs +40 -0
- package/templates/base/web/src/lib/auth/oauth.ts.ejs +72 -0
- package/templates/base/web/src/lib/auth/pkce.ts.ejs +48 -0
- package/templates/base/web/src/lib/auth/sessions.ts.ejs +135 -0
- package/templates/base/web/src/lib/auth/user-agent.ts.ejs +47 -0
- package/templates/base/web/src/lib/device/actions.ts.ejs +148 -0
- package/templates/base/web/src/lib/device/id.ts.ejs +74 -0
- package/templates/base/web/src/lib/utils.ts +6 -0
- package/templates/base/web/src/proxy.ts.ejs +66 -0
- package/templates/base/web/src/store/auth.store.ts.ejs +89 -0
- package/templates/base/web/src/store/deviceSession.store.ts.ejs +141 -0
- package/templates/base/web/tsconfig.json +34 -0
- package/templates/features/mobile/auth/app/(auth)/_layout.tsx +16 -0
- package/templates/features/mobile/auth/app/(auth)/login.tsx +86 -0
- package/templates/features/mobile/auth/app/(auth)/register.tsx +86 -0
- package/templates/features/mobile/auth/components/auth/LoginForm.tsx.ejs +349 -0
- package/templates/features/mobile/auth/components/auth/RegisterForm.tsx.ejs +407 -0
- package/templates/features/mobile/auth/components/auth/index.ts +2 -0
- package/templates/features/mobile/auth/hooks/index.ts.ejs +1 -0
- package/templates/features/mobile/auth/hooks/useAuth.ts.ejs +367 -0
- package/templates/features/mobile/auth/services/deviceSession.ts +370 -0
- package/templates/features/mobile/auth/store/deviceSession.store.ts +326 -0
- package/templates/features/mobile/onboarding/app/(onboarding)/_layout.tsx.ejs +11 -0
- package/templates/features/mobile/onboarding/app/(onboarding)/page-1.tsx.ejs +52 -0
- package/templates/features/mobile/onboarding/app/(onboarding)/page-2.tsx.ejs +52 -0
- package/templates/features/mobile/onboarding/app/(onboarding)/page-3.tsx.ejs +60 -0
- package/templates/features/mobile/paywall/app/paywall.tsx +550 -0
- package/templates/features/mobile/tabs/app/(tabs)/_layout.tsx +26 -0
- package/templates/features/mobile/tabs/app/(tabs)/index.tsx +565 -0
- package/templates/features/web/.gitkeep +0 -0
- package/templates/features/web/auth/app/(app)/dashboard/dashboard-client.tsx.ejs +166 -0
- package/templates/features/web/auth/app/(app)/dashboard/page.tsx.ejs +24 -0
- package/templates/features/web/auth/app/(app)/layout.tsx.ejs +43 -0
- package/templates/features/web/auth/app/(app)/settings/sessions/page.tsx.ejs +29 -0
- package/templates/features/web/auth/app/(app)/settings/sessions/sessions-client.tsx.ejs +77 -0
- package/templates/features/web/auth/app/(auth)/forgot-password/page.tsx.ejs +127 -0
- package/templates/features/web/auth/app/(auth)/layout.tsx.ejs +32 -0
- package/templates/features/web/auth/app/(auth)/login/page.tsx.ejs +35 -0
- package/templates/features/web/auth/app/(auth)/register/page.tsx.ejs +19 -0
- package/templates/features/web/auth/app/(auth)/reset-password/page.tsx.ejs +40 -0
- package/templates/features/web/auth/app/(auth)/verify-email/page.tsx.ejs +198 -0
- package/templates/features/web/auth/app/auth/callback/route.ts.ejs +152 -0
- package/templates/features/web/auth/components/auth/login-form.tsx.ejs +100 -0
- package/templates/features/web/auth/components/auth/oauth-buttons.tsx.ejs +126 -0
- package/templates/features/web/auth/components/auth/password-reset-form.tsx.ejs +103 -0
- package/templates/features/web/auth/components/auth/register-form.tsx.ejs +139 -0
- package/templates/features/web/auth/components/settings/session-card.tsx.ejs +132 -0
- package/templates/integrations/mobile/adjust/services/adjustService.ts.ejs +163 -0
- package/templates/integrations/mobile/adjust/store/adjust.store.ts +243 -0
- package/templates/integrations/mobile/att/services/attService.ts +84 -0
- package/templates/integrations/mobile/att/services/trackingPermissions.ts +208 -0
- package/templates/integrations/mobile/att/store/att.store.ts +162 -0
- package/templates/integrations/mobile/revenuecat/services/revenuecatService.ts.ejs +174 -0
- package/templates/integrations/mobile/revenuecat/store/revenuecat.store.ts +286 -0
- package/templates/integrations/mobile/scate/services/scateService.ts.ejs +85 -0
- package/templates/integrations/mobile/scate/store/scate.store.ts +125 -0
- package/templates/integrations/web/.gitkeep +0 -0
- package/templates/shared/.env.example.ejs +21 -0
- package/templates/shared/.gitignore.ejs +145 -0
- package/templates/shared/README.md.ejs +134 -0
- package/templates/shared/docker-compose.prod.yml.ejs +120 -0
- package/templates/shared/docker-compose.yml.ejs +129 -0
- package/templates/shared/scripts/docker-dev.sh.ejs +395 -0
- package/templates/shared/scripts/docker-prod.sh.ejs +542 -0
- 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 "$@"
|