fix(deploy): force PM2 restart backone-frontend with --update-env
This commit is contained in:
1 parent
1a913716a2
commit
b829cf540b
3 files changed
+103
-1
No files matched your search
@@ -21,6 +21,10 @@ under a heading per module/section, matching `plans/next-enhancements.md`.
|
||||
taken, what succeeded/failed, the resulting state, and considerations for next
|
||||
time. See AGENTS.md §2b. — shipped 2026-07-08
|
||||
|
||||
## User Accounts & Authentication
|
||||
|
||||
- **Ad-hoc** Implemented 3-Attempt Rate Limiting, 15-Minute Account Lockout & Admin Manual Unlock System: (1) Enforced maximum 3 failed password attempts before locking account for 15 minutes, (2) Returned exact remaining attempts warnings (`Invalid password. 2 attempts remaining before lockout.`), (3) Added real-time countdown timer (`mm:ss`) to login page with input/button locking during lockout, (4) Added `Locked 🔒` status badge and `Unlock 🔓` action button in `/user-accounts` table for Superadmin and Tenant Admins. — shipped 2026-07-31
|
||||
|
||||
## Agents Management
|
||||
|
||||
- **Ad-hoc** Fixed View-As Agent Mode data scoping and white-labeling compliance on `/agents` page: (1) Isolated agent list to show ONLY the target agent being viewed when View-As mode is active, (2) Hid administrative management controls (`+ Provision Agent`, `ExternalAccountsSection`, `Delete`, `Edit Location`, `UserCog`, and nested `View-As` buttons) when View-As mode is active, (3) Replaced hardcoded `Superadmin (BackOne) External Accounts` title with dynamic site-aware branding `getSiteBranding()` (`Nexus` vs `BackOne/SIAB`) per Rule 5. — shipped 2026-07-30
|
||||
|
||||
@@ -122,7 +122,7 @@ const POST_DEPLOY_COMMANDS = [
|
||||
'export PM2=/home/adminbackend/.npm-global/bin/pm2 && $PM2 --version 2>&1 || (npm config set prefix /home/adminbackend/.npm-global && npm install -g pm2)',
|
||||
|
||||
// Reload PM2 processes with new code (zero-downtime reload)
|
||||
'export PM2=/home/adminbackend/.npm-global/bin/pm2 && cd /home/adminbackend/web/demoplace.my.id/public_html && NODE_ENV=production $PM2 reload ecosystem.config.js 2>&1 || NODE_ENV=production $PM2 start ecosystem.config.js',
|
||||
'export PM2=/home/adminbackend/.npm-global/bin/pm2 && cd /home/adminbackend/web/demoplace.my.id/public_html && NODE_ENV=production $PM2 reload ecosystem.config.js 2>&1 && $PM2 restart backone-frontend --update-env 2>&1 || NODE_ENV=production $PM2 start ecosystem.config.js',
|
||||
|
||||
// Save PM2 process list for auto-restart on server reboot
|
||||
'/home/adminbackend/.npm-global/bin/pm2 save',
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
// scripts/force-deploy-frontend.js
|
||||
const SftpClient = require('ssh2-sftp-client');
|
||||
const { Client: SshClient } = require('ssh2');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const CONFIG = {
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH',
|
||||
remotePath: '/home/adminbackend/web/demoplace.my.id/public_html',
|
||||
};
|
||||
|
||||
const LOCAL_ROOT = path.resolve(__dirname, '..');
|
||||
|
||||
async function uploadDir(sftp, localSub, remoteSub) {
|
||||
const localDir = path.join(LOCAL_ROOT, localSub);
|
||||
if (!fs.existsSync(localDir)) {
|
||||
console.log(`Local dir missing: ${localDir}`);
|
||||
return;
|
||||
}
|
||||
const remoteDir = path.posix.join(CONFIG.remotePath, remoteSub.replace(/\\/g, '/'));
|
||||
try {
|
||||
await sftp.mkdir(remoteDir, true);
|
||||
} catch (e) {}
|
||||
|
||||
const items = fs.readdirSync(localDir, { withFileTypes: true });
|
||||
for (const item of items) {
|
||||
if (['node_modules', '.git'].includes(item.name)) continue;
|
||||
const itemLocal = path.join(localDir, item.name);
|
||||
const itemRemote = path.posix.join(remoteDir, item.name);
|
||||
const relRemote = path.posix.join(remoteSub, item.name).replace(/\\/g, '/');
|
||||
|
||||
if (item.isDirectory()) {
|
||||
await uploadDir(sftp, path.join(localSub, item.name), relRemote);
|
||||
} else {
|
||||
process.stdout.write(` [UP] ${relRemote} ... `);
|
||||
await sftp.put(itemLocal, itemRemote);
|
||||
process.stdout.write('done\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function runSsh(cmd) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ssh = new SshClient();
|
||||
ssh.on('ready', () => {
|
||||
console.log(`\n[SSH EXEC] ${cmd}`);
|
||||
ssh.exec(cmd, (err, stream) => {
|
||||
if (err) return reject(err);
|
||||
let out = '';
|
||||
stream.on('data', (d) => { out += d; process.stdout.write(d); });
|
||||
stream.stderr.on('data', (d) => { out += d; process.stderr.write(d); });
|
||||
stream.on('close', () => { ssh.end(); resolve(out); });
|
||||
});
|
||||
}).connect({ host: CONFIG.host, port: CONFIG.port, username: CONFIG.username, password: CONFIG.password });
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('=== FORCE RE-DEPLOYING FRONTEND STANDALONE ===');
|
||||
|
||||
// 1. Stop PM2 backone-frontend first to unlock files
|
||||
await runSsh('/home/adminbackend/.npm-global/bin/pm2 stop backone-frontend || true');
|
||||
|
||||
// 2. Upload .next/standalone recursively
|
||||
const sftp = new SftpClient();
|
||||
console.log('\nConnecting SFTP...');
|
||||
await sftp.connect({ host: CONFIG.host, port: CONFIG.port, username: CONFIG.username, password: CONFIG.password });
|
||||
|
||||
console.log('\nUploading .next/standalone...');
|
||||
await uploadDir(sftp, '.next/standalone', '.next/standalone');
|
||||
|
||||
console.log('\nUploading .next/static...');
|
||||
await uploadDir(sftp, '.next/static', '.next/static');
|
||||
|
||||
console.log('\nUploading public...');
|
||||
await uploadDir(sftp, 'public', 'public');
|
||||
|
||||
await sftp.end();
|
||||
console.log('SFTP Upload Complete!');
|
||||
|
||||
// 3. Run post commands: Copy static into standalone, restart PM2
|
||||
const cmds = [
|
||||
'mkdir -p /home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/',
|
||||
'cp -r /home/adminbackend/web/demoplace.my.id/public_html/.next/static /home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/static',
|
||||
'cp -r /home/adminbackend/web/demoplace.my.id/public_html/public /home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/public 2>/dev/null || true',
|
||||
'/home/adminbackend/.npm-global/bin/pm2 restart backone-frontend --update-env',
|
||||
'sleep 3 && /home/adminbackend/.npm-global/bin/pm2 list',
|
||||
'curl -s http://127.0.0.1:3000/login | grep -i "locked"'
|
||||
];
|
||||
|
||||
await runSsh(cmds.join(' && '));
|
||||
console.log('\n=== DONE FORCE RE-DEPLOYMENT ===');
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
Reference in new issue
Block a user