securepool 1.0.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 (126) hide show
  1. package/.dockerignore +7 -0
  2. package/.env.example +20 -0
  3. package/ARCHITECTURE.md +279 -0
  4. package/DEPLOYMENT.md +441 -0
  5. package/README.md +283 -0
  6. package/SETUP.md +388 -0
  7. package/apps/demo-backend/Dockerfile +33 -0
  8. package/apps/demo-backend/package.json +19 -0
  9. package/apps/demo-backend/src/index.ts +71 -0
  10. package/apps/demo-backend/tsconfig.json +8 -0
  11. package/apps/demo-frontend/.env.example +2 -0
  12. package/apps/demo-frontend/README.md +73 -0
  13. package/apps/demo-frontend/eslint.config.js +23 -0
  14. package/apps/demo-frontend/index.html +13 -0
  15. package/apps/demo-frontend/package.json +24 -0
  16. package/apps/demo-frontend/public/favicon.svg +1 -0
  17. package/apps/demo-frontend/public/icons.svg +24 -0
  18. package/apps/demo-frontend/src/App.tsx +33 -0
  19. package/apps/demo-frontend/src/assets/hero.png +0 -0
  20. package/apps/demo-frontend/src/assets/vite.svg +1 -0
  21. package/apps/demo-frontend/src/components/AccountSwitcher.tsx +373 -0
  22. package/apps/demo-frontend/src/components/ChangePasswordModal.tsx +128 -0
  23. package/apps/demo-frontend/src/index.css +272 -0
  24. package/apps/demo-frontend/src/main.tsx +10 -0
  25. package/apps/demo-frontend/src/pages/DashboardPage.tsx +141 -0
  26. package/apps/demo-frontend/src/pages/ForgotPasswordPage.tsx +183 -0
  27. package/apps/demo-frontend/src/pages/LoginPage.tsx +158 -0
  28. package/apps/demo-frontend/src/pages/OtpLoginPage.tsx +114 -0
  29. package/apps/demo-frontend/src/pages/SignupPage.tsx +95 -0
  30. package/apps/demo-frontend/src/pages/VerifyEmailPage.tsx +84 -0
  31. package/apps/demo-frontend/tsconfig.app.json +28 -0
  32. package/apps/demo-frontend/tsconfig.json +7 -0
  33. package/apps/demo-frontend/tsconfig.node.json +26 -0
  34. package/apps/demo-frontend/vite.config.ts +15 -0
  35. package/docs/DATABASE_MONGODB.md +280 -0
  36. package/docs/DATABASE_SQL.md +472 -0
  37. package/package.json +21 -0
  38. package/packages/api/package.json +30 -0
  39. package/packages/api/src/createSecurePool.ts +113 -0
  40. package/packages/api/src/index.ts +8 -0
  41. package/packages/api/src/middleware/authMiddleware.ts +26 -0
  42. package/packages/api/src/middleware/authorize.ts +24 -0
  43. package/packages/api/src/middleware/rateLimiter.ts +25 -0
  44. package/packages/api/src/middleware/tenantMiddleware.ts +12 -0
  45. package/packages/api/src/routes/authRoutes.ts +229 -0
  46. package/packages/api/src/routes/sessionRoutes.ts +30 -0
  47. package/packages/api/src/swagger.ts +529 -0
  48. package/packages/api/tsconfig.json +8 -0
  49. package/packages/application/package.json +16 -0
  50. package/packages/application/src/index.ts +17 -0
  51. package/packages/application/src/interfaces/IAuditLogRepository.ts +6 -0
  52. package/packages/application/src/interfaces/IAuthPlugin.ts +4 -0
  53. package/packages/application/src/interfaces/IEmailService.ts +3 -0
  54. package/packages/application/src/interfaces/IGoogleAuthService.ts +3 -0
  55. package/packages/application/src/interfaces/IOtpRepository.ts +8 -0
  56. package/packages/application/src/interfaces/IOtpService.ts +4 -0
  57. package/packages/application/src/interfaces/IPasswordHasher.ts +4 -0
  58. package/packages/application/src/interfaces/IRoleRepository.ts +8 -0
  59. package/packages/application/src/interfaces/ISessionRepository.ts +8 -0
  60. package/packages/application/src/interfaces/ITokenRepository.ts +9 -0
  61. package/packages/application/src/interfaces/ITokenService.ts +5 -0
  62. package/packages/application/src/interfaces/IUserRepository.ts +8 -0
  63. package/packages/application/src/services/AuthService.ts +323 -0
  64. package/packages/application/src/services/RefreshTokenService.ts +53 -0
  65. package/packages/application/tsconfig.json +8 -0
  66. package/packages/core/package.json +13 -0
  67. package/packages/core/src/entities/AuditLog.ts +11 -0
  68. package/packages/core/src/entities/OtpCode.ts +10 -0
  69. package/packages/core/src/entities/RefreshToken.ts +9 -0
  70. package/packages/core/src/entities/Role.ts +6 -0
  71. package/packages/core/src/entities/Session.ts +10 -0
  72. package/packages/core/src/entities/Tenant.ts +7 -0
  73. package/packages/core/src/entities/User.ts +10 -0
  74. package/packages/core/src/entities/UserRole.ts +6 -0
  75. package/packages/core/src/enums/index.ts +22 -0
  76. package/packages/core/src/index.ts +10 -0
  77. package/packages/core/tsconfig.json +8 -0
  78. package/packages/infrastructure/package.json +24 -0
  79. package/packages/infrastructure/src/email/NodemailerEmailService.ts +55 -0
  80. package/packages/infrastructure/src/google/GoogleAuthServiceImpl.ts +28 -0
  81. package/packages/infrastructure/src/hashing/BcryptHasher.ts +18 -0
  82. package/packages/infrastructure/src/index.ts +6 -0
  83. package/packages/infrastructure/src/jwt/JwtTokenService.ts +32 -0
  84. package/packages/infrastructure/src/otp/OtpServiceImpl.ts +50 -0
  85. package/packages/infrastructure/tsconfig.json +8 -0
  86. package/packages/persistence/package.json +22 -0
  87. package/packages/persistence/prisma/schema.prisma +88 -0
  88. package/packages/persistence/src/factory.ts +48 -0
  89. package/packages/persistence/src/index.ts +30 -0
  90. package/packages/persistence/src/mongo/connection.ts +9 -0
  91. package/packages/persistence/src/mongo/models/AuditLogModel.ts +21 -0
  92. package/packages/persistence/src/mongo/models/OtpModel.ts +19 -0
  93. package/packages/persistence/src/mongo/models/RefreshTokenModel.ts +17 -0
  94. package/packages/persistence/src/mongo/models/RoleModel.ts +11 -0
  95. package/packages/persistence/src/mongo/models/SessionModel.ts +19 -0
  96. package/packages/persistence/src/mongo/models/UserModel.ts +21 -0
  97. package/packages/persistence/src/mongo/models/UserRoleModel.ts +15 -0
  98. package/packages/persistence/src/mongo/repositories/MongoAuditLogRepository.ts +29 -0
  99. package/packages/persistence/src/mongo/repositories/MongoOtpRepository.ts +34 -0
  100. package/packages/persistence/src/mongo/repositories/MongoRoleRepository.ts +32 -0
  101. package/packages/persistence/src/mongo/repositories/MongoSessionRepository.ts +29 -0
  102. package/packages/persistence/src/mongo/repositories/MongoTokenRepository.ts +34 -0
  103. package/packages/persistence/src/mongo/repositories/MongoUserRepository.ts +37 -0
  104. package/packages/persistence/src/prisma/repositories/PrismaAuditLogRepository.ts +37 -0
  105. package/packages/persistence/src/prisma/repositories/PrismaOtpRepository.ts +43 -0
  106. package/packages/persistence/src/prisma/repositories/PrismaRoleRepository.ts +36 -0
  107. package/packages/persistence/src/prisma/repositories/PrismaSessionRepository.ts +39 -0
  108. package/packages/persistence/src/prisma/repositories/PrismaTokenRepository.ts +50 -0
  109. package/packages/persistence/src/prisma/repositories/PrismaUserRepository.ts +45 -0
  110. package/packages/persistence/tsconfig.json +8 -0
  111. package/packages/react-sdk/package.json +23 -0
  112. package/packages/react-sdk/src/components/GoogleLoginButton.tsx +54 -0
  113. package/packages/react-sdk/src/components/LoginForm.tsx +67 -0
  114. package/packages/react-sdk/src/components/OTPVerification.tsx +104 -0
  115. package/packages/react-sdk/src/components/SessionList.tsx +64 -0
  116. package/packages/react-sdk/src/components/SignupForm.tsx +95 -0
  117. package/packages/react-sdk/src/context/AuthContext.ts +4 -0
  118. package/packages/react-sdk/src/context/SecurePoolProvider.tsx +492 -0
  119. package/packages/react-sdk/src/hooks/useAuth.ts +11 -0
  120. package/packages/react-sdk/src/index.ts +22 -0
  121. package/packages/react-sdk/src/types.ts +53 -0
  122. package/packages/react-sdk/tsconfig.json +12 -0
  123. package/scripts/setup.js +285 -0
  124. package/scripts/setup.sh +309 -0
  125. package/tsconfig.base.json +16 -0
  126. package/turbo.json +16 -0
@@ -0,0 +1,285 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * SecurePool - Cross-platform Setup Script
5
+ * Works on macOS, Linux, and Windows
6
+ *
7
+ * Usage: node scripts/setup.js
8
+ */
9
+
10
+ const { execSync } = require("child_process");
11
+ const fs = require("fs");
12
+ const path = require("path");
13
+ const readline = require("readline");
14
+
15
+ const ROOT = path.resolve(__dirname, "..");
16
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
17
+
18
+ function ask(question, defaultVal) {
19
+ return new Promise((resolve) => {
20
+ const suffix = defaultVal ? ` [${defaultVal}]` : "";
21
+ rl.question(` ${question}${suffix}: `, (answer) => {
22
+ resolve(answer.trim() || defaultVal || "");
23
+ });
24
+ });
25
+ }
26
+
27
+ function run(cmd, opts = {}) {
28
+ try {
29
+ return execSync(cmd, { cwd: ROOT, stdio: opts.silent ? "pipe" : "inherit", ...opts }).toString().trim();
30
+ } catch {
31
+ return null;
32
+ }
33
+ }
34
+
35
+ function runSilent(cmd) {
36
+ return run(cmd, { silent: true, stdio: "pipe" });
37
+ }
38
+
39
+ const GREEN = "\x1b[32m";
40
+ const YELLOW = "\x1b[33m";
41
+ const RED = "\x1b[31m";
42
+ const BLUE = "\x1b[34m";
43
+ const BOLD = "\x1b[1m";
44
+ const NC = "\x1b[0m";
45
+
46
+ function step(num, total, msg) {
47
+ console.log(`\n${BLUE}${BOLD}[${num}/${total}]${NC} ${GREEN}${msg}${NC}`);
48
+ console.log("─".repeat(40));
49
+ }
50
+
51
+ function ok(msg) { console.log(` ${GREEN}✓${NC} ${msg}`); }
52
+ function warn(msg) { console.log(` ${YELLOW}⚠${NC} ${msg}`); }
53
+ function fail(msg) { console.log(` ${RED}✗${NC} ${msg}`); }
54
+
55
+ const TOTAL_STEPS = 7;
56
+
57
+ async function main() {
58
+ console.log(`\n${BOLD}═══════════════════════════════════════${NC}`);
59
+ console.log(`${BOLD} SecurePool Setup${NC}`);
60
+ console.log(`${BOLD}═══════════════════════════════════════${NC}`);
61
+
62
+ // ──────────────────────────────────────
63
+ // Step 1: Check Prerequisites
64
+ // ──────────────────────────────────────
65
+ step(1, TOTAL_STEPS, "Checking prerequisites");
66
+
67
+ const nodeV = runSilent("node -v");
68
+ if (nodeV) {
69
+ ok(`Node.js ${nodeV}`);
70
+ } else {
71
+ fail("Node.js not found. Install from https://nodejs.org");
72
+ process.exit(1);
73
+ }
74
+
75
+ const npmV = runSilent("npm -v");
76
+ if (npmV) ok(`npm ${npmV}`);
77
+
78
+ const hasOpenSSL = runSilent("openssl version");
79
+ if (hasOpenSSL) {
80
+ ok("OpenSSL available");
81
+ } else {
82
+ warn("OpenSSL not found - you'll need to generate RSA keys manually");
83
+ }
84
+
85
+ const hasMongo = runSilent("mongosh --version");
86
+ if (hasMongo) {
87
+ ok(`mongosh ${hasMongo}`);
88
+ } else {
89
+ warn("mongosh not found - MongoDB setup will be skipped");
90
+ }
91
+
92
+ // ──────────────────────────────────────
93
+ // Step 2: Install Dependencies
94
+ // ──────────────────────────────────────
95
+ step(2, TOTAL_STEPS, "Installing dependencies");
96
+ run("npm install");
97
+ ok("Dependencies installed");
98
+
99
+ // ──────────────────────────────────────
100
+ // Step 3: Generate RSA Keys
101
+ // ──────────────────────────────────────
102
+ step(3, TOTAL_STEPS, "Setting up JWT RSA keys");
103
+
104
+ const privPath = path.join(ROOT, "private.pem");
105
+ const pubPath = path.join(ROOT, "public.pem");
106
+
107
+ if (fs.existsSync(privPath) && fs.existsSync(pubPath)) {
108
+ ok("RSA keys already exist (private.pem, public.pem)");
109
+ } else if (hasOpenSSL) {
110
+ runSilent(`openssl genrsa -out "${privPath}" 2048`);
111
+ runSilent(`openssl rsa -in "${privPath}" -pubout -out "${pubPath}"`);
112
+ ok("Generated RSA key pair");
113
+ } else {
114
+ warn("Cannot generate keys without OpenSSL.");
115
+ warn("Generate manually:");
116
+ console.log(" openssl genrsa -out private.pem 2048");
117
+ console.log(" openssl rsa -in private.pem -pubout -out public.pem");
118
+ }
119
+
120
+ // ──────────────────────────────────────
121
+ // Step 4: MongoDB Setup
122
+ // ──────────────────────────────────────
123
+ step(4, TOTAL_STEPS, "Database configuration");
124
+
125
+ let dbUrl = "mongodb://localhost:27017/securepool";
126
+
127
+ // Check if MongoDB is running
128
+ let mongoRunning = false;
129
+ if (hasMongo) {
130
+ const ping = runSilent('mongosh --eval "db.runCommand({ping:1})" --quiet 2>/dev/null');
131
+ if (ping && ping.includes("ok")) {
132
+ mongoRunning = true;
133
+ ok("MongoDB is running");
134
+ } else {
135
+ warn("MongoDB is not running. Start it before running the app.");
136
+ }
137
+ }
138
+
139
+ console.log("");
140
+ console.log(` ${YELLOW}Choose database:${NC}`);
141
+ console.log(" 1) MongoDB without auth (simplest)");
142
+ console.log(" 2) MongoDB with auth");
143
+ console.log(" 3) Custom connection string");
144
+ console.log("");
145
+
146
+ const dbChoice = await ask("Enter choice", "1");
147
+
148
+ if (dbChoice === "2") {
149
+ const dbUser = await ask("DB username", "securepool-user");
150
+ const dbPass = await ask("DB password", "SecurePool@123");
151
+ const dbPassEncoded = dbPass.replace(/@/g, "%40");
152
+ dbUrl = `mongodb://${dbUser}:${dbPassEncoded}@localhost:27017/securepool?authSource=securepool`;
153
+
154
+ if (mongoRunning) {
155
+ const createUserCmd = `mongosh --quiet --eval "use securepool; try { db.createUser({ user: '${dbUser}', pwd: '${dbPass}', roles: [{ role: 'readWrite', db: 'securepool' }] }); print('created'); } catch(e) { print('exists'); }"`;
156
+ const result = runSilent(createUserCmd);
157
+ if (result && result.includes("created")) {
158
+ ok(`MongoDB user '${dbUser}' created`);
159
+ } else {
160
+ ok(`MongoDB user '${dbUser}' already exists`);
161
+ }
162
+ }
163
+ } else if (dbChoice === "3") {
164
+ dbUrl = await ask("Connection string", dbUrl);
165
+ }
166
+
167
+ ok(`Database: ${dbUrl.replace(/:[^:@]+@/, ":***@")}`);
168
+
169
+ // ──────────────────────────────────────
170
+ // Step 5: Email Setup
171
+ // ──────────────────────────────────────
172
+ step(5, TOTAL_STEPS, "Email configuration (for OTP)");
173
+
174
+ let emailHost = "";
175
+ let emailPort = "";
176
+ let emailSecure = "";
177
+ let emailUser = "";
178
+ let emailPass = "";
179
+ let emailFrom = "";
180
+
181
+ console.log("");
182
+ console.log(` ${YELLOW}Email is needed to send OTP codes.${NC}`);
183
+ console.log(" You can skip and add it later to .env");
184
+ console.log("");
185
+
186
+ const setupEmail = await ask("Setup email now? (y/N)", "N");
187
+
188
+ if (setupEmail.toLowerCase() === "y") {
189
+ console.log("");
190
+ console.log(" For Gmail: create App Password at");
191
+ console.log(" https://myaccount.google.com/apppasswords");
192
+ console.log("");
193
+ emailUser = await ask("Gmail address", "");
194
+ emailPass = await ask("App Password (16 chars)", "");
195
+
196
+ if (emailUser && emailPass) {
197
+ emailHost = "smtp.gmail.com";
198
+ emailPort = "587";
199
+ emailSecure = "false";
200
+ emailFrom = emailUser;
201
+ ok(`Email: ${emailUser}`);
202
+ } else {
203
+ warn("Email skipped (empty input)");
204
+ }
205
+ } else {
206
+ warn("Email skipped - OTP emails won't be sent");
207
+ }
208
+
209
+ // ──────────────────────────────────────
210
+ // Step 6: Create .env
211
+ // ──────────────────────────────────────
212
+ step(6, TOTAL_STEPS, "Creating .env file");
213
+
214
+ const envPath = path.join(ROOT, ".env");
215
+ let writeEnv = true;
216
+
217
+ if (fs.existsSync(envPath)) {
218
+ const overwrite = await ask(".env already exists. Overwrite? (y/N)", "N");
219
+ writeEnv = overwrite.toLowerCase() === "y";
220
+ if (!writeEnv) warn("Keeping existing .env");
221
+ }
222
+
223
+ if (writeEnv) {
224
+ const envContent = `# Database
225
+ DB_TYPE=mongo
226
+ DB_URL=${dbUrl}
227
+
228
+ # JWT
229
+ JWT_PRIVATE_KEY_PATH=./private.pem
230
+ JWT_PUBLIC_KEY_PATH=./public.pem
231
+
232
+ # Email (Gmail SMTP)
233
+ EMAIL_HOST=${emailHost}
234
+ EMAIL_PORT=${emailPort}
235
+ EMAIL_SECURE=${emailSecure}
236
+ EMAIL_USER=${emailUser}
237
+ EMAIL_PASS=${emailPass}
238
+ EMAIL_FROM=${emailFrom}
239
+
240
+ # Server
241
+ PORT=5001
242
+
243
+ # Security
244
+ RATE_LIMIT_ENABLED=true
245
+ CORS_ORIGINS=*
246
+ `;
247
+ fs.writeFileSync(envPath, envContent);
248
+ ok(".env file created");
249
+ }
250
+
251
+ // ──────────────────────────────────────
252
+ // Step 7: Build
253
+ // ──────────────────────────────────────
254
+ step(7, TOTAL_STEPS, "Building all packages");
255
+ run("npx turbo run build --filter=@securepool/*");
256
+ ok("All packages built");
257
+
258
+ // ──────────────────────────────────────
259
+ // Done
260
+ // ──────────────────────────────────────
261
+ console.log("");
262
+ console.log(`${BOLD}═══════════════════════════════════════${NC}`);
263
+ console.log(`${GREEN}${BOLD} SecurePool setup complete!${NC}`);
264
+ console.log(`${BOLD}═══════════════════════════════════════${NC}`);
265
+ console.log("");
266
+ console.log(` ${BOLD}Start backend:${NC}`);
267
+ console.log(" npm run start:backend");
268
+ console.log("");
269
+ console.log(` ${BOLD}Start frontend:${NC} (new terminal)`);
270
+ console.log(" npm run start:frontend");
271
+ console.log("");
272
+ console.log(` ${BOLD}Open:${NC}`);
273
+ console.log(" Frontend → http://localhost:5173");
274
+ console.log(" API Docs → http://localhost:5001/docs");
275
+ console.log(" Health → http://localhost:5001/health");
276
+ console.log("");
277
+
278
+ rl.close();
279
+ }
280
+
281
+ main().catch((err) => {
282
+ console.error(err);
283
+ rl.close();
284
+ process.exit(1);
285
+ });
@@ -0,0 +1,309 @@
1
+ #!/bin/bash
2
+
3
+ # =============================================
4
+ # SecurePool - One-Command Setup Script
5
+ # =============================================
6
+
7
+ set -e
8
+
9
+ ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
10
+ cd "$ROOT_DIR"
11
+
12
+ # Colors
13
+ GREEN='\033[0;32m'
14
+ YELLOW='\033[1;33m'
15
+ RED='\033[0;31m'
16
+ BLUE='\033[0;34m'
17
+ NC='\033[0m' # No Color
18
+ BOLD='\033[1m'
19
+
20
+ print_step() {
21
+ echo ""
22
+ echo -e "${BLUE}${BOLD}[$1/8]${NC} ${GREEN}$2${NC}"
23
+ echo "─────────────────────────────────────"
24
+ }
25
+
26
+ print_success() {
27
+ echo -e " ${GREEN}✓${NC} $1"
28
+ }
29
+
30
+ print_warn() {
31
+ echo -e " ${YELLOW}⚠${NC} $1"
32
+ }
33
+
34
+ print_error() {
35
+ echo -e " ${RED}✗${NC} $1"
36
+ }
37
+
38
+ # =============================================
39
+ # Step 1: Check Prerequisites
40
+ # =============================================
41
+ print_step 1 "Checking prerequisites"
42
+
43
+ # Node.js
44
+ if command -v node &> /dev/null; then
45
+ NODE_VERSION=$(node -v)
46
+ print_success "Node.js $NODE_VERSION"
47
+ else
48
+ print_error "Node.js not found. Install with: brew install node"
49
+ exit 1
50
+ fi
51
+
52
+ # npm
53
+ if command -v npm &> /dev/null; then
54
+ NPM_VERSION=$(npm -v)
55
+ print_success "npm $NPM_VERSION"
56
+ else
57
+ print_error "npm not found"
58
+ exit 1
59
+ fi
60
+
61
+ # OpenSSL
62
+ if command -v openssl &> /dev/null; then
63
+ print_success "OpenSSL available"
64
+ else
65
+ print_error "OpenSSL not found"
66
+ exit 1
67
+ fi
68
+
69
+ # MongoDB
70
+ if command -v mongosh &> /dev/null; then
71
+ print_success "mongosh available"
72
+ else
73
+ print_warn "mongosh not found. Install with: brew install mongodb-community"
74
+ print_warn "Skipping MongoDB setup - you'll need to configure DB_URL manually"
75
+ fi
76
+
77
+ # =============================================
78
+ # Step 2: Install Dependencies
79
+ # =============================================
80
+ print_step 2 "Installing dependencies"
81
+
82
+ npm install --silent 2>&1 | tail -1
83
+ print_success "All packages installed"
84
+
85
+ # =============================================
86
+ # Step 3: Generate RSA Keys
87
+ # =============================================
88
+ print_step 3 "Setting up JWT RSA keys"
89
+
90
+ if [ -f "$ROOT_DIR/private.pem" ] && [ -f "$ROOT_DIR/public.pem" ]; then
91
+ print_success "RSA keys already exist (private.pem, public.pem)"
92
+ else
93
+ openssl genrsa -out "$ROOT_DIR/private.pem" 2048 2>/dev/null
94
+ openssl rsa -in "$ROOT_DIR/private.pem" -pubout -out "$ROOT_DIR/public.pem" 2>/dev/null
95
+ print_success "Generated new RSA key pair"
96
+ fi
97
+
98
+ # =============================================
99
+ # Step 4: Setup MongoDB
100
+ # =============================================
101
+ print_step 4 "Setting up MongoDB"
102
+
103
+ MONGO_RUNNING=false
104
+ DB_URL=""
105
+
106
+ # Check if MongoDB is running
107
+ if mongosh --eval "db.runCommand({ ping: 1 })" --quiet 2>/dev/null | grep -q "ok"; then
108
+ MONGO_RUNNING=true
109
+ print_success "MongoDB is running"
110
+ else
111
+ # Try to start MongoDB
112
+ if command -v brew &> /dev/null; then
113
+ print_warn "MongoDB not running. Attempting to start..."
114
+ brew services start mongodb-community 2>/dev/null || true
115
+ sleep 2
116
+ if mongosh --eval "db.runCommand({ ping: 1 })" --quiet 2>/dev/null | grep -q "ok"; then
117
+ MONGO_RUNNING=true
118
+ print_success "MongoDB started via brew"
119
+ fi
120
+ fi
121
+ fi
122
+
123
+ if [ "$MONGO_RUNNING" = true ]; then
124
+ # Ask about authentication setup
125
+ echo ""
126
+ echo -e " ${YELLOW}Choose MongoDB setup:${NC}"
127
+ echo " 1) Simple (no auth) - recommended for quick start"
128
+ echo " 2) With authentication - production-like setup"
129
+ echo ""
130
+ read -p " Enter choice [1]: " MONGO_CHOICE
131
+ MONGO_CHOICE=${MONGO_CHOICE:-1}
132
+
133
+ if [ "$MONGO_CHOICE" = "2" ]; then
134
+ echo ""
135
+ read -p " DB username [securepool-user]: " DB_USER
136
+ DB_USER=${DB_USER:-securepool-user}
137
+ read -p " DB password [SecurePool@123]: " DB_PASS
138
+ DB_PASS=${DB_PASS:-SecurePool@123}
139
+ DB_NAME="securepool"
140
+
141
+ # Create user in MongoDB
142
+ mongosh --quiet --eval "
143
+ use $DB_NAME;
144
+ try {
145
+ db.createUser({
146
+ user: '$DB_USER',
147
+ pwd: '$DB_PASS',
148
+ roles: [{ role: 'readWrite', db: '$DB_NAME' }]
149
+ });
150
+ print('User created successfully');
151
+ } catch(e) {
152
+ if (e.codeName === 'DuplicateKey' || e.code === 11000) {
153
+ print('User already exists - skipping');
154
+ } else {
155
+ print('Note: ' + e.message);
156
+ }
157
+ }
158
+ " 2>/dev/null || true
159
+
160
+ # URL-encode the password (replace @ with %40)
161
+ DB_PASS_ENCODED=$(echo "$DB_PASS" | sed 's/@/%40/g')
162
+ DB_URL="mongodb://${DB_USER}:${DB_PASS_ENCODED}@localhost:27017/${DB_NAME}?authSource=${DB_NAME}"
163
+ print_success "MongoDB user '${DB_USER}' configured"
164
+ else
165
+ DB_URL="mongodb://localhost:27017/securepool"
166
+ print_success "Using MongoDB without authentication"
167
+ fi
168
+ else
169
+ print_warn "MongoDB not available. Using default URL (update .env manually)"
170
+ DB_URL="mongodb://localhost:27017/securepool"
171
+ fi
172
+
173
+ # =============================================
174
+ # Step 5: Setup Email (Optional)
175
+ # =============================================
176
+ print_step 5 "Email configuration (for OTP)"
177
+
178
+ echo ""
179
+ echo -e " ${YELLOW}Email is needed for OTP verification.${NC}"
180
+ echo " You can skip this and add it later to .env"
181
+ echo ""
182
+ read -p " Setup email now? [y/N]: " SETUP_EMAIL
183
+ SETUP_EMAIL=${SETUP_EMAIL:-N}
184
+
185
+ EMAIL_HOST=""
186
+ EMAIL_PORT=""
187
+ EMAIL_SECURE=""
188
+ EMAIL_USER=""
189
+ EMAIL_PASS=""
190
+ EMAIL_FROM=""
191
+
192
+ if [[ "$SETUP_EMAIL" =~ ^[Yy]$ ]]; then
193
+ echo ""
194
+ echo " Using Gmail SMTP (most common):"
195
+ echo " 1. Go to https://myaccount.google.com/apppasswords"
196
+ echo " 2. Generate an App Password"
197
+ echo ""
198
+ read -p " Gmail address: " EMAIL_USER
199
+ read -p " App Password (16 chars): " EMAIL_PASS
200
+
201
+ if [ -n "$EMAIL_USER" ] && [ -n "$EMAIL_PASS" ]; then
202
+ EMAIL_HOST="smtp.gmail.com"
203
+ EMAIL_PORT="587"
204
+ EMAIL_SECURE="false"
205
+ EMAIL_FROM="$EMAIL_USER"
206
+ print_success "Email configured: $EMAIL_USER"
207
+ else
208
+ print_warn "Email skipped (empty input)"
209
+ fi
210
+ else
211
+ print_warn "Email skipped - OTP emails won't be sent"
212
+ fi
213
+
214
+ # =============================================
215
+ # Step 6: Create .env File
216
+ # =============================================
217
+ print_step 6 "Creating .env file"
218
+
219
+ ENV_FILE="$ROOT_DIR/.env"
220
+
221
+ if [ -f "$ENV_FILE" ]; then
222
+ read -p " .env already exists. Overwrite? [y/N]: " OVERWRITE
223
+ OVERWRITE=${OVERWRITE:-N}
224
+ if [[ ! "$OVERWRITE" =~ ^[Yy]$ ]]; then
225
+ print_warn "Keeping existing .env file"
226
+ else
227
+ WRITE_ENV=true
228
+ fi
229
+ else
230
+ WRITE_ENV=true
231
+ fi
232
+
233
+ if [ "$WRITE_ENV" = true ]; then
234
+ cat > "$ENV_FILE" << ENVEOF
235
+ # Database
236
+ DB_TYPE=mongo
237
+ DB_URL=$DB_URL
238
+
239
+ # JWT
240
+ JWT_PRIVATE_KEY_PATH=./private.pem
241
+ JWT_PUBLIC_KEY_PATH=./public.pem
242
+
243
+ # Email (Gmail SMTP)
244
+ EMAIL_HOST=$EMAIL_HOST
245
+ EMAIL_PORT=$EMAIL_PORT
246
+ EMAIL_SECURE=$EMAIL_SECURE
247
+ EMAIL_USER=$EMAIL_USER
248
+ EMAIL_PASS=$EMAIL_PASS
249
+ EMAIL_FROM=$EMAIL_FROM
250
+
251
+ # Server
252
+ PORT=5001
253
+
254
+ # Security
255
+ RATE_LIMIT_ENABLED=true
256
+ CORS_ORIGINS=*
257
+ ENVEOF
258
+ print_success ".env file created"
259
+ fi
260
+
261
+ # =============================================
262
+ # Step 7: Build All Packages
263
+ # =============================================
264
+ print_step 7 "Building all packages"
265
+
266
+ npx turbo run build --filter='@securepool/*' 2>&1 | grep -E "(successful|Failed|cached)" | tail -1
267
+ print_success "All packages built"
268
+
269
+ # =============================================
270
+ # Step 8: Verify Setup
271
+ # =============================================
272
+ print_step 8 "Verifying setup"
273
+
274
+ # Check all dist folders exist
275
+ PACKAGES_OK=true
276
+ for pkg in core application infrastructure persistence api react-sdk; do
277
+ if [ -d "$ROOT_DIR/packages/$pkg/dist" ]; then
278
+ print_success "@securepool/$pkg built"
279
+ else
280
+ print_error "@securepool/$pkg - dist missing!"
281
+ PACKAGES_OK=false
282
+ fi
283
+ done
284
+
285
+ # =============================================
286
+ # Done!
287
+ # =============================================
288
+ echo ""
289
+ echo "═══════════════════════════════════════════"
290
+ echo -e "${GREEN}${BOLD} SecurePool setup complete!${NC}"
291
+ echo "═══════════════════════════════════════════"
292
+ echo ""
293
+ echo -e " ${BOLD}Start backend:${NC}"
294
+ echo " cd apps/demo-backend"
295
+ echo " npx ts-node src/index.ts"
296
+ echo ""
297
+ echo -e " ${BOLD}Start frontend:${NC} (new terminal)"
298
+ echo " cd apps/demo-frontend"
299
+ echo " npx vite"
300
+ echo ""
301
+ echo -e " ${BOLD}API Docs:${NC}"
302
+ echo " http://localhost:5001/docs"
303
+ echo ""
304
+ echo -e " ${BOLD}Frontend:${NC}"
305
+ echo " http://localhost:5173"
306
+ echo ""
307
+ echo -e " ${BOLD}Health check:${NC}"
308
+ echo " curl http://localhost:5001/health"
309
+ echo ""
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "CommonJS",
5
+ "lib": ["ES2020"],
6
+ "declaration": true,
7
+ "declarationMap": true,
8
+ "sourceMap": true,
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "resolveJsonModule": true,
14
+ "moduleResolution": "node"
15
+ }
16
+ }
package/turbo.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "$schema": "https://turbo.build/schema.json",
3
+ "tasks": {
4
+ "build": {
5
+ "dependsOn": ["^build"],
6
+ "outputs": ["dist/**"]
7
+ },
8
+ "dev": {
9
+ "cache": false,
10
+ "persistent": true
11
+ },
12
+ "clean": {
13
+ "cache": false
14
+ }
15
+ }
16
+ }