Add daily activity digest — Phase B (v0.1.0:77)
Sends a once-a-day internal email to all active admins summarizing each team member's email activity per investor, plus a team-wide by-investor view (inbound + outbound, deduped). Narratives are generated on the LOCAL Spark model, never Claude — the digest is intentionally un-anonymized, so substance stays on Ten31 infra. This is an internal ops email, exempt from the 'agents draft, humans send' rule (which governs outward LP contact). - backend/digest_builder.py: per-user + per-investor activity queries (soft-delete filtered), per-user Spark narrative with a deterministic fallback, two-section plain-text body, and the DB-backed policy resolver. - backend/email_integration/digest_scheduler.py: always-on daily thread that re-reads the policy each cycle and sends once/day; window cursor in app_settings so a missed day rolls forward. - server.py: POST /api/admin/digest/send-now and GET/PATCH /api/admin/digest/policy; scheduler wired into main(). - Control lives in Settings -> Admin (enable toggle + send-time dropdown), not StartOS actions; env vars only seed the first-boot default. - Tests: backend/test_digest_builder.py.
This commit is contained in:
@@ -37,8 +37,9 @@ import { v_0_1_0_73 } from './v0.1.0.73'
|
||||
import { v_0_1_0_74 } from './v0.1.0.74'
|
||||
import { v_0_1_0_75 } from './v0.1.0.75'
|
||||
import { v_0_1_0_76 } from './v0.1.0.76'
|
||||
import { v_0_1_0_77 } from './v0.1.0.77'
|
||||
|
||||
export const versionGraph = VersionGraph.of({
|
||||
current: v_0_1_0_76,
|
||||
other: [v_0_1_0_39, v_0_1_0_40, v_0_1_0_41, v_0_1_0_42, v_0_1_0_43, v_0_1_0_44, v_0_1_0_45, v_0_1_0_46, v_0_1_0_47, v_0_1_0_48, v_0_1_0_49, v_0_1_0_50, v_0_1_0_51, v_0_1_0_52, v_0_1_0_53, v_0_1_0_54, v_0_1_0_55, v_0_1_0_56, v_0_1_0_57, v_0_1_0_58, v_0_1_0_59, v_0_1_0_60, v_0_1_0_61, v_0_1_0_62, v_0_1_0_63, v_0_1_0_64, v_0_1_0_65, v_0_1_0_66, v_0_1_0_67, v_0_1_0_68, v_0_1_0_69, v_0_1_0_70, v_0_1_0_71, v_0_1_0_72, v_0_1_0_73, v_0_1_0_74, v_0_1_0_75],
|
||||
current: v_0_1_0_77,
|
||||
other: [v_0_1_0_39, v_0_1_0_40, v_0_1_0_41, v_0_1_0_42, v_0_1_0_43, v_0_1_0_44, v_0_1_0_45, v_0_1_0_46, v_0_1_0_47, v_0_1_0_48, v_0_1_0_49, v_0_1_0_50, v_0_1_0_51, v_0_1_0_52, v_0_1_0_53, v_0_1_0_54, v_0_1_0_55, v_0_1_0_56, v_0_1_0_57, v_0_1_0_58, v_0_1_0_59, v_0_1_0_60, v_0_1_0_61, v_0_1_0_62, v_0_1_0_63, v_0_1_0_64, v_0_1_0_65, v_0_1_0_66, v_0_1_0_67, v_0_1_0_68, v_0_1_0_69, v_0_1_0_70, v_0_1_0_71, v_0_1_0_72, v_0_1_0_73, v_0_1_0_74, v_0_1_0_75, v_0_1_0_76],
|
||||
})
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { VersionInfo } from '@start9labs/start-sdk'
|
||||
|
||||
// Daily activity digest — Phase B. Code-only, no schema change (uses the existing
|
||||
// email_* tables + app_settings; migrations are no-ops):
|
||||
// * backend/digest_builder.py: build_digest() composes two sections — by team
|
||||
// member (per-user narrative from the LOCAL Spark model, never Claude) and by
|
||||
// investor (team-wide, inbound + outbound, deduped). Soft-delete filtered.
|
||||
// * backend/email_integration/digest_scheduler.py: an always-on daily thread
|
||||
// that re-reads a DB-backed policy each cycle and sends once/day to all active
|
||||
// admins. Window cursor lives in app_settings (a missed day rolls forward).
|
||||
// * Control moved into the admin panel: app_settings.digest_policy + GET/PATCH
|
||||
// /api/admin/digest/policy + a Settings enable toggle and send-time dropdown
|
||||
// (CRM_DIGEST_ENABLED/SEND_HOUR only seed the first-boot default).
|
||||
// * POST /api/admin/digest/send-now + a "Send Digest Now" button send the real
|
||||
// last-24h digest on demand without touching the daily cursor.
|
||||
export const v_0_1_0_77 = VersionInfo.of({
|
||||
version: '0.1.0:77',
|
||||
releaseNotes: {
|
||||
en_US: [
|
||||
'New daily activity digest: a once-a-day email to all admins summarizing each team member’s email',
|
||||
'activity per investor, plus a by-investor view (inbound and outbound). Summaries are generated',
|
||||
'locally (Spark), never sent to Claude. Enable it and set the send time in Settings → Admin.',
|
||||
].join(' '),
|
||||
},
|
||||
migrations: { up: async () => {}, down: async () => {} },
|
||||
})
|
||||
Reference in New Issue
Block a user