gigafibre-fsm/services/targo-hub/lib/dispatch-audit.js
louispaulb 512c4a5f1b feat(ops): dispatch auto complet + perf Boîte/rapports + fix session
Planificateur « Suggérer » : 4 stratégies (smart / meilleurs d'abord / équilibré /
juste ce qu'il faut), compétences+niveaux par tech (édition inline), niveau requis
par compétence + par job, carte des tournées (1 couleur/tech, domicile→arrêts,
sélecteur de jour), fenêtre de dispatch auj.+demain (dates sélectionnées), règle
week-end + placeholder « en attente du quart », clustering + lasso + filtre-date
sur la carte, accès rapide « À assigner » (badge).

Boîte : liste /conversations allégée (45 Mo → ~1 Mo, 17×) + messages chargés à
l'ouverture. Rapports : cache SWR sur revenue-explorer (22×). Session : keep-alive
+ timeout fetch global + authFetch durci → fin des rechargements manuels.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 08:49:35 -04:00

49 lines
2.1 KiB
JavaScript

'use strict'
// Journal d'audit d'assignation des Dispatch Jobs : CHAQUE changement horodaté (assigné / réassigné / reflété de F /
// retour au pool / complété / annulé), avec l'ACTEUR (courriel Authentik, ou « F » pour le legacy) et la SOURCE.
// Stockage append-only JSONL dans /app/data (bind-monté → persiste, comme user_prefs.json). Zéro schéma ERPNext.
const fs = require('fs')
const path = require('path')
const { log } = require('./helpers')
const DIR = '/app/data'
const FILE = path.join(DIR, 'dispatch_audit.jsonl')
// Enregistre un événement d'assignation. Fire-and-forget : ne bloque JAMAIS la synchro même si l'écriture échoue.
function record (entry) {
try {
if (!entry || !entry.job) return
const line = JSON.stringify({
ts: new Date().toISOString(),
job: String(entry.job),
ticket: String(entry.ticket || ''),
event: entry.event || 'change', // assigned | reassigned | mirror-assigned | returned-to-pool | completed | cancelled | backfill
from: entry.from || '',
to: entry.to || '',
actor: entry.actor || 'system', // courriel Authentik · 'F' (legacy) · 'system'
source: entry.source || '', // ops-push | F-watch | ops-return | backfill
}) + '\n'
try { fs.mkdirSync(DIR, { recursive: true }) } catch (e) {}
fs.appendFile(FILE, line, () => {})
} catch (e) { try { log('dispatch-audit record error: ' + e.message) } catch (x) {} }
}
// Lecture filtrée (par job et/ou tech et/ou plage ISO), du plus RÉCENT au plus ancien, plafonnée à `limit`.
function read ({ job, tech, from, to, limit = 500 } = {}) {
let raw = ''
try { raw = fs.readFileSync(FILE, 'utf8') } catch (e) { return [] }
const lines = raw.split('\n'); const out = []
for (let i = lines.length - 1; i >= 0 && out.length < limit; i--) {
const l = lines[i].trim(); if (!l) continue
let e; try { e = JSON.parse(l) } catch (x) { continue }
if (job && e.job !== job) continue
if (tech && e.to !== tech && e.from !== tech) continue
if (from && e.ts < from) continue
if (to && e.ts > to) continue
out.push(e)
}
return out
}
module.exports = { record, read }