diff --git a/AGENTS.md b/AGENTS.md index fd39a5f..f070bcb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -104,7 +104,7 @@ _Phase 0 substrate + Phase 1 thesis/outreach are built; **deployed box is v0.1.0 - **Working (all draft-only):** CRM + ingest (chunk→embed→Qdrant + retrieval) + redaction boundary; Gmail capture (DWD) + email-activity propose→approve; Thesis Workshop + Architect (Claude) with dual-approval gate; Outreach Draft Assistant + follow-up radar + per-user voice + Tier-B in-thread Gmail draft creation. - **Deployed & verified live (2026-06-13):** v0.1.0:74 is **installed and healthy on the box** (`$START9_BOX_HOST` / immense-voyage.local). Grant confirms login works; `/assets/` traversal 404s live (plain + URL-encoded), root health 200. On boot, `ensure_thesis_v2_promoted` makes the v2.0 reserve-asset spine the working *approved* spine (node-level, reversible). -- **Repo ahead of the box (committed, NOT yet built/deployed):** the box is pristine v74; `main` is at **v0.1.0:75** and carries two unshipped batches. (a) Post-v74: the **list-view soft-delete aggregate fix** (`server.py`: org `contact_count`/`total_funded`, contacts `comm_count`/`last_contact_date` now filter `deleted_at`), three **regression tests**, and an **aggregate test runner**. (b) **v0.1.0:75 — daily-digest Phase A** (outbound SMTP send): the **`configureDigestSmtp`** Start9 action writes a per-package SMTP account to `/data/secrets/smtp/*` (password over stdin; independent of any StartOS system-wide SMTP), `docker_entrypoint.sh` exports `SMTP_*`, `backend/smtp_send.py` (stdlib smtplib) sends, and admin **`POST /api/admin/digest/test-email`** proves the pipe (recipients restricted to the active-admin set — not an open relay). One `make` ships both batches. +- **Repo ahead of the box (committed, NOT yet built/deployed):** the box is pristine v74; `main` is at **v0.1.0:75** and carries two unshipped batches. (a) Post-v74: the **list-view soft-delete aggregate fix** (`server.py`: org `contact_count`/`total_funded`, contacts `comm_count`/`last_contact_date` now filter `deleted_at`), three **regression tests**, and an **aggregate test runner**. (b) **v0.1.0:75 — daily-digest Phase A** (outbound SMTP send): the **`configureDigestSmtp`** Start9 action writes a per-package SMTP account to `/data/secrets/smtp/*` (password over stdin; independent of any StartOS system-wide SMTP), `docker_entrypoint.sh` exports `SMTP_*`, `backend/smtp_send.py` (stdlib smtplib) sends, and admin **`POST /api/admin/digest/test-email`** proves the pipe (recipients restricted to the active-admin set — not an open relay), surfaced as a **Settings → Admin "Send Test Digest Email" button**. One `make` ships both batches. - **Shipped in v0.1.0:74** (security/privacy hardening from the 2026-06-12 full-eval; report in `EVALUATION.md`): closed a pre-auth `/assets/` path traversal (could read crm.db / JWT secret / Gmail key); wired the local-Qwen NER backstop into the outreach redaction boundary (free-prose email bodies were reaching Claude with unknown names in the clear); added `deleted_at IS NULL` to every get-by-id + nested sub-select read path. Verified locally (py_compile, query exec, redaction/outreach tests, containment logic) + two reviewer passes. - **Tests (2026-06-15):** **18/18 backend tests green** via `python3 backend/run_tests.py` (+`test_smtp_send.py`/`test_smtp_endpoint.py` this session). `py_compile` clean; the s9pk TypeScript typechecks (`cd start9/0.4 && npm run check`, deps installed); `docker_entrypoint.sh` passes `sh -n`. The 2 stale thesis tests stay fixed (seed structure in `docs/guides/thesis.md`). - **Decided, not yet built:** CRM as canonical thesis backbone with the signal-engine reading from it (reconciliation unwired); reply-all for Tier-B drafts (drafts currently reply to the LP only). diff --git a/frontend/index.html b/frontend/index.html index 8660876..859b1cd 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -7768,6 +7768,7 @@ const [users, setUsers] = useState([]); const [usersLoading, setUsersLoading] = useState(false); const [userActionLoadingId, setUserActionLoadingId] = useState(null); + const [testEmailLoading, setTestEmailLoading] = useState(false); const [auditLogs, setAuditLogs] = useState([]); const [auditLoading, setAuditLoading] = useState(false); const [automationRules, setAutomationRules] = useState([]); @@ -8216,6 +8217,22 @@ } }; + const handleSendTestDigestEmail = async () => { + setTestEmailLoading(true); + try { + const result = await api('/api/admin/digest/test-email', { + method: 'POST', + body: JSON.stringify({}) + }, token); + const to = (result?.data?.sent_to || []).join(', '); + onShowToast(`Test digest email sent${to ? ` to ${to}` : ''}`, 'success'); + } catch (err) { + onShowToast(getErrorMessage(err, 'Failed to send test email — is SMTP configured? (Start9: Configure Digest SMTP, then restart)'), 'error'); + } finally { + setTestEmailLoading(false); + } + }; + const handleContactsCsvFileUpload = async (event) => { const file = event.target.files && event.target.files[0]; if (!file) return; @@ -8496,6 +8513,16 @@ Invite users and manage fundraising state backups. +
+
Daily Digest Email
+
+ Sends a test message to all active admins through the configured SMTP account, to verify outbound email works. Configure SMTP via the Start9 "Configure Digest SMTP" action, then restart the service. +
+ +
+
Invite User
diff --git a/start9/0.4/startos/utils.ts b/start9/0.4/startos/utils.ts index 7f784d8..7684424 100644 --- a/start9/0.4/startos/utils.ts +++ b/start9/0.4/startos/utils.ts @@ -40,7 +40,7 @@ export const PACKAGE_TITLE = 'Ten31 Database' // * 0.1.0:72 (stage v2.0 reserve-asset thesis spine as Workshop candidates) // * 0.1.0:73 (replace old settlement spine with v2.0 reserve-asset spine across Architect + outreach prompts, seed constants, and docs; promote v2.0 to the working approved spine + soft-retire old settlement nodes, reversibly, node-level only) // * 0.1.0:74 (security/privacy hardening — full-eval P0+2×P1: close /assets/ path traversal, add NER backstop to the outreach redaction boundary, filter deleted_at on get-by-id) -// * Current: 0.1.0:75 (Phase-A digest SMTP: per-package "Configure Digest SMTP" action writes /data/secrets/smtp/*; entrypoint exports SMTP_*; backend smtp_send.py + admin "send test email" endpoint) +// * Current: 0.1.0:75 (Phase-A digest SMTP: per-package "Configure Digest SMTP" action writes /data/secrets/smtp/*; entrypoint exports SMTP_*; backend smtp_send.py + admin "send test email" endpoint + Settings→Admin "Send Test Digest Email" button) export const PACKAGE_VERSION = '0.1.0:75' export const DATA_MOUNT_PATH = '/data'