sat startup script for local development

This commit is contained in:
Dmitri 2026-06-26 08:23:11 +02:00
parent 9802a1d131
commit b43c1cd5b4
7 changed files with 70 additions and 34 deletions

View File

@ -47,7 +47,7 @@ PGPASSWORD='postgres' psql -U postgres -c "CREATE DATABASE app_39215 OWNER app_3
```bash
cd backend
yarn install
export $(cat .env | xargs) && NODE_ENV=production yarn start
npm run start-dev
```
Backend runs on **http://localhost:8080**

View File

@ -28,7 +28,7 @@ yarn install
yarn db:create
# 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.

View File

@ -3,6 +3,7 @@
"description": "Tour Builder Platform - template backend",
"scripts": {
"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",
"db:migrate": "sequelize-cli db:migrate",
"db:migrate:undo": "sequelize-cli db:migrate:undo",

View File

@ -9,7 +9,6 @@ const config = require('../db.config')[env];
const db = {};
let sequelize;
console.log(env);
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {

View File

@ -1,5 +1,6 @@
const ValidationError = require('../services/notifications/errors/validation');
const RolesDBApi = require('../db/api/roles');
const { logger } = require('../utils/logger');
// Cache for the 'Public' role object
let publicRoleCache = null;
@ -11,17 +12,21 @@ async function fetchAndCachePublicRole() {
publicRoleCache = await RolesDBApi.findBy({ name: 'Public' });
if (!publicRoleCache) {
console.error(
"WARNING: Role 'Public' not found in database during middleware startup. Check your migrations.",
logger.warn(
{ 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.
} else {
console.log("'Public' role successfully loaded and cached.");
logger.info(
{ role: 'Public', roleId: publicRoleCache.id },
'Role loaded and cached',
);
}
} catch (error) {
console.error(
"Error fetching 'Public' role during middleware startup:",
error,
logger.error(
{ err: error, role: 'Public' },
'Error fetching role during permissions middleware startup',
);
// Handle the error during startup fetch
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.
fetchAndCachePublicRole().catch((error) => {
// Handle the case where the fetchAndCachePublicRole promise is rejected
console.error(
'Critical error during permissions middleware initialization:',
error,
logger.error(
{ err: error },
'Critical error during permissions middleware initialization',
);
});
@ -81,8 +86,10 @@ function checkPermissions(permission) {
if (!publicRoleCache) {
// 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.
console.error(
'Public role cache is empty. Attempting synchronous fetch...',
const log = req.log || logger;
log.warn(
{ role: 'Public' },
'Role cache is empty, attempting synchronous fetch',
);
// Less efficient fallback option:
effectiveRole = await RolesDBApi.findBy({ name: 'Public' }); // Could be slow
@ -117,9 +124,10 @@ function checkPermissions(permission) {
} else if (Array.isArray(effectiveRole.permissions)) {
rolePermissions = effectiveRole.permissions; // Or take from property if permissions are pre-loaded
} else {
console.error(
'Role object lacks getPermissions() method or permissions property:',
effectiveRole,
const log = req.log || logger;
log.error(
{ roleId: effectiveRole.id, roleName: effectiveRole.name },
'Role object lacks getPermissions method or permissions property',
);
return next(
new Error('Internal Server Error: Invalid role object format.'),
@ -140,7 +148,8 @@ function checkPermissions(permission) {
}
} catch (e) {
// 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
}
};

View File

@ -1,12 +1,21 @@
const pino = require('pino');
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({
level: process.env.LOG_LEVEL || 'info',
transport: isDevelopment
? { target: 'pino-pretty', options: { colorize: true } }
transport: shouldPrettyPrint
? {
target: 'pino-pretty',
options: {
colorize: true,
ignore: 'pid,hostname',
messageFormat: '{service} | {msg}',
translateTime: 'SYS:yyyy-mm-dd HH:MM:ss.l',
},
}
: undefined,
base: {
service: 'tour-builder-api',
@ -27,7 +36,7 @@ function requestLogger(req, res, next) {
method: req.method,
url: req.originalUrl || req.url,
status: res.statusCode,
duration,
durationMs: duration,
userAgent: req.headers['user-agent'],
};

View File

@ -1,21 +1,38 @@
const chokidar = require('chokidar');
const { exec } = require('child_process');
const nodemon = require('nodemon');
const { logger } = require('./src/utils/logger');
const nodeEnv = process.env.NODE_ENV || 'dev_stage';
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', {
persistent: true,
ignoreInitial: true
});
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) => {
console.log(stdout);
if (error) {
console.error(stderr);
}
logCommandResult(error, stdout, stderr, 'Migration command completed');
});
});
@ -24,12 +41,9 @@ const seedersWatcher = chokidar.watch('./src/db/seeders', {
ignoreInitial: true
});
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) => {
console.log(stdout);
if (error) {
console.error(stderr);
}
logCommandResult(error, stdout, stderr, 'Seeder command completed');
});
});
@ -41,9 +55,13 @@ nodemon({
});
nodemon.on('start', () => {
console.log('Nodemon started');
log.info({ nodeEnv }, 'Nodemon started');
});
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');
});