feat: log failures, validate env at startup, load .env (findings 3, 4, 7)

Finding 3: fetch_error, not_found, mail_error and de onverwachte-fout
branch loggen nu naam/url plus reden naar stderr; runCheck logt na elke
run een regel met de tellingen per status, zodat een cron-run zichtbaar
is in de container-logs. De recordCheckSuccess/recordCheckFailure-condities
en alle return-waarden zijn ongewijzigd.

Finding 4: server.js controleert bij het opstarten dat BASIC_AUTH_USER,
BASIC_AUTH_PASS, SMTP_FROM en NOTIFY_EMAIL gezet zijn en stopt anders met
exit code 1 in plaats van later opake 500's te geven.

Finding 7: dotenv toegevoegd en als eerste regel in server.js geladen,
zodat het gedocumenteerde `cp .env.example .env && npm start` echt werkt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013gwc3aCiyQxmCWQke8RvEz
This commit is contained in:
Sjoerd de Vries
2026-09-05 15:52:57 +02:00
parent 52c9947267
commit fb3fc62b4b
6 changed files with 70 additions and 6 deletions
+25 -1
View File
@@ -1,3 +1,7 @@
// Leest een .env-bestand in voor lokale ontwikkeling; in productie komen de
// env vars van Coolify. quiet houdt de opstartlogging schoon.
require('dotenv').config({ quiet: true });
const path = require('node:path');
const {
openDb, listProducts, addProduct, deleteProduct,
@@ -9,12 +13,29 @@ const { checkAllProducts } = require('./src/checkProducts');
const { start: startScheduler } = require('./src/scheduler');
const { createApp } = require('./src/app');
const REQUIRED_ENV = ['BASIC_AUTH_USER', 'BASIC_AUTH_PASS', 'SMTP_FROM', 'NOTIFY_EMAIL'];
const missing = REQUIRED_ENV.filter((name) => !process.env[name]);
if (missing.length > 0) {
console.error(`Ontbrekende verplichte environment variables: ${missing.join(', ')}`);
console.error('Zet ze (bijvoorbeeld in .env, zie .env.example) en start opnieuw.');
process.exit(1);
}
const PORT = process.env.PORT || 3000;
const DB_PATH = process.env.DB_PATH || path.join(__dirname, 'data', 'korting.db');
const db = openDb(DB_PATH);
const transport = createTransport(process.env);
function summarize(results) {
const counts = {};
for (const result of results) {
counts[result.status] = (counts[result.status] || 0) + 1;
}
const parts = Object.entries(counts).map(([status, count]) => `${status}=${count}`);
return parts.length > 0 ? parts.join(' ') : 'geen producten';
}
function runCheck() {
const products = listProducts(db);
const deps = {
@@ -28,7 +49,10 @@ function runCheck() {
recordCheckSuccess: (id, data) => recordCheckSuccess(db, id, data),
now: () => new Date().toISOString(),
};
return checkAllProducts(products, deps);
return checkAllProducts(products, deps).then((results) => {
console.log(`[check] ${products.length} product(en) gecontroleerd: ${summarize(results)}`);
return results;
});
}
startScheduler(runCheck);