Baseline commit of the existing Maquina Comercial Pessoal project

Tracks the app that was already in place (capture, treatment, outreach,
WhatsApp integration, server, frontend, tests, docs) so future feature
work can branch and use isolated worktrees.
This commit is contained in:
Gustavo
2026-07-31 10:54:07 -03:00
parent 6cd336a41e
commit d330bb5ff0
132 changed files with 29969 additions and 0 deletions
+82
View File
@@ -0,0 +1,82 @@
import { loadDotEnv, APP_PORT, paths } from '../src/env.mjs';
import { openDb, ensureSeeds, recoverPendingOutreach, updateOutreachMessageStatus } from '../src/db.mjs';
import { createJobManager, recoverOrphans } from '../src/jobs/manager.mjs';
import { createAppServer } from '../src/server/index.mjs';
import { startOutreachScheduler } from '../src/outreach/scheduler.mjs';
import { pauseCampaignsAfterRestart, recoverReservedCampaignQueue } from '../src/outreach/campaign-worker.mjs';
import { recordInboundReply } from '../src/outreach/inbound.mjs';
import { createWhatsAppManager, hasWhatsAppSession } from '../src/whatsapp/manager.mjs';
// Servidor local da Maquina Comercial Pessoal.
await loadDotEnv();
const log = (message) => console.log(`[servidor] ${message}`);
const db = openDb();
await ensureSeeds(db, { log });
recoverOrphans(db, log);
recoverPendingOutreach(db);
pauseCampaignsAfterRestart(db);
recoverReservedCampaignQueue(db);
const jobs = createJobManager({ db });
const whatsapp = createWhatsAppManager({
authDir: paths.whatsappAuth,
log,
onMessageStatus: (event) => updateOutreachMessageStatus(db, event),
onInboundMessage: (event) => recordInboundReply(db, event)
});
if (await hasWhatsAppSession(paths.whatsappAuth)) {
whatsapp.connect().catch((error) => log(`whatsapp: reconexao inicial falhou: ${error.message}`));
}
const server = createAppServer({ db, jobs, whatsapp, log });
const stopScheduler = startOutreachScheduler({ db, whatsapp, log });
const port = APP_PORT;
server.listen(port, '127.0.0.1', () => {
log(`Maquina Comercial Pessoal rodando em http://127.0.0.1:${port}`);
log('somente este computador tem acesso (127.0.0.1). Ctrl+C para encerrar.');
});
let shuttingDown = false;
async function shutdown() {
if (shuttingDown) return;
shuttingDown = true;
log('encerrando...');
const watchdog = setTimeout(() => process.exit(1), 30_000);
watchdog.unref();
const shutdownTasks = [
stopScheduler().catch((error) => log(`outreach: falha ao encerrar scheduler: ${error.message}`)),
jobs.close().catch((error) => log(`jobs: falha ao encerrar: ${error.message}`)),
whatsapp.close().catch((error) => log(`whatsapp: falha ao encerrar: ${error.message}`))
];
let resourceTimer;
const resourcesTimedOut = await Promise.race([
Promise.allSettled(shutdownTasks).then(() => false),
new Promise((resolve) => {
resourceTimer = setTimeout(() => resolve(true), 20_000);
resourceTimer.unref();
})
]);
clearTimeout(resourceTimer);
if (resourcesTimedOut) log('encerramento dos recursos excedeu o prazo; prosseguindo');
recoverOrphans(db, log);
let httpTimer;
const httpTimedOut = await Promise.race([
new Promise((resolve) => server.close(resolve)).then(() => false),
new Promise((resolve) => {
httpTimer = setTimeout(() => resolve(true), 5_000);
httpTimer.unref();
})
]);
clearTimeout(httpTimer);
if (httpTimedOut) log('encerramento HTTP excedeu o prazo; prosseguindo');
db.close();
process.exit(0);
}
process.on('SIGINT', shutdown);
process.on('SIGTERM', shutdown);