create-arktos 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.
- package/.env.example +69 -0
- package/LICENSE +21 -0
- package/README.md +533 -0
- package/bin/cli.js +318 -0
- package/eslint.config.js +79 -0
- package/package.json +108 -0
- package/prisma/schema.prisma +172 -0
- package/src/app.ts +101 -0
- package/src/config/env.validation.ts +15 -0
- package/src/config/logger.ts +76 -0
- package/src/constants/errorCodes.ts +59 -0
- package/src/constants/messages.ts +190 -0
- package/src/controllers/auth.controller.ts +546 -0
- package/src/middleware/index.ts +638 -0
- package/src/routes/auth.routes.ts +29 -0
- package/src/routes/index.ts +63 -0
- package/src/schemas/index.ts +139 -0
- package/src/services/database.service.ts +120 -0
- package/src/services/email.service.ts +244 -0
- package/src/services/jwt.service.ts +227 -0
- package/src/types/express.d.ts +19 -0
- package/src/types/index.ts +156 -0
- package/src/utils/response.ts +55 -0
- package/src/views/emails/notification.html +87 -0
- package/src/views/emails/resetPassword.html +118 -0
- package/src/views/emails/verification.html +107 -0
- package/src/views/emails/welcome.html +113 -0
- package/template.package.json +82 -0
- package/tsconfig.json +35 -0
- package/vercel.json +34 -0
package/bin/cli.js
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
const TEMPLATE_DIR = path.join(__dirname, '../src');
|
|
8
|
+
const ROOT_DIR = path.join(__dirname, '..');
|
|
9
|
+
|
|
10
|
+
function createProject(projectName) {
|
|
11
|
+
console.log(`🚀 Creating Arktos project: ${projectName}`);
|
|
12
|
+
console.log();
|
|
13
|
+
|
|
14
|
+
// Validate project name
|
|
15
|
+
if (!projectName || !/^[a-zA-Z0-9-_]+$/.test(projectName)) {
|
|
16
|
+
console.error('❌ Invalid project name. Use only letters, numbers, hyphens, and underscores.');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Check if directory already exists
|
|
21
|
+
if (fs.existsSync(projectName)) {
|
|
22
|
+
console.error(`❌ Directory '${projectName}' already exists.`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
// Create project directory
|
|
28
|
+
console.log('📁 Creating project directory...');
|
|
29
|
+
fs.mkdirSync(projectName);
|
|
30
|
+
|
|
31
|
+
// Copy template files
|
|
32
|
+
console.log('📋 Copying template files...');
|
|
33
|
+
copyDir(TEMPLATE_DIR, projectName);
|
|
34
|
+
|
|
35
|
+
// Copy template config files
|
|
36
|
+
console.log('📝 Copying configuration files...');
|
|
37
|
+
copyTemplateFiles(projectName);
|
|
38
|
+
|
|
39
|
+
// Copy and update package.json
|
|
40
|
+
console.log('🔧 Updating project configuration...');
|
|
41
|
+
const templatePackageJsonPath = path.join(ROOT_DIR, 'template.package.json');
|
|
42
|
+
const targetPackageJsonPath = path.join(projectName, 'package.json');
|
|
43
|
+
|
|
44
|
+
if (fs.existsSync(templatePackageJsonPath)) {
|
|
45
|
+
const packageJson = JSON.parse(fs.readFileSync(templatePackageJsonPath, 'utf8'));
|
|
46
|
+
|
|
47
|
+
// Update project name
|
|
48
|
+
packageJson.name = projectName;
|
|
49
|
+
|
|
50
|
+
fs.writeFileSync(targetPackageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
console.log('✅ Project created successfully!');
|
|
54
|
+
console.log();
|
|
55
|
+
console.log('🎯 Next steps:');
|
|
56
|
+
console.log(` cd ${projectName}`);
|
|
57
|
+
console.log(' npm install');
|
|
58
|
+
console.log(' cp .env.example .env');
|
|
59
|
+
console.log(' # Edit .env with your database and API keys');
|
|
60
|
+
console.log(' npx prisma migrate dev');
|
|
61
|
+
console.log(' npm run dev');
|
|
62
|
+
console.log();
|
|
63
|
+
console.log('📚 Documentation:');
|
|
64
|
+
console.log(' • Backend API: http://localhost:3001');
|
|
65
|
+
console.log(' • Setup your Neon database: https://neon.tech');
|
|
66
|
+
console.log(' • Setup Resend for emails: https://resend.com');
|
|
67
|
+
console.log(' • Deploy on Vercel: https://vercel.com');
|
|
68
|
+
console.log();
|
|
69
|
+
console.log('🔧 Available commands:');
|
|
70
|
+
console.log(' npm run dev - Start development server');
|
|
71
|
+
console.log(' npm run build - Build for production');
|
|
72
|
+
console.log(' npm run start - Start production server');
|
|
73
|
+
console.log(' npm run db:studio - Open Prisma Studio');
|
|
74
|
+
console.log();
|
|
75
|
+
console.log('Happy coding! 🎉');
|
|
76
|
+
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error('❌ Error creating project:', error.message);
|
|
79
|
+
|
|
80
|
+
// Cleanup on error
|
|
81
|
+
try {
|
|
82
|
+
if (fs.existsSync(projectName)) {
|
|
83
|
+
fs.rmSync(projectName, { recursive: true, force: true });
|
|
84
|
+
}
|
|
85
|
+
} catch (cleanupError) {
|
|
86
|
+
console.error('❌ Error during cleanup:', cleanupError.message);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function copyDir(src, dest) {
|
|
94
|
+
// Create destination directory
|
|
95
|
+
if (!fs.existsSync(dest)) {
|
|
96
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Read source directory
|
|
100
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
101
|
+
|
|
102
|
+
for (const entry of entries) {
|
|
103
|
+
const srcPath = path.join(src, entry.name);
|
|
104
|
+
const destPath = path.join(dest, entry.name);
|
|
105
|
+
|
|
106
|
+
if (entry.isDirectory()) {
|
|
107
|
+
// Recursively copy subdirectories
|
|
108
|
+
copyDir(srcPath, destPath);
|
|
109
|
+
} else {
|
|
110
|
+
// Copy files
|
|
111
|
+
fs.copyFileSync(srcPath, destPath);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function copyTemplateFiles(dest) {
|
|
117
|
+
// Create common config files
|
|
118
|
+
const configFiles = {
|
|
119
|
+
'.gitignore': `# Dependencies
|
|
120
|
+
node_modules/
|
|
121
|
+
npm-debug.log*
|
|
122
|
+
yarn-debug.log*
|
|
123
|
+
yarn-error.log*
|
|
124
|
+
|
|
125
|
+
# Environment variables
|
|
126
|
+
.env
|
|
127
|
+
.env.local
|
|
128
|
+
.env.development.local
|
|
129
|
+
.env.test.local
|
|
130
|
+
.env.production.local
|
|
131
|
+
|
|
132
|
+
# Build outputs
|
|
133
|
+
dist/
|
|
134
|
+
build/
|
|
135
|
+
|
|
136
|
+
# Logs
|
|
137
|
+
logs/
|
|
138
|
+
*.log
|
|
139
|
+
|
|
140
|
+
# Runtime data
|
|
141
|
+
pids
|
|
142
|
+
*.pid
|
|
143
|
+
*.seed
|
|
144
|
+
*.pid.lock
|
|
145
|
+
|
|
146
|
+
# Coverage directory used by tools like istanbul
|
|
147
|
+
coverage/
|
|
148
|
+
|
|
149
|
+
# OS generated files
|
|
150
|
+
.DS_Store
|
|
151
|
+
.DS_Store?
|
|
152
|
+
._*
|
|
153
|
+
.Spotlight-V100
|
|
154
|
+
.Trashes
|
|
155
|
+
ehthumbs.db
|
|
156
|
+
Thumbs.db
|
|
157
|
+
|
|
158
|
+
# IDE files
|
|
159
|
+
.vscode/
|
|
160
|
+
.idea/
|
|
161
|
+
*.swp
|
|
162
|
+
*.swo
|
|
163
|
+
*~
|
|
164
|
+
|
|
165
|
+
# Prisma
|
|
166
|
+
prisma/migrations/dev.db*
|
|
167
|
+
|
|
168
|
+
# Temporary files
|
|
169
|
+
*.tmp
|
|
170
|
+
*.temp
|
|
171
|
+
.cache/
|
|
172
|
+
|
|
173
|
+
# Vercel
|
|
174
|
+
.vercel
|
|
175
|
+
|
|
176
|
+
# TypeScript
|
|
177
|
+
*.tsbuildinfo`,
|
|
178
|
+
'.prettierrc': `{
|
|
179
|
+
"semi": true,
|
|
180
|
+
"trailingComma": "es5",
|
|
181
|
+
"singleQuote": true,
|
|
182
|
+
"printWidth": 80,
|
|
183
|
+
"tabWidth": 2,
|
|
184
|
+
"useTabs": false,
|
|
185
|
+
"bracketSpacing": true,
|
|
186
|
+
"arrowParens": "avoid",
|
|
187
|
+
"endOfLine": "lf"
|
|
188
|
+
}`,
|
|
189
|
+
'README.md': `# ${path.basename(dest)} API
|
|
190
|
+
|
|
191
|
+
A modern Node.js backend API built with Arktos boilerplate.
|
|
192
|
+
|
|
193
|
+
## 🚀 Features
|
|
194
|
+
|
|
195
|
+
- **TypeScript**: Full TypeScript support with strict type checking
|
|
196
|
+
- **Express.js**: Fast, unopinionated web framework
|
|
197
|
+
- **Authentication**: Complete JWT-based authentication system
|
|
198
|
+
- **Database**: Prisma ORM with PostgreSQL (Neon serverless)
|
|
199
|
+
- **Email Service**: Resend integration for transactional emails
|
|
200
|
+
- **Security**: Helmet, CORS, rate limiting, and security middleware
|
|
201
|
+
- **Validation**: Zod-based request validation
|
|
202
|
+
- **Logging**: Winston logger with file rotation
|
|
203
|
+
- **Error Handling**: Comprehensive error handling and responses
|
|
204
|
+
- **API Documentation**: Structured API responses
|
|
205
|
+
- **Deployment Ready**: Vercel configuration included
|
|
206
|
+
|
|
207
|
+
## 📋 Prerequisites
|
|
208
|
+
|
|
209
|
+
- Node.js 18+ and npm 8+
|
|
210
|
+
- PostgreSQL database (recommend [Neon](https://neon.tech/) for serverless)
|
|
211
|
+
- Resend account for email service
|
|
212
|
+
|
|
213
|
+
## 🛠️ Installation
|
|
214
|
+
|
|
215
|
+
1. **Install dependencies**
|
|
216
|
+
\`\`\`bash
|
|
217
|
+
npm install
|
|
218
|
+
\`\`\`
|
|
219
|
+
|
|
220
|
+
2. **Environment Setup**
|
|
221
|
+
\`\`\`bash
|
|
222
|
+
cp .env.example .env
|
|
223
|
+
\`\`\`
|
|
224
|
+
Fill in your environment variables in \`.env\`
|
|
225
|
+
|
|
226
|
+
3. **Database Setup**
|
|
227
|
+
\`\`\`bash
|
|
228
|
+
# Generate Prisma client
|
|
229
|
+
npx prisma generate
|
|
230
|
+
|
|
231
|
+
# Run database migrations
|
|
232
|
+
npx prisma migrate dev
|
|
233
|
+
\`\`\`
|
|
234
|
+
|
|
235
|
+
4. **Start Development Server**
|
|
236
|
+
\`\`\`bash
|
|
237
|
+
npm run dev
|
|
238
|
+
\`\`\`
|
|
239
|
+
|
|
240
|
+
## 🔧 Available Scripts
|
|
241
|
+
|
|
242
|
+
- \`npm run dev\` - Start development server with hot reload
|
|
243
|
+
- \`npm run build\` - Build for production
|
|
244
|
+
- \`npm start\` - Start production server
|
|
245
|
+
- \`npm run type-check\` - Run TypeScript type checking
|
|
246
|
+
- \`npm run lint\` - Run ESLint
|
|
247
|
+
- \`npm run db:studio\` - Open Prisma Studio
|
|
248
|
+
|
|
249
|
+
Happy coding! 🎉`
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// Write config files
|
|
253
|
+
for (const [fileName, content] of Object.entries(configFiles)) {
|
|
254
|
+
fs.writeFileSync(path.join(dest, fileName), content);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Copy template files from root
|
|
258
|
+
const templateFiles = ['.env.example', 'vercel.json', 'tsconfig.json', 'eslint.config.js'];
|
|
259
|
+
|
|
260
|
+
for (const templateFile of templateFiles) {
|
|
261
|
+
const srcPath = path.join(ROOT_DIR, templateFile);
|
|
262
|
+
const destPath = path.join(dest, templateFile);
|
|
263
|
+
|
|
264
|
+
if (fs.existsSync(srcPath)) {
|
|
265
|
+
fs.copyFileSync(srcPath, destPath);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function showHelp() {
|
|
271
|
+
console.log();
|
|
272
|
+
console.log('🏛️ Arktos - Modern Node.js Backend Boilerplate');
|
|
273
|
+
console.log();
|
|
274
|
+
console.log('Usage:');
|
|
275
|
+
console.log(' npx create-arktos <project-name>');
|
|
276
|
+
console.log();
|
|
277
|
+
console.log('Example:');
|
|
278
|
+
console.log(' npx create-arktos my-awesome-api');
|
|
279
|
+
console.log();
|
|
280
|
+
console.log('Features:');
|
|
281
|
+
console.log(' ✅ Express.js server with modern middleware');
|
|
282
|
+
console.log(' ✅ JWT authentication with refresh tokens');
|
|
283
|
+
console.log(' ✅ Prisma ORM with PostgreSQL (Neon)');
|
|
284
|
+
console.log(' ✅ Email service with Resend');
|
|
285
|
+
console.log(' ✅ User authentication and management');
|
|
286
|
+
console.log(' ✅ Login logging and security features');
|
|
287
|
+
console.log(' ✅ Rate limiting and security headers');
|
|
288
|
+
console.log(' ✅ Comprehensive error handling');
|
|
289
|
+
console.log(' ✅ Winston logging');
|
|
290
|
+
console.log(' ✅ ESLint and Prettier configuration');
|
|
291
|
+
console.log(' ✅ Vercel deployment ready');
|
|
292
|
+
console.log();
|
|
293
|
+
console.log('Options:');
|
|
294
|
+
console.log(' -h, --help Show this help message');
|
|
295
|
+
console.log(' -v, --version Show version');
|
|
296
|
+
console.log();
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function showVersion() {
|
|
300
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'), 'utf8'));
|
|
301
|
+
console.log(packageJson.version);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Main CLI logic
|
|
305
|
+
const args = process.argv.slice(2);
|
|
306
|
+
|
|
307
|
+
if (args.length === 0 || args[0] === '-h' || args[0] === '--help') {
|
|
308
|
+
showHelp();
|
|
309
|
+
process.exit(0);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (args[0] === '-v' || args[0] === '--version') {
|
|
313
|
+
showVersion();
|
|
314
|
+
process.exit(0);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const projectName = args[0];
|
|
318
|
+
createProject(projectName);
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const js = require('@eslint/js');
|
|
2
|
+
|
|
3
|
+
module.exports = [
|
|
4
|
+
js.configs.recommended,
|
|
5
|
+
{
|
|
6
|
+
languageOptions: {
|
|
7
|
+
ecmaVersion: 2022,
|
|
8
|
+
sourceType: 'commonjs',
|
|
9
|
+
globals: {
|
|
10
|
+
console: 'readonly',
|
|
11
|
+
process: 'readonly',
|
|
12
|
+
Buffer: 'readonly',
|
|
13
|
+
__dirname: 'readonly',
|
|
14
|
+
__filename: 'readonly',
|
|
15
|
+
module: 'readonly',
|
|
16
|
+
require: 'readonly',
|
|
17
|
+
exports: 'readonly',
|
|
18
|
+
global: 'readonly',
|
|
19
|
+
setTimeout: 'readonly',
|
|
20
|
+
setInterval: 'readonly',
|
|
21
|
+
clearTimeout: 'readonly',
|
|
22
|
+
clearInterval: 'readonly',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
rules: {
|
|
26
|
+
'no-unused-vars': ['error', {
|
|
27
|
+
argsIgnorePattern: '^_',
|
|
28
|
+
varsIgnorePattern: '^_'
|
|
29
|
+
}],
|
|
30
|
+
'no-console': ['warn', {
|
|
31
|
+
allow: ['warn', 'error']
|
|
32
|
+
}],
|
|
33
|
+
'prefer-const': 'error',
|
|
34
|
+
'no-var': 'error',
|
|
35
|
+
'eqeqeq': ['error', 'always'],
|
|
36
|
+
'curly': ['error', 'all'],
|
|
37
|
+
'brace-style': ['error', '1tbs'],
|
|
38
|
+
'comma-dangle': ['error', 'always-multiline'],
|
|
39
|
+
'indent': ['error', 2],
|
|
40
|
+
'quotes': ['error', 'single'],
|
|
41
|
+
'semi': ['error', 'always'],
|
|
42
|
+
'no-trailing-spaces': 'error',
|
|
43
|
+
'no-multiple-empty-lines': ['error', {
|
|
44
|
+
max: 2,
|
|
45
|
+
maxEOF: 1
|
|
46
|
+
}],
|
|
47
|
+
'object-curly-spacing': ['error', 'always'],
|
|
48
|
+
'array-bracket-spacing': ['error', 'never'],
|
|
49
|
+
'key-spacing': ['error', {
|
|
50
|
+
beforeColon: false,
|
|
51
|
+
afterColon: true
|
|
52
|
+
}],
|
|
53
|
+
'comma-spacing': ['error', {
|
|
54
|
+
before: false,
|
|
55
|
+
after: true
|
|
56
|
+
}],
|
|
57
|
+
'no-undef': 'error',
|
|
58
|
+
'no-redeclare': 'error',
|
|
59
|
+
'no-dupe-keys': 'error',
|
|
60
|
+
'no-unreachable': 'error',
|
|
61
|
+
'valid-typeof': 'error',
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
files: ['**/*.test.js', '**/*.spec.js'],
|
|
66
|
+
languageOptions: {
|
|
67
|
+
globals: {
|
|
68
|
+
describe: 'readonly',
|
|
69
|
+
it: 'readonly',
|
|
70
|
+
test: 'readonly',
|
|
71
|
+
expect: 'readonly',
|
|
72
|
+
beforeEach: 'readonly',
|
|
73
|
+
afterEach: 'readonly',
|
|
74
|
+
before: 'readonly',
|
|
75
|
+
after: 'readonly',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
];
|
package/package.json
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-arktos",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "🚀 A modern Node.js backend boilerplate with TypeScript, Express, JWT authentication, Prisma ORM, PostgreSQL, and Resend email service. Includes complete authentication flow, security middleware, and database management.",
|
|
5
|
+
"main": "bin/cli.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-arktos": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"src/",
|
|
12
|
+
"prisma/",
|
|
13
|
+
"template.package.json",
|
|
14
|
+
".env.example",
|
|
15
|
+
"vercel.json",
|
|
16
|
+
"tsconfig.json",
|
|
17
|
+
"eslint.config.js",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc",
|
|
23
|
+
"start": "node bin/cli.js",
|
|
24
|
+
"dev": "ts-node --esm bin/cli.js",
|
|
25
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
26
|
+
"lint": "eslint . --ext .ts,.js",
|
|
27
|
+
"lint:fix": "eslint . --ext .ts,.js --fix",
|
|
28
|
+
"format": "prettier --write .",
|
|
29
|
+
"format:check": "prettier --check .",
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
|
+
"prepublishOnly": "echo 'Publishing arktos CLI tool...'",
|
|
32
|
+
"clean": "rm -rf dist"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"nodejs",
|
|
36
|
+
"typescript",
|
|
37
|
+
"express",
|
|
38
|
+
"jwt",
|
|
39
|
+
"authentication",
|
|
40
|
+
"prisma",
|
|
41
|
+
"orm",
|
|
42
|
+
"postgresql",
|
|
43
|
+
"database",
|
|
44
|
+
"resend",
|
|
45
|
+
"email",
|
|
46
|
+
"auth",
|
|
47
|
+
"security",
|
|
48
|
+
"middleware",
|
|
49
|
+
"boilerplate",
|
|
50
|
+
"template",
|
|
51
|
+
"generator",
|
|
52
|
+
"cli",
|
|
53
|
+
"backend",
|
|
54
|
+
"api",
|
|
55
|
+
"rest",
|
|
56
|
+
"starter",
|
|
57
|
+
"scaffold"
|
|
58
|
+
],
|
|
59
|
+
"author": {
|
|
60
|
+
"name": "Zafer Gök",
|
|
61
|
+
"email": "gok.zaferr@gmail.com",
|
|
62
|
+
"url": "https://github.com/zzafergok"
|
|
63
|
+
},
|
|
64
|
+
"license": "MIT",
|
|
65
|
+
"engines": {
|
|
66
|
+
"node": ">=18.0.0",
|
|
67
|
+
"npm": ">=8.0.0"
|
|
68
|
+
},
|
|
69
|
+
"repository": {
|
|
70
|
+
"type": "git",
|
|
71
|
+
"url": "git+https://github.com/zzafergok/arktos.git"
|
|
72
|
+
},
|
|
73
|
+
"bugs": {
|
|
74
|
+
"url": "https://github.com/zzafergok/arktos/issues"
|
|
75
|
+
},
|
|
76
|
+
"homepage": "https://github.com/zzafergok/arktos#readme",
|
|
77
|
+
"funding": {
|
|
78
|
+
"type": "github",
|
|
79
|
+
"url": "https://github.com/sponsors/zzafergok"
|
|
80
|
+
},
|
|
81
|
+
"publishConfig": {
|
|
82
|
+
"access": "public",
|
|
83
|
+
"registry": "https://registry.npmjs.org/"
|
|
84
|
+
},
|
|
85
|
+
"dependencies": {
|
|
86
|
+
"chalk": "^5.3.0",
|
|
87
|
+
"commander": "^12.0.0",
|
|
88
|
+
"inquirer": "^10.0.0",
|
|
89
|
+
"ora": "^8.0.1",
|
|
90
|
+
"fs-extra": "^11.2.0"
|
|
91
|
+
},
|
|
92
|
+
"devDependencies": {
|
|
93
|
+
"@types/fs-extra": "^11.0.4",
|
|
94
|
+
"@types/inquirer": "^9.0.7",
|
|
95
|
+
"@types/node": "^22.0.0",
|
|
96
|
+
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
97
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
98
|
+
"eslint": "^9.0.0",
|
|
99
|
+
"eslint-config-prettier": "^9.0.0",
|
|
100
|
+
"eslint-plugin-prettier": "^5.0.0",
|
|
101
|
+
"prettier": "^3.3.0",
|
|
102
|
+
"ts-node": "^10.9.2",
|
|
103
|
+
"typescript": "^5.5.0"
|
|
104
|
+
},
|
|
105
|
+
"peerDependencies": {
|
|
106
|
+
"typescript": ">=4.7.0"
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
generator client {
|
|
2
|
+
provider = "prisma-client-js"
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
datasource db {
|
|
6
|
+
provider = "postgresql"
|
|
7
|
+
url = env("DATABASE_URL")
|
|
8
|
+
directUrl = env("DIRECT_URL")
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
enum Role {
|
|
12
|
+
USER
|
|
13
|
+
ADMIN
|
|
14
|
+
MODERATOR
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
enum LoginType {
|
|
18
|
+
EMAIL
|
|
19
|
+
GOOGLE
|
|
20
|
+
GITHUB
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
enum EmailVerificationStatus {
|
|
24
|
+
PENDING
|
|
25
|
+
VERIFIED
|
|
26
|
+
EXPIRED
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
model User {
|
|
30
|
+
id String @id @default(cuid())
|
|
31
|
+
email String @unique
|
|
32
|
+
username String? @unique
|
|
33
|
+
firstName String?
|
|
34
|
+
lastName String?
|
|
35
|
+
avatar String?
|
|
36
|
+
password String?
|
|
37
|
+
role Role @default(USER)
|
|
38
|
+
isActive Boolean @default(true)
|
|
39
|
+
isEmailVerified Boolean @default(false)
|
|
40
|
+
emailVerifiedAt DateTime?
|
|
41
|
+
lastLoginAt DateTime?
|
|
42
|
+
createdAt DateTime @default(now())
|
|
43
|
+
updatedAt DateTime @updatedAt
|
|
44
|
+
|
|
45
|
+
// Relations
|
|
46
|
+
loginLogs LoginLog[]
|
|
47
|
+
emailVerifications EmailVerification[]
|
|
48
|
+
refreshTokens RefreshToken[]
|
|
49
|
+
passwordResets PasswordReset[]
|
|
50
|
+
|
|
51
|
+
@@map("users")
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
model LoginLog {
|
|
55
|
+
id String @id @default(cuid())
|
|
56
|
+
userId String
|
|
57
|
+
loginType LoginType @default(EMAIL)
|
|
58
|
+
ipAddress String?
|
|
59
|
+
userAgent String?
|
|
60
|
+
location String?
|
|
61
|
+
isSuccess Boolean @default(true)
|
|
62
|
+
failReason String?
|
|
63
|
+
createdAt DateTime @default(now())
|
|
64
|
+
|
|
65
|
+
// Relations
|
|
66
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
67
|
+
|
|
68
|
+
@@map("login_logs")
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
model EmailVerification {
|
|
72
|
+
id String @id @default(cuid())
|
|
73
|
+
userId String
|
|
74
|
+
token String @unique
|
|
75
|
+
email String
|
|
76
|
+
status EmailVerificationStatus @default(PENDING)
|
|
77
|
+
expiresAt DateTime
|
|
78
|
+
createdAt DateTime @default(now())
|
|
79
|
+
|
|
80
|
+
// Relations
|
|
81
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
82
|
+
|
|
83
|
+
@@map("email_verifications")
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
model PasswordReset {
|
|
87
|
+
id String @id @default(cuid())
|
|
88
|
+
userId String
|
|
89
|
+
token String @unique
|
|
90
|
+
isUsed Boolean @default(false)
|
|
91
|
+
expiresAt DateTime
|
|
92
|
+
createdAt DateTime @default(now())
|
|
93
|
+
|
|
94
|
+
// Relations
|
|
95
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
96
|
+
|
|
97
|
+
@@map("password_resets")
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
model RefreshToken {
|
|
101
|
+
id String @id @default(cuid())
|
|
102
|
+
userId String
|
|
103
|
+
token String @unique
|
|
104
|
+
isRevoked Boolean @default(false)
|
|
105
|
+
expiresAt DateTime
|
|
106
|
+
createdAt DateTime @default(now())
|
|
107
|
+
|
|
108
|
+
// Relations
|
|
109
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
110
|
+
|
|
111
|
+
@@map("refresh_tokens")
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
model Booking {
|
|
115
|
+
id String @id @default(cuid())
|
|
116
|
+
userId String
|
|
117
|
+
title String
|
|
118
|
+
description String?
|
|
119
|
+
startDate DateTime
|
|
120
|
+
endDate DateTime
|
|
121
|
+
status String @default("PENDING")
|
|
122
|
+
totalAmount Decimal? @db.Decimal(10, 2)
|
|
123
|
+
createdAt DateTime @default(now())
|
|
124
|
+
updatedAt DateTime @updatedAt
|
|
125
|
+
|
|
126
|
+
@@map("bookings")
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
model Product {
|
|
130
|
+
id String @id @default(cuid())
|
|
131
|
+
name String
|
|
132
|
+
description String?
|
|
133
|
+
price Decimal @db.Decimal(10, 2)
|
|
134
|
+
category String?
|
|
135
|
+
isActive Boolean @default(true)
|
|
136
|
+
stock Int @default(0)
|
|
137
|
+
images String[]
|
|
138
|
+
createdAt DateTime @default(now())
|
|
139
|
+
updatedAt DateTime @updatedAt
|
|
140
|
+
|
|
141
|
+
@@map("products")
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
model Blog {
|
|
145
|
+
id String @id @default(cuid())
|
|
146
|
+
title String
|
|
147
|
+
slug String @unique
|
|
148
|
+
content String
|
|
149
|
+
excerpt String?
|
|
150
|
+
isPublished Boolean @default(false)
|
|
151
|
+
authorId String?
|
|
152
|
+
tags String[]
|
|
153
|
+
createdAt DateTime @default(now())
|
|
154
|
+
updatedAt DateTime @updatedAt
|
|
155
|
+
|
|
156
|
+
@@map("blogs")
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
model Payment {
|
|
160
|
+
id String @id @default(cuid())
|
|
161
|
+
userId String?
|
|
162
|
+
amount Decimal @db.Decimal(10, 2)
|
|
163
|
+
currency String @default("USD")
|
|
164
|
+
status String @default("PENDING")
|
|
165
|
+
paymentMethod String?
|
|
166
|
+
transactionId String? @unique
|
|
167
|
+
metadata Json?
|
|
168
|
+
createdAt DateTime @default(now())
|
|
169
|
+
updatedAt DateTime @updatedAt
|
|
170
|
+
|
|
171
|
+
@@map("payments")
|
|
172
|
+
}
|