sat startup script for local development
This commit is contained in:
parent
9802a1d131
commit
b43c1cd5b4
@ -47,7 +47,7 @@ PGPASSWORD='postgres' psql -U postgres -c "CREATE DATABASE app_39215 OWNER app_3
|
|||||||
```bash
|
```bash
|
||||||
cd backend
|
cd backend
|
||||||
yarn install
|
yarn install
|
||||||
export $(cat .env | xargs) && NODE_ENV=production yarn start
|
npm run start-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
Backend runs on **http://localhost:8080**
|
Backend runs on **http://localhost:8080**
|
||||||
|
|||||||
@ -28,7 +28,7 @@ yarn install
|
|||||||
yarn db:create
|
yarn db:create
|
||||||
|
|
||||||
# Start server (runs migrations, seeds, and watches for changes)
|
# Start server (runs migrations, seeds, and watches for changes)
|
||||||
export $(cat .env | xargs) && NODE_ENV=production yarn start
|
npm run start-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
The server runs on **port 8080** by default.
|
The server runs on **port 8080** by default.
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
"description": "Tour Builder Platform - template backend",
|
"description": "Tour Builder Platform - template backend",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "npm run db:migrate && npm run db:seed && npm run watch",
|
"start": "npm run db:migrate && npm run db:seed && npm run watch",
|
||||||
|
"start-dev": "cross-env NODE_ENV=production LOG_PRETTY=true DOTENV_CONFIG_PATH=.env NODE_OPTIONS=\"-r dotenv/config\" npm run start",
|
||||||
"lint": "eslint . --ext .js",
|
"lint": "eslint . --ext .js",
|
||||||
"db:migrate": "sequelize-cli db:migrate",
|
"db:migrate": "sequelize-cli db:migrate",
|
||||||
"db:migrate:undo": "sequelize-cli db:migrate:undo",
|
"db:migrate:undo": "sequelize-cli db:migrate:undo",
|
||||||
|
|||||||
@ -9,7 +9,6 @@ const config = require('../db.config')[env];
|
|||||||
const db = {};
|
const db = {};
|
||||||
|
|
||||||
let sequelize;
|
let sequelize;
|
||||||
console.log(env);
|
|
||||||
if (config.use_env_variable) {
|
if (config.use_env_variable) {
|
||||||
sequelize = new Sequelize(process.env[config.use_env_variable], config);
|
sequelize = new Sequelize(process.env[config.use_env_variable], config);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
const ValidationError = require('../services/notifications/errors/validation');
|
const ValidationError = require('../services/notifications/errors/validation');
|
||||||
const RolesDBApi = require('../db/api/roles');
|
const RolesDBApi = require('../db/api/roles');
|
||||||
|
const { logger } = require('../utils/logger');
|
||||||
|
|
||||||
// Cache for the 'Public' role object
|
// Cache for the 'Public' role object
|
||||||
let publicRoleCache = null;
|
let publicRoleCache = null;
|
||||||
@ -11,17 +12,21 @@ async function fetchAndCachePublicRole() {
|
|||||||
publicRoleCache = await RolesDBApi.findBy({ name: 'Public' });
|
publicRoleCache = await RolesDBApi.findBy({ name: 'Public' });
|
||||||
|
|
||||||
if (!publicRoleCache) {
|
if (!publicRoleCache) {
|
||||||
console.error(
|
logger.warn(
|
||||||
"WARNING: Role 'Public' not found in database during middleware startup. Check your migrations.",
|
{ role: 'Public' },
|
||||||
|
'Role not found during permissions middleware startup',
|
||||||
);
|
);
|
||||||
// The system might not function correctly without this role. May need to throw an error or use a fallback stub.
|
// The system might not function correctly without this role. May need to throw an error or use a fallback stub.
|
||||||
} else {
|
} else {
|
||||||
console.log("'Public' role successfully loaded and cached.");
|
logger.info(
|
||||||
|
{ role: 'Public', roleId: publicRoleCache.id },
|
||||||
|
'Role loaded and cached',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
logger.error(
|
||||||
"Error fetching 'Public' role during middleware startup:",
|
{ err: error, role: 'Public' },
|
||||||
error,
|
'Error fetching role during permissions middleware startup',
|
||||||
);
|
);
|
||||||
// Handle the error during startup fetch
|
// Handle the error during startup fetch
|
||||||
throw error; // Important to know if the app can proceed without the Public role
|
throw error; // Important to know if the app can proceed without the Public role
|
||||||
@ -32,9 +37,9 @@ async function fetchAndCachePublicRole() {
|
|||||||
// This should happen during application startup when routes are being configured.
|
// This should happen during application startup when routes are being configured.
|
||||||
fetchAndCachePublicRole().catch((error) => {
|
fetchAndCachePublicRole().catch((error) => {
|
||||||
// Handle the case where the fetchAndCachePublicRole promise is rejected
|
// Handle the case where the fetchAndCachePublicRole promise is rejected
|
||||||
console.error(
|
logger.error(
|
||||||
'Critical error during permissions middleware initialization:',
|
{ err: error },
|
||||||
error,
|
'Critical error during permissions middleware initialization',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -81,8 +86,10 @@ function checkPermissions(permission) {
|
|||||||
if (!publicRoleCache) {
|
if (!publicRoleCache) {
|
||||||
// If the cache is unexpectedly empty (e.g., startup error caught),
|
// If the cache is unexpectedly empty (e.g., startup error caught),
|
||||||
// we can try fetching the role again synchronously (less ideal) or just deny access.
|
// we can try fetching the role again synchronously (less ideal) or just deny access.
|
||||||
console.error(
|
const log = req.log || logger;
|
||||||
'Public role cache is empty. Attempting synchronous fetch...',
|
log.warn(
|
||||||
|
{ role: 'Public' },
|
||||||
|
'Role cache is empty, attempting synchronous fetch',
|
||||||
);
|
);
|
||||||
// Less efficient fallback option:
|
// Less efficient fallback option:
|
||||||
effectiveRole = await RolesDBApi.findBy({ name: 'Public' }); // Could be slow
|
effectiveRole = await RolesDBApi.findBy({ name: 'Public' }); // Could be slow
|
||||||
@ -117,9 +124,10 @@ function checkPermissions(permission) {
|
|||||||
} else if (Array.isArray(effectiveRole.permissions)) {
|
} else if (Array.isArray(effectiveRole.permissions)) {
|
||||||
rolePermissions = effectiveRole.permissions; // Or take from property if permissions are pre-loaded
|
rolePermissions = effectiveRole.permissions; // Or take from property if permissions are pre-loaded
|
||||||
} else {
|
} else {
|
||||||
console.error(
|
const log = req.log || logger;
|
||||||
'Role object lacks getPermissions() method or permissions property:',
|
log.error(
|
||||||
effectiveRole,
|
{ roleId: effectiveRole.id, roleName: effectiveRole.name },
|
||||||
|
'Role object lacks getPermissions method or permissions property',
|
||||||
);
|
);
|
||||||
return next(
|
return next(
|
||||||
new Error('Internal Server Error: Invalid role object format.'),
|
new Error('Internal Server Error: Invalid role object format.'),
|
||||||
@ -140,7 +148,8 @@ function checkPermissions(permission) {
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Handle errors during role or permission fetching
|
// Handle errors during role or permission fetching
|
||||||
console.error('Error during permission check:', e);
|
const log = req.log || logger;
|
||||||
|
log.error({ err: e, permission }, 'Error during permission check');
|
||||||
next(e); // Pass the error to the next middleware
|
next(e); // Pass the error to the next middleware
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,12 +1,21 @@
|
|||||||
const pino = require('pino');
|
const pino = require('pino');
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
|
|
||||||
const isDevelopment = process.env.NODE_ENV === 'development';
|
const shouldPrettyPrint =
|
||||||
|
process.env.LOG_PRETTY === 'true' || process.env.NODE_ENV === 'development';
|
||||||
|
|
||||||
const logger = pino({
|
const logger = pino({
|
||||||
level: process.env.LOG_LEVEL || 'info',
|
level: process.env.LOG_LEVEL || 'info',
|
||||||
transport: isDevelopment
|
transport: shouldPrettyPrint
|
||||||
? { target: 'pino-pretty', options: { colorize: true } }
|
? {
|
||||||
|
target: 'pino-pretty',
|
||||||
|
options: {
|
||||||
|
colorize: true,
|
||||||
|
ignore: 'pid,hostname',
|
||||||
|
messageFormat: '{service} | {msg}',
|
||||||
|
translateTime: 'SYS:yyyy-mm-dd HH:MM:ss.l',
|
||||||
|
},
|
||||||
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
base: {
|
base: {
|
||||||
service: 'tour-builder-api',
|
service: 'tour-builder-api',
|
||||||
@ -27,7 +36,7 @@ function requestLogger(req, res, next) {
|
|||||||
method: req.method,
|
method: req.method,
|
||||||
url: req.originalUrl || req.url,
|
url: req.originalUrl || req.url,
|
||||||
status: res.statusCode,
|
status: res.statusCode,
|
||||||
duration,
|
durationMs: duration,
|
||||||
userAgent: req.headers['user-agent'],
|
userAgent: req.headers['user-agent'],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,21 +1,38 @@
|
|||||||
const chokidar = require('chokidar');
|
const chokidar = require('chokidar');
|
||||||
const { exec } = require('child_process');
|
const { exec } = require('child_process');
|
||||||
const nodemon = require('nodemon');
|
const nodemon = require('nodemon');
|
||||||
|
const { logger } = require('./src/utils/logger');
|
||||||
|
|
||||||
const nodeEnv = process.env.NODE_ENV || 'dev_stage';
|
const nodeEnv = process.env.NODE_ENV || 'dev_stage';
|
||||||
const childEnv = { ...process.env, NODE_ENV: nodeEnv };
|
const childEnv = { ...process.env, NODE_ENV: nodeEnv };
|
||||||
|
const log = logger.child({ module: 'watcher' });
|
||||||
|
|
||||||
|
function logCommandResult(error, stdout, stderr, successMessage) {
|
||||||
|
const output = stdout && stdout.trim();
|
||||||
|
const errorOutput = stderr && stderr.trim();
|
||||||
|
|
||||||
|
if (output) {
|
||||||
|
log.info({ output }, successMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
log.error(
|
||||||
|
{ err: error, stderr: errorOutput },
|
||||||
|
'Watched database command failed',
|
||||||
|
);
|
||||||
|
} else if (errorOutput) {
|
||||||
|
log.warn({ stderr: errorOutput }, 'Watched database command wrote stderr');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const migrationsWatcher = chokidar.watch('./src/db/migrations', {
|
const migrationsWatcher = chokidar.watch('./src/db/migrations', {
|
||||||
persistent: true,
|
persistent: true,
|
||||||
ignoreInitial: true
|
ignoreInitial: true
|
||||||
});
|
});
|
||||||
migrationsWatcher.on('add', (filePath) => {
|
migrationsWatcher.on('add', (filePath) => {
|
||||||
console.log(`[DEBUG] New migration file: ${filePath}`);
|
log.info({ filePath }, 'New migration file detected');
|
||||||
exec('npm run db:migrate', { env: childEnv }, (error, stdout, stderr) => {
|
exec('npm run db:migrate', { env: childEnv }, (error, stdout, stderr) => {
|
||||||
console.log(stdout);
|
logCommandResult(error, stdout, stderr, 'Migration command completed');
|
||||||
if (error) {
|
|
||||||
console.error(stderr);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -24,12 +41,9 @@ const seedersWatcher = chokidar.watch('./src/db/seeders', {
|
|||||||
ignoreInitial: true
|
ignoreInitial: true
|
||||||
});
|
});
|
||||||
seedersWatcher.on('add', (filePath) => {
|
seedersWatcher.on('add', (filePath) => {
|
||||||
console.log(`[DEBUG] New seed file: ${filePath}`);
|
log.info({ filePath }, 'New seed file detected');
|
||||||
exec('npm run db:seed', { env: childEnv }, (error, stdout, stderr) => {
|
exec('npm run db:seed', { env: childEnv }, (error, stdout, stderr) => {
|
||||||
console.log(stdout);
|
logCommandResult(error, stdout, stderr, 'Seeder command completed');
|
||||||
if (error) {
|
|
||||||
console.error(stderr);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -41,9 +55,13 @@ nodemon({
|
|||||||
});
|
});
|
||||||
|
|
||||||
nodemon.on('start', () => {
|
nodemon.on('start', () => {
|
||||||
console.log('Nodemon started');
|
log.info({ nodeEnv }, 'Nodemon started');
|
||||||
});
|
});
|
||||||
|
|
||||||
nodemon.on('restart', (files) => {
|
nodemon.on('restart', (files) => {
|
||||||
console.log('Nodemon restarted due changes in:', files);
|
log.info({ files }, 'Nodemon restarted due to file changes');
|
||||||
|
});
|
||||||
|
|
||||||
|
nodemon.on('crash', () => {
|
||||||
|
log.error('Nodemon app crashed');
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user