Files
memind/health-observation-store.mjs
T
john 2baf29b3ae feat(health): complete P0 health channel — baseline engine, page-data, MindSpace UI
Deliver encrypted health zone, observation API, baseline maturity pipeline,
page-data bindings, and H5/WeChat channel integration for health P0.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 18:04:57 +08:00

53 lines
1.8 KiB
JavaScript

export function createInMemoryHealthObservationStore() {
const rowsByUser = new Map();
const dedupIndex = new Map();
let nextId = 1;
return {
listUserIds() {
return [...rowsByUser.keys()];
},
async list(userId, { limit = 50 } = {}) {
const rows = rowsByUser.get(String(userId)) ?? [];
return rows.filter((row) => row.deletedAt == null).slice(0, limit);
},
async findByDedupKey(userId, dedupKey) {
const id = dedupIndex.get(`${String(userId)}|${dedupKey}`);
if (!id) return null;
const rows = rowsByUser.get(String(userId)) ?? [];
return rows.find((row) => row.id === id) ?? null;
},
async insert(userId, observation) {
if (!observation?.confirmed) {
const error = Object.assign(new Error('健康观测必须确认后才能保存'), {
code: 'health_unconfirmed',
});
throw error;
}
const row = {
id: nextId++,
userId: String(userId),
observedAt: observation.observedAt,
metricType: observation.metricType,
valueNum: observation.valueNum ?? null,
valueText: observation.valueText ?? null,
unit: observation.unit ?? null,
context: observation.context ?? null,
source: observation.source ?? 'manual',
sourceRef: observation.sourceRef ?? null,
qualityFlag: observation.qualityFlag ?? 'ok',
deletedAt: observation.deletedAt ?? null,
note: observation.note ?? null,
createdAt: observation.createdAt ?? Date.now(),
};
if (observation.dedupKey) {
dedupIndex.set(`${row.userId}|${observation.dedupKey}`, row.id);
}
const list = rowsByUser.get(row.userId) ?? [];
list.unshift(row);
rowsByUser.set(row.userId, list);
return row;
},
};
}