create-fullstack-boilerplate 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/README.md +390 -0
- package/index.js +78 -0
- package/lib/addDB.js +77 -0
- package/lib/addRoute.js +264 -0
- package/lib/copyProject.js +25 -0
- package/lib/dataTypes.js +79 -0
- package/lib/installDeps.js +11 -0
- package/lib/prompts.js +289 -0
- package/lib/setupExtraDB.js +172 -0
- package/lib/setupMainDB.js +9 -0
- package/lib/testDBConnection.js +31 -0
- package/lib/utils.js +39 -0
- package/package.json +45 -0
- package/template/Backend/.env +7 -0
- package/template/Backend/DB/DBInit.js +28 -0
- package/template/Backend/DB/dbConfigs.js +4 -0
- package/template/Backend/Models/index.js +54 -0
- package/template/Backend/README.md +535 -0
- package/template/Backend/middleware/authMiddleware.js +19 -0
- package/template/Backend/package-lock.json +2997 -0
- package/template/Backend/package.json +32 -0
- package/template/Backend/routes/authRoutes.js +15 -0
- package/template/Backend/routes/dashboardRoutes.js +13 -0
- package/template/Backend/routes/index.js +15 -0
- package/template/Backend/routes/settingsRoutes.js +9 -0
- package/template/Backend/server.js +70 -0
- package/template/Backend/services/authService.js +68 -0
- package/template/Backend/services/cryptoService.js +14 -0
- package/template/Backend/services/dashboardService.js +39 -0
- package/template/Backend/services/settingsService.js +43 -0
- package/template/Frontend/.env +3 -0
- package/template/Frontend/README.md +576 -0
- package/template/Frontend/eslint.config.js +29 -0
- package/template/Frontend/index.html +13 -0
- package/template/Frontend/package-lock.json +3690 -0
- package/template/Frontend/package.json +39 -0
- package/template/Frontend/public/PMDLogo.png +0 -0
- package/template/Frontend/public/pp.jpg +0 -0
- package/template/Frontend/public/tabicon.png +0 -0
- package/template/Frontend/src/App.jsx +71 -0
- package/template/Frontend/src/assets/fonts/ArticulatCFDemiBold/font.woff +0 -0
- package/template/Frontend/src/assets/fonts/ArticulatCFDemiBold/font.woff2 +0 -0
- package/template/Frontend/src/assets/fonts/ArticulatCFNormal/font.woff +0 -0
- package/template/Frontend/src/assets/fonts/ArticulatCFNormal/font.woff2 +0 -0
- package/template/Frontend/src/assets/fonts/ArticulatCFRegular/font.woff +0 -0
- package/template/Frontend/src/assets/fonts/ArticulatCFRegular/font.woff2 +0 -0
- package/template/Frontend/src/assets/fonts/MixtaProRegularItalic/font.woff +0 -0
- package/template/Frontend/src/assets/fonts/MixtaProRegularItalic/font.woff2 +0 -0
- package/template/Frontend/src/assets/fonts/fonts_sohne/OTF/S/303/266hneMono-Buch.otf +0 -0
- package/template/Frontend/src/assets/fonts/fonts_sohne/OTF/S/303/266hneMono-Leicht.otf +0 -0
- package/template/Frontend/src/assets/fonts/fonts_sohne/WOFF2/soehne-mono-buch.woff2 +0 -0
- package/template/Frontend/src/assets/fonts/fonts_sohne/WOFF2/soehne-mono-leicht.woff2 +0 -0
- package/template/Frontend/src/components/Layout.jsx +61 -0
- package/template/Frontend/src/components/Loader.jsx +19 -0
- package/template/Frontend/src/components/ProtectedRoute.jsx +19 -0
- package/template/Frontend/src/components/Sidebar.jsx +286 -0
- package/template/Frontend/src/components/ThemeToggle.jsx +30 -0
- package/template/Frontend/src/config/axiosClient.js +46 -0
- package/template/Frontend/src/config/encryption.js +11 -0
- package/template/Frontend/src/config/routes.js +65 -0
- package/template/Frontend/src/contexts/AuthContext.jsx +144 -0
- package/template/Frontend/src/contexts/ThemeContext.jsx +69 -0
- package/template/Frontend/src/index.css +88 -0
- package/template/Frontend/src/main.jsx +11 -0
- package/template/Frontend/src/pages/Dashboard.jsx +137 -0
- package/template/Frontend/src/pages/Login.jsx +195 -0
- package/template/Frontend/src/pages/NotFound.jsx +70 -0
- package/template/Frontend/src/pages/Settings.jsx +69 -0
- package/template/Frontend/tailwind.config.js +90 -0
- package/template/Frontend/vite.config.js +37 -0
- package/template/Readme.md +0 -0
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
# Backend Documentation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This is the backend of your fullstack application built with **Node.js**, **Express**, and **Sequelize ORM**. It provides a scalable, maintainable structure for building RESTful APIs with multiple database support.
|
|
6
|
+
|
|
7
|
+
## ๐๏ธ Project Structure
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
backend/
|
|
11
|
+
โโโ DB/ # Database configurations
|
|
12
|
+
โ โโโ DBInit.js # Database connection initialization with retry logic
|
|
13
|
+
โ โโโ dbConfigs.js # Array of all database configurations
|
|
14
|
+
โโโ Models/ # Sequelize models organized by database
|
|
15
|
+
โ โโโ index.js # Exports all database connections
|
|
16
|
+
โ โโโ [DB_NAME]/ # Folder for each database
|
|
17
|
+
โ โโโ [model].js # Individual model files
|
|
18
|
+
โโโ routes/ # API route definitions
|
|
19
|
+
โ โโโ index.js # Main router that combines all routes
|
|
20
|
+
โ โโโ authRoutes.js # Authentication endpoints
|
|
21
|
+
โ โโโ dashboardRoutes.js # Dashboard endpoints
|
|
22
|
+
โ โโโ settingsRoutes.js # Settings endpoints
|
|
23
|
+
โโโ services/ # Business logic layer
|
|
24
|
+
โ โโโ authService.js # Authentication business logic
|
|
25
|
+
โ โโโ cryptoService.js # Encryption/decryption utilities
|
|
26
|
+
โ โโโ dashboardService.js # Dashboard business logic
|
|
27
|
+
โ โโโ settingsService.js # Settings business logic
|
|
28
|
+
โโโ middleware/ # Express middleware
|
|
29
|
+
โ โโโ authMiddleware.js # JWT authentication middleware
|
|
30
|
+
โโโ .env # Environment variables
|
|
31
|
+
โโโ package.json # Dependencies and scripts
|
|
32
|
+
โโโ server.js # Main application entry point
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## ๐ Getting Started
|
|
36
|
+
|
|
37
|
+
### Prerequisites
|
|
38
|
+
|
|
39
|
+
- Node.js >= 20
|
|
40
|
+
- npm or yarn
|
|
41
|
+
- MySQL, MariaDB, or PostgreSQL database server
|
|
42
|
+
|
|
43
|
+
### Installation
|
|
44
|
+
|
|
45
|
+
Dependencies are automatically installed during project creation. To reinstall:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm install
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Environment Variables
|
|
52
|
+
|
|
53
|
+
Configure your environment variables in the `.env` file:
|
|
54
|
+
|
|
55
|
+
```env
|
|
56
|
+
# Server Configuration
|
|
57
|
+
PORT=5000
|
|
58
|
+
CLIENT_URL=http://localhost:5173
|
|
59
|
+
|
|
60
|
+
# Security
|
|
61
|
+
JWT_SECRET=your_jwt_secret_key
|
|
62
|
+
PASSWORD_ENCRYPTION_KEY=your_encryption_key
|
|
63
|
+
|
|
64
|
+
# Database Configuration (if you added databases)
|
|
65
|
+
YOUR_DB_USER=username
|
|
66
|
+
YOUR_DB_PASSWORD=password
|
|
67
|
+
YOUR_DB_NAME=database_name
|
|
68
|
+
YOUR_DB_HOST=localhost
|
|
69
|
+
YOUR_DB_PORT=3306
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Running the Server
|
|
73
|
+
|
|
74
|
+
**Development mode** (with auto-reload):
|
|
75
|
+
```bash
|
|
76
|
+
npm run dev
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Production mode**:
|
|
80
|
+
```bash
|
|
81
|
+
npm start
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The server will start on `http://localhost:5000` (or the PORT specified in .env).
|
|
85
|
+
|
|
86
|
+
## ๐๏ธ Working with Databases
|
|
87
|
+
|
|
88
|
+
### Multiple Database Support
|
|
89
|
+
|
|
90
|
+
This backend supports connecting to multiple databases simultaneously. Each database has its own:
|
|
91
|
+
- Configuration file in `DB/`
|
|
92
|
+
- Models folder in `Models/[DB_NAME]/`
|
|
93
|
+
- Environment variables
|
|
94
|
+
|
|
95
|
+
### Database Configuration
|
|
96
|
+
|
|
97
|
+
All databases are registered in `DB/dbConfigs.js`:
|
|
98
|
+
|
|
99
|
+
```javascript
|
|
100
|
+
const dbConfigs = [
|
|
101
|
+
{
|
|
102
|
+
key: "MAIN_DB", // Identifier used in code
|
|
103
|
+
folder: "MAIN_DB", // Folder name in Models/
|
|
104
|
+
configPath: "/../DB/MAIN_DB.config.js" // Path to config file
|
|
105
|
+
},
|
|
106
|
+
// Add more databases here...
|
|
107
|
+
];
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Adding a New Database
|
|
111
|
+
|
|
112
|
+
Use the CLI command:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
npx create-fullstack-app add-db
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
This will:
|
|
119
|
+
1. Prompt for database credentials
|
|
120
|
+
2. Test the connection
|
|
121
|
+
3. Create configuration files
|
|
122
|
+
4. Generate a sample model
|
|
123
|
+
5. Update environment variables
|
|
124
|
+
|
|
125
|
+
### Importing and Using Databases
|
|
126
|
+
|
|
127
|
+
#### Import All Databases
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
const databases = require('./Models');
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The `databases` object contains all your database connections:
|
|
134
|
+
|
|
135
|
+
```javascript
|
|
136
|
+
{
|
|
137
|
+
MAIN_DB: {
|
|
138
|
+
sequelize: [Sequelize Instance],
|
|
139
|
+
Sequelize: [Sequelize Class],
|
|
140
|
+
User: [User Model],
|
|
141
|
+
Product: [Product Model],
|
|
142
|
+
// ... other models
|
|
143
|
+
},
|
|
144
|
+
REPORTING_DB: {
|
|
145
|
+
sequelize: [Sequelize Instance],
|
|
146
|
+
Sequelize: [Sequelize Class],
|
|
147
|
+
Report: [Report Model],
|
|
148
|
+
// ... other models
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
#### Import a Specific Database
|
|
154
|
+
|
|
155
|
+
```javascript
|
|
156
|
+
const { MAIN_DB } = require('./Models');
|
|
157
|
+
|
|
158
|
+
// Access models
|
|
159
|
+
const { User, Product } = MAIN_DB;
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
#### Import a Specific Model
|
|
163
|
+
|
|
164
|
+
```javascript
|
|
165
|
+
const { MAIN_DB } = require('./Models');
|
|
166
|
+
const User = MAIN_DB.User;
|
|
167
|
+
|
|
168
|
+
// Or destructure directly
|
|
169
|
+
const { User, Product } = require('./Models').MAIN_DB;
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Using Sequelize Commands
|
|
173
|
+
|
|
174
|
+
#### Create a New Record
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
const { MAIN_DB } = require('./Models');
|
|
178
|
+
const { User } = MAIN_DB;
|
|
179
|
+
|
|
180
|
+
// Create
|
|
181
|
+
const newUser = await User.create({
|
|
182
|
+
username: 'john_doe',
|
|
183
|
+
email: 'john@example.com',
|
|
184
|
+
password: 'hashed_password'
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
#### Find Records
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
// Find all
|
|
192
|
+
const allUsers = await User.findAll();
|
|
193
|
+
|
|
194
|
+
// Find with conditions
|
|
195
|
+
const activeUsers = await User.findAll({
|
|
196
|
+
where: { status: 'active' }
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// Find one by primary key
|
|
200
|
+
const user = await User.findByPk(1);
|
|
201
|
+
|
|
202
|
+
// Find one with condition
|
|
203
|
+
const user = await User.findOne({
|
|
204
|
+
where: { email: 'john@example.com' }
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
#### Update Records
|
|
209
|
+
|
|
210
|
+
```javascript
|
|
211
|
+
// Update instance
|
|
212
|
+
const user = await User.findByPk(1);
|
|
213
|
+
await user.update({ username: 'new_username' });
|
|
214
|
+
|
|
215
|
+
// Bulk update
|
|
216
|
+
await User.update(
|
|
217
|
+
{ status: 'inactive' },
|
|
218
|
+
{ where: { lastLogin: { [Op.lt]: new Date('2023-01-01') } } }
|
|
219
|
+
);
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
#### Delete Records
|
|
223
|
+
|
|
224
|
+
```javascript
|
|
225
|
+
// Delete instance
|
|
226
|
+
const user = await User.findByPk(1);
|
|
227
|
+
await user.destroy();
|
|
228
|
+
|
|
229
|
+
// Bulk delete
|
|
230
|
+
await User.destroy({
|
|
231
|
+
where: { status: 'deleted' }
|
|
232
|
+
});
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
#### Complex Queries
|
|
236
|
+
|
|
237
|
+
```javascript
|
|
238
|
+
const { Op } = require('sequelize');
|
|
239
|
+
|
|
240
|
+
// Where operators
|
|
241
|
+
const users = await User.findAll({
|
|
242
|
+
where: {
|
|
243
|
+
age: { [Op.gte]: 18 },
|
|
244
|
+
status: { [Op.in]: ['active', 'pending'] },
|
|
245
|
+
email: { [Op.like]: '%@gmail.com' }
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Ordering
|
|
250
|
+
const sortedUsers = await User.findAll({
|
|
251
|
+
order: [['createdAt', 'DESC']]
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// Limiting and pagination
|
|
255
|
+
const page = 1;
|
|
256
|
+
const limit = 10;
|
|
257
|
+
const offset = (page - 1) * limit;
|
|
258
|
+
|
|
259
|
+
const paginatedUsers = await User.findAndCountAll({
|
|
260
|
+
limit,
|
|
261
|
+
offset
|
|
262
|
+
});
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
#### Associations
|
|
266
|
+
|
|
267
|
+
```javascript
|
|
268
|
+
// Define associations in your model file
|
|
269
|
+
User.associate = function(models) {
|
|
270
|
+
User.hasMany(models.Post, { foreignKey: 'userId' });
|
|
271
|
+
User.belongsTo(models.Role, { foreignKey: 'roleId' });
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
// Query with associations
|
|
275
|
+
const userWithPosts = await User.findOne({
|
|
276
|
+
where: { id: 1 },
|
|
277
|
+
include: [{
|
|
278
|
+
model: Post,
|
|
279
|
+
as: 'posts'
|
|
280
|
+
}]
|
|
281
|
+
});
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
#### Transactions
|
|
285
|
+
|
|
286
|
+
```javascript
|
|
287
|
+
const { sequelize } = MAIN_DB;
|
|
288
|
+
|
|
289
|
+
const t = await sequelize.transaction();
|
|
290
|
+
|
|
291
|
+
try {
|
|
292
|
+
const user = await User.create({
|
|
293
|
+
username: 'john'
|
|
294
|
+
}, { transaction: t });
|
|
295
|
+
|
|
296
|
+
await Post.create({
|
|
297
|
+
userId: user.id,
|
|
298
|
+
title: 'First Post'
|
|
299
|
+
}, { transaction: t });
|
|
300
|
+
|
|
301
|
+
await t.commit();
|
|
302
|
+
} catch (error) {
|
|
303
|
+
await t.rollback();
|
|
304
|
+
throw error;
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## ๐ฃ๏ธ Working with Routes
|
|
309
|
+
|
|
310
|
+
### Adding a New Route
|
|
311
|
+
|
|
312
|
+
Use the CLI command:
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
npx create-fullstack-app add-route
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
This will:
|
|
319
|
+
1. Prompt for route information
|
|
320
|
+
2. Create a route file in `routes/`
|
|
321
|
+
3. Create a service file in `services/`
|
|
322
|
+
4. Update `routes/index.js` automatically
|
|
323
|
+
|
|
324
|
+
### Route Structure
|
|
325
|
+
|
|
326
|
+
Routes should be thin and delegate logic to services:
|
|
327
|
+
|
|
328
|
+
```javascript
|
|
329
|
+
// routes/usersRoutes.js
|
|
330
|
+
const express = require('express');
|
|
331
|
+
const router = express.Router();
|
|
332
|
+
const { authenticateToken } = require('../middleware/authMiddleware');
|
|
333
|
+
const usersService = require('../services/usersService');
|
|
334
|
+
|
|
335
|
+
router.get('/', authenticateToken, usersService.getAll);
|
|
336
|
+
router.get('/:id', authenticateToken, usersService.getById);
|
|
337
|
+
router.post('/', authenticateToken, usersService.create);
|
|
338
|
+
router.put('/:id', authenticateToken, usersService.update);
|
|
339
|
+
router.delete('/:id', authenticateToken, usersService.delete);
|
|
340
|
+
|
|
341
|
+
module.exports = router;
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Service Structure
|
|
345
|
+
|
|
346
|
+
Services contain business logic:
|
|
347
|
+
|
|
348
|
+
```javascript
|
|
349
|
+
// services/usersService.js
|
|
350
|
+
const { MAIN_DB } = require('../Models');
|
|
351
|
+
const { User } = MAIN_DB;
|
|
352
|
+
|
|
353
|
+
exports.getAll = async (req, res) => {
|
|
354
|
+
try {
|
|
355
|
+
const users = await User.findAll();
|
|
356
|
+
res.json(users);
|
|
357
|
+
} catch (error) {
|
|
358
|
+
console.error('Error fetching users:', error);
|
|
359
|
+
res.status(500).json({ message: 'Error fetching users', error: error.message });
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
exports.getById = async (req, res) => {
|
|
364
|
+
try {
|
|
365
|
+
const { id } = req.params;
|
|
366
|
+
const user = await User.findByPk(id);
|
|
367
|
+
|
|
368
|
+
if (!user) {
|
|
369
|
+
return res.status(404).json({ message: 'User not found' });
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
res.json(user);
|
|
373
|
+
} catch (error) {
|
|
374
|
+
res.status(500).json({ message: 'Error fetching user', error: error.message });
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
## ๐ Authentication
|
|
380
|
+
|
|
381
|
+
The backend includes JWT-based authentication:
|
|
382
|
+
|
|
383
|
+
### Protecting Routes
|
|
384
|
+
|
|
385
|
+
```javascript
|
|
386
|
+
const { authenticateToken } = require('../middleware/authMiddleware');
|
|
387
|
+
|
|
388
|
+
router.get('/protected', authenticateToken, (req, res) => {
|
|
389
|
+
// req.user contains the decoded JWT payload
|
|
390
|
+
res.json({ message: 'This is protected', user: req.user });
|
|
391
|
+
});
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### Authentication Flow
|
|
395
|
+
|
|
396
|
+
1. User logs in via `/api/auth/login`
|
|
397
|
+
2. Server validates credentials and returns JWT token
|
|
398
|
+
3. Client stores token and sends it in subsequent requests
|
|
399
|
+
4. `authenticateToken` middleware verifies the token
|
|
400
|
+
|
|
401
|
+
## ๐ Model Creation
|
|
402
|
+
|
|
403
|
+
### Creating a New Model
|
|
404
|
+
|
|
405
|
+
Create a file in `Models/[DB_NAME]/modelName.js`:
|
|
406
|
+
|
|
407
|
+
```javascript
|
|
408
|
+
'use strict';
|
|
409
|
+
module.exports = (sequelize, DataTypes) => {
|
|
410
|
+
const User = sequelize.define('User', {
|
|
411
|
+
id: {
|
|
412
|
+
type: DataTypes.INTEGER,
|
|
413
|
+
primaryKey: true,
|
|
414
|
+
autoIncrement: true
|
|
415
|
+
},
|
|
416
|
+
username: {
|
|
417
|
+
type: DataTypes.STRING(50),
|
|
418
|
+
allowNull: false,
|
|
419
|
+
unique: true
|
|
420
|
+
},
|
|
421
|
+
email: {
|
|
422
|
+
type: DataTypes.STRING(100),
|
|
423
|
+
allowNull: false,
|
|
424
|
+
unique: true,
|
|
425
|
+
validate: {
|
|
426
|
+
isEmail: true
|
|
427
|
+
}
|
|
428
|
+
},
|
|
429
|
+
password: {
|
|
430
|
+
type: DataTypes.STRING(255),
|
|
431
|
+
allowNull: false
|
|
432
|
+
},
|
|
433
|
+
status: {
|
|
434
|
+
type: DataTypes.ENUM('active', 'inactive', 'suspended'),
|
|
435
|
+
defaultValue: 'active'
|
|
436
|
+
}
|
|
437
|
+
}, {
|
|
438
|
+
tableName: 'users',
|
|
439
|
+
timestamps: true // Adds createdAt and updatedAt
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
User.associate = function(models) {
|
|
443
|
+
// Define associations here
|
|
444
|
+
User.hasMany(models.Post, { foreignKey: 'userId', as: 'posts' });
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
return User;
|
|
448
|
+
};
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
### Data Types Reference
|
|
452
|
+
|
|
453
|
+
Common Sequelize data types:
|
|
454
|
+
|
|
455
|
+
- `DataTypes.STRING(length)` - VARCHAR
|
|
456
|
+
- `DataTypes.TEXT` - TEXT
|
|
457
|
+
- `DataTypes.INTEGER` - INTEGER
|
|
458
|
+
- `DataTypes.BIGINT` - BIGINT
|
|
459
|
+
- `DataTypes.FLOAT` - FLOAT
|
|
460
|
+
- `DataTypes.DOUBLE` - DOUBLE
|
|
461
|
+
- `DataTypes.DECIMAL(precision, scale)` - DECIMAL
|
|
462
|
+
- `DataTypes.BOOLEAN` - BOOLEAN
|
|
463
|
+
- `DataTypes.DATE` - DATETIME
|
|
464
|
+
- `DataTypes.DATEONLY` - DATE
|
|
465
|
+
- `DataTypes.JSON` - JSON
|
|
466
|
+
- `DataTypes.JSONB` - JSONB (PostgreSQL)
|
|
467
|
+
- `DataTypes.ENUM('value1', 'value2')` - ENUM
|
|
468
|
+
- `DataTypes.UUID` - UUID
|
|
469
|
+
|
|
470
|
+
## ๐งช Testing
|
|
471
|
+
|
|
472
|
+
Add your test files and update package.json with test scripts:
|
|
473
|
+
|
|
474
|
+
```bash
|
|
475
|
+
npm install --save-dev jest supertest
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
```javascript
|
|
479
|
+
// __tests__/users.test.js
|
|
480
|
+
const request = require('supertest');
|
|
481
|
+
const app = require('../server');
|
|
482
|
+
|
|
483
|
+
describe('User API', () => {
|
|
484
|
+
test('GET /api/users should return users', async () => {
|
|
485
|
+
const response = await request(app).get('/api/users');
|
|
486
|
+
expect(response.statusCode).toBe(200);
|
|
487
|
+
expect(Array.isArray(response.body)).toBe(true);
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
## ๐ Additional Resources
|
|
493
|
+
|
|
494
|
+
- [Express.js Documentation](https://expressjs.com/)
|
|
495
|
+
- [Sequelize Documentation](https://sequelize.org/)
|
|
496
|
+
- [Node.js Best Practices](https://github.com/goldbergyoni/nodebestpractices)
|
|
497
|
+
|
|
498
|
+
## ๐ค Contributing
|
|
499
|
+
|
|
500
|
+
When adding new features:
|
|
501
|
+
|
|
502
|
+
1. Create models in appropriate database folders
|
|
503
|
+
2. Create services for business logic
|
|
504
|
+
3. Create routes for API endpoints
|
|
505
|
+
4. Update this README if needed
|
|
506
|
+
5. Test your changes thoroughly
|
|
507
|
+
|
|
508
|
+
## ๐ Troubleshooting
|
|
509
|
+
|
|
510
|
+
### Database Connection Issues
|
|
511
|
+
|
|
512
|
+
- Verify credentials in `.env`
|
|
513
|
+
- Ensure database server is running
|
|
514
|
+
- Check network connectivity
|
|
515
|
+
- Review logs in the console
|
|
516
|
+
|
|
517
|
+
### Module Not Found Errors
|
|
518
|
+
|
|
519
|
+
```bash
|
|
520
|
+
npm install
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Port Already in Use
|
|
524
|
+
|
|
525
|
+
Change the PORT in `.env` or kill the process using the port:
|
|
526
|
+
|
|
527
|
+
```bash
|
|
528
|
+
# Windows
|
|
529
|
+
netstat -ano | findstr :5000
|
|
530
|
+
taskkill /PID <PID> /F
|
|
531
|
+
|
|
532
|
+
# Linux/Mac
|
|
533
|
+
lsof -i :5000
|
|
534
|
+
kill -9 <PID>
|
|
535
|
+
```
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const jwt = require('jsonwebtoken');
|
|
2
|
+
const JWT_SECRET = process.env.JWT_SECRET;
|
|
3
|
+
|
|
4
|
+
exports.authenticateToken = (req, res, next) => {
|
|
5
|
+
const authHeader = req.headers['authorization'];
|
|
6
|
+
const token = authHeader && authHeader.split(' ')[1];
|
|
7
|
+
|
|
8
|
+
if (!token) {
|
|
9
|
+
return res.status(401).json({ message: 'Access token required' });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
jwt.verify(token, JWT_SECRET, (err, user) => {
|
|
13
|
+
if (err) {
|
|
14
|
+
return res.status(403).json({ message: 'Invalid or expired token' });
|
|
15
|
+
}
|
|
16
|
+
req.user = user;
|
|
17
|
+
next();
|
|
18
|
+
});
|
|
19
|
+
};
|