Schedule send, contacts CRM, inbox tabs, and reliability fixes#40
Open
clickclacknvrwhack wants to merge 5 commits into
Open
Conversation
…king Extends the SQLite store with the data layer for this batch of features: - scheduled_messages table + queries (scheduled.go): create/list/cancel, atomic pending->sending claim for exactly-once delivery, due-message lookup, and on-demand media-blob loading. Backs schedule-send. - last_read_ts read watermark on conversations (conversations.go, db.go): MarkConversationRead advances it, and UpsertConversation only honors an incoming unread flag when the event carries genuinely newer activity -- so Google's stale unread re-syncs can't resurrect a cleared badge. - people.go / contact_meta.go: contacts-CRM aggregation (group 1:1s by person, real message counts) plus per-person tags, reach-out cadence, and cached relationship summaries. - tapback.go: parse iMessage tapbacks (Loved "...") into emoji reactions on the referenced message, with a startup repair pass. - stub.go: detect and batch-remove empty placeholder rows that would otherwise render as "Empty message" and wrongly surface threads. Each addition is covered by table-driven tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Backend for the new features plus several reliability fixes:
- scheduler.go: background loop (startup catch-up + 20s ticker) that sends
due scheduled messages. Atomically claims each (exactly-once), checks the
route is connected, and routes text/media by platform -- WhatsApp/Signal
carry captions inline; SMS uploads via libgm and sends any caption as a
follow-up text. Offline -> retry; >=5 attempts -> mark failed. Test hooks
(sendText/sendMediaOverride) keep it deterministic in tests.
- contacts.go: read-only Google Messages contact sync (never creates
conversations, so it can't flood the inbox).
- gm.go / send_group.go: two-step CREATE_RCS group-creation flow and E.164
phone normalization, fixing "Google Messages didn't return a conversation"
and missing-"+" group sends.
- events.go / backfill.go: gate incoming messages through ApplyTapback and
IsEmptyStubMessage; advance recency only on real content.
- app.go: startup repair chain (legacy artifacts -> contentless recency ->
tapbacks -> empty stubs -> media placeholders).
- story/summary.go: local relationship summaries with system-message
filtering ("No communication" when only RCS banners exist).
- importer/contacts_macos.go + CLI wiring for `import contacts`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Web layer for the new features plus rendering fixes:
- Schedule-send endpoints: /api/schedule (GET list + POST text),
/api/schedule-media (POST multipart, persists the blob), and
/api/schedule/{id} DELETE to cancel. Compose UI gains a clock menu
(Tomorrow 9 AM / 5 PM / custom), media-aware scheduling, and a pending
strip above the composer with a paperclip for attachments.
- Contacts CRM endpoints (/api/people, /api/people/{key}/{tags,reach-out,
summary}, /api/contacts sync + add-local) and a person-icon CRM view:
list with sort modes, detail with photo, contact info, last-contacted,
tags, reach-out tickler, summary, and open-conversation.
- Rendering fixes: keyed-reconcile message rendering (no more triple
white flash on send/receive) and window-scoped media load/error
handlers (images no longer stick on the loading spinner).
- normalizePhoneNumber (E.164) for new conversations.
Covered by phone_test.go, schedule_media_test.go, and e2e specs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
docs/CODEMAP.md: a guide to where everything lives -- entry points, the app coordinator, platform connectors, the SQLite store, importers, the web/API + UI, MCP tools, analytics/viz, and cross-cutting data flows (receive, send, new conversation, schedule-send, contacts CRM). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase C orphan-contact discovery is now gated by upstream's orphanContactDiscoveryEnabled() (OPENMESSAGES_BACKFILL_DISCOVER_ORPHANS), introduced in MaxGhenis#21, which supersedes the App.EnableContactDiscovery field this branch had added for the same purpose. Remove the now-dead field and the redundant test assignments; the tests already opt in via t.Setenv. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
41a9a7b to
1f2ebf2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A batch of new features and reliability fixes for the inbox, all local-first and test-covered.
✨ Features
scheduled_messagestable, a background scheduler (startup catch-up + 20s ticker, atomic exactly-once claim, offline-retry/fail, per-platform routing),/api/schedule+/api/schedule-mediaendpoints, and a pending strip above the composer with cancel.docs/CODEMAP.md.🔧 Repairs
last_read_tswatermark; migration auto-protects already-read threads).Loved "…"texts convert into emoji reactions instead of cluttering threads.CREATE_RCS) flow + E.164 phone normalization.Notes
go test ./internal/... ./cmd/);staticcheckclean on changed packages.main; happy to rebase if preferred.🤖 Generated with Claude Code