Contact + AI Facts profile page (redesign Phase 1, SPEC-0017)#215
Open
joestump wants to merge 1 commit into
Open
Contact + AI Facts profile page (redesign Phase 1, SPEC-0017)#215joestump wants to merge 1 commit into
joestump wants to merge 1 commit into
Conversation
New GET /contact/{id} per-person profile (SPEC-0017), reached from the transcript
header: merged Signal+iMessage identity + identifier chips, a gap-filled
message-volume sparkline, derivable stat tiles (total / sent / received / photos
/ pace / most-active hour / first message), top reactions, and AI-gathered facts
grouped by category — each cited fact deep-linking to its OWN source conversation.
All aggregates are keyed by contact id (the merged-person grain) over the
existing schema (contacts / contact_identifiers / contact_facts / messages /
reactions / attachments) — no new tables. GetContactByID is identity-only;
ContactStats owns the counts (single scan). The sparkline is CSP-safe inline SVG
(presentational attributes only) and gap-fills silent years. Fact text is
html/template-escaped. UTC bucketing; ts ordering never uses MIN/MAX(ts) string
aggregation. A contact with zero conversations still renders (no template crash).
- store: internal/store/contacts.go + ContactFact.SourceConversationID +
ConversationSummary.ContactID (drives the header link)
- web: /contact/{id} handler + contact.html; the transcript header name links to
the profile when the conversation is linked to a contact
- deferred non-goals (spec'd): sentiment-over-time, shared vocabulary,
activity-rhythm heatmap, median reply time, per-day mood
- docs: SPEC-0017 contact-profile spec pair
Tests cover merged aggregates, sent/received split, fact source resolution
(incl. gone-message id 0), full/partial render, 404, fact escaping, and the
zero-conversation contact regression.
Part of SPEC-0017
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Summary
Phase 1 of the redesign (design brief-2): a per-person Contact + AI Facts profile at
GET /contact/{id}, reached from the transcript header (the name links to the person's profile). Implements SPEC-0017 (docs/openspec/specs/contact-profile/).Reassuringly, the data already existed — this is largely a new page over the current schema, no new tables.
What it shows
facts.Categoriesorder, each cited fact deep-linking to its own source conversation (/c/{convID}/at/{msgID}); a gone message renders undated/link-less. Fact text ishtml/template-escaped.Implementation notes
contact_id(the merged-person grain). Load-bearing predicate:conversation_id IN (SELECT id FROM conversations WHERE contact_id = ?).GetContactByIDis identity-only;ContactStatsowns the counts, so a page render does a single message scan (not two).internal/store/contacts.go,internal/web/contact.go+contact.html.ContactFactgainedSourceConversationID;ConversationSummarygainedContactID(drives the header link).message_sentiment-style NLP-table plug-in point): sentiment-over-time, shared vocabulary, activity-rhythm heatmap, median reply time, per-day mood.Review + verification
/code-review; it caught (and this PR fixes) a zero-conversation → HTTP 500 template crash, a sparkline gap-fill bug, a label-overlap bug, and a redundant double message scan — each now fixed with a regression test.go vet,gofmt, and the CSP no-inline-style guard are green. Verified live against the fixture archive.Note
The mockup's fact categories (Family/Location/Channels/…) differ from the existing
factstaxonomy (personal/work/relationships/…); this renders the real stored categories — changing the extraction taxonomy is a separate decision.Part of SPEC-0017
🤖 Posted on behalf of
@joestumpby Claude.