godcrm/backend/services/briefing/fetchers.js
GOD CRM Release f89e074dd1
Some checks failed
CI / Lint / Typecheck / Test / Build (push) Has been cancelled
CI / PostgreSQL Integration Tests (push) Has been cancelled
GOD CRM — public scrubbed snapshot
Governed substrate for autonomous agents: scoped identity (passports),
audited actions, MCP workspace. Infra IPs and secrets redacted for public release.
2026-08-10 04:01:45 +03:00

193 lines
5.9 KiB
JavaScript

/**
* Briefing — Data Fetchers
*
* Functions that query CRM tables for calendar events, tasks, health, medications, etc.
*/
import { dbAll, dbGet, safeJsonParse } from '../../database/connection.js';
import {
log, TABLE_IDS, WELLNESS_SCHEDULE_TABLE, ATOMIC_HABITS_TABLE,
getOptionLabels, resolveTaskFields, extractTime,
} from './constants.js';
// =============================================================================
// DATA FETCHERS
// =============================================================================
export async function fetchTodayEvents(todayStr) {
try {
const rows = await dbAll(
'SELECT id, data FROM table_rows WHERE table_id = ? ORDER BY created_at DESC',
[TABLE_IDS.CALENDAR_EVENTS]
);
const events = [];
for (const row of rows) {
const data = safeJsonParse(row.data) || {};
const startDt = data.start_datetime || '';
if (startDt.startsWith(todayStr)) {
events.push({
id: row.id,
title: data.title || data.summary || '\u0411\u0435\u0437 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f',
start_datetime: startDt,
end_datetime: data.end_datetime || '',
location: data.location || '',
time: extractTime(startDt),
});
}
}
events.sort((a, b) => a.start_datetime.localeCompare(b.start_datetime));
return events;
} catch (err) {
log.error({ err }, 'Failed to fetch calendar events');
return [];
}
}
export async function fetchSprintTasks() {
try {
const opts = await getOptionLabels();
const rows = await dbAll(
'SELECT id, data FROM table_rows WHERE table_id = ? ORDER BY created_at DESC',
[TABLE_IDS.SPRINT_TASKS]
);
const tasks = [];
for (const row of rows) {
const data = safeJsonParse(row.data) || {};
const { title, stateLabel, priorityLabel, isDone } = resolveTaskFields(data, opts);
if (!isDone) {
tasks.push({
id: row.id,
title,
state: stateLabel,
priority: priorityLabel,
assigned_to: data.assigned_to || '',
});
}
}
const priorityOrder = { p0: 0, p1: 1, urgent: 1, high: 1, critical: 0, p2: 2, medium: 2, normal: 2, p3: 3, low: 3, p4: 4 };
tasks.sort((a, b) => {
const pa = priorityOrder[String(a.priority).toLowerCase()] ?? 5;
const pb = priorityOrder[String(b.priority).toLowerCase()] ?? 5;
return pa - pb;
});
return tasks;
} catch (err) {
log.error({ err }, 'Failed to fetch sprint tasks');
return [];
}
}
export async function fetchHealthMetrics() {
try {
const row = await dbGet(
'SELECT id, data, created_at FROM table_rows WHERE table_id = ? ORDER BY created_at DESC LIMIT 1',
[TABLE_IDS.HEALTH_METRICS]
);
if (!row) return null;
return { id: row.id, ...safeJsonParse(row.data), _recorded_at: row.created_at };
} catch (err) {
log.error({ err }, 'Failed to fetch health metrics');
return null;
}
}
export async function fetchMedications() {
try {
const rows = await dbAll(
'SELECT id, data FROM table_rows WHERE table_id = ? ORDER BY created_at ASC',
[TABLE_IDS.MEDICATIONS]
);
return rows.map(row => {
const data = safeJsonParse(row.data) || {};
return {
id: row.id,
name: data.name || data.title || 'Unknown',
dosage: data.dosage || '',
time_of_day: data.time_of_day || data.schedule || data.time || 'any',
notes: data.notes || '',
};
});
} catch (err) {
log.error({ err }, 'Failed to fetch medications');
return [];
}
}
export async function fetchCompletedToday(todayStr) {
try {
const opts = await getOptionLabels();
const rows = await dbAll(
'SELECT id, data, updated_at FROM table_rows WHERE table_id = ? ORDER BY updated_at DESC',
[TABLE_IDS.SPRINT_TASKS]
);
const completed = [];
for (const row of rows) {
const data = safeJsonParse(row.data) || {};
const { title, stateLabel, priorityLabel, isDone } = resolveTaskFields(data, opts);
const rawUpdated = row.updated_at || '';
const updatedAt = rawUpdated instanceof Date ? rawUpdated.toISOString() : String(rawUpdated);
if (isDone && updatedAt.startsWith(todayStr)) {
completed.push({
id: row.id,
title,
state: stateLabel,
priority: priorityLabel,
});
}
}
return completed;
} catch (err) {
log.error({ err }, 'Failed to fetch completed tasks');
return [];
}
}
/**
* Fetch wellness schedule blocks from CRM table.
*/
export async function fetchWellnessSchedule() {
try {
const rows = await dbAll(
'SELECT id, data FROM table_rows WHERE table_id = ? ORDER BY created_at ASC',
[WELLNESS_SCHEDULE_TABLE]
);
return rows.map(row => {
const data = safeJsonParse(row.data) || {};
return {
id: row.id,
time_start: data.time_start || data.start_time || '',
time_end: data.time_end || data.end_time || '',
block_name: data.block_name || data.name || data.title || '',
category: data.category || data.type || '',
details: data.details || data.description || '',
};
});
} catch (err) {
log.error({ err }, 'Failed to fetch wellness schedule');
return [];
}
}
/**
* Fetch atomic habit stacks from CRM table.
*/
export async function fetchAtomicHabits() {
try {
const rows = await dbAll(
'SELECT id, data FROM table_rows WHERE table_id = ? ORDER BY created_at ASC',
[ATOMIC_HABITS_TABLE]
);
return rows.map(row => {
const data = safeJsonParse(row.data) || {};
return {
id: row.id,
trigger: data.trigger || data.cue || '',
habit: data.habit || data.micro_habit || data.name || '',
duration: data.duration || data.time || '',
};
});
} catch (err) {
log.error({ err }, 'Failed to fetch atomic habits');
return [];
}
}