Commit Graph
19 Commits
Author SHA1 Message Date
Jamie BruntonandClaude Opus 5 725b5fc4e6 feat: application-level read state and inbox triage for conversations
Conversations were hard to manage because "unread" came straight from
Matrix's notification_count, and nothing in the app ever sends a read
receipt — so opening a conversation in the dashboard could never clear it
and the unread set only ever grew. The list also collapsed three
orthogonal facts into one word, labelling "they spoke last and we have
not replied" as "Up to date".

Read state is now ours:

- conversation_read_state table (migration 19) plus
  ConversationReadStateRepository, kept separate from conversation_states
  so a read write can never be lost to mergeConversationState. The
  watermark is monotonic, so a stale poll cannot resurrect an unread
  badge.
- hasUnreadInbound and needsReply are derived server-side and returned on
  every conversation. Matrix's `unread` stays on the contract but the
  dashboard no longer reads it.
- POST /conversations/{id}/read|unread|status and
  POST /conversations/bulk-read, with optimistic cache updates.

Inbox rework:

- List rows are a real grid (checkbox, open button, chip strip) instead of
  a full-bleed absolute overlay button, which previously forced a
  pointer-events escape hatch for anything interactive in a row. Rows use
  aria-current rather than aria-pressed. Not a listbox: options must not
  contain interactive descendants.
- Counted filter pills replace the select, independent state chips replace
  the collapsed status word, plus a sort control (including oldest
  unanswered), a per-account filter, age-coloured timestamps, and an
  explicit count of rows hidden by the seller filter.
- Keyboard: j/k/arrows, Enter, u, e, / and Escape. Shortcuts yield to any
  open dialog so Escape dismisses the modal, not the conversation behind
  it. Multi-select with bulk mark-read and mark-done.
- Detail panel: auto-mark-read on open, a "New messages" divider pinned at
  mount (deriving it from the live watermark made it vanish a second after
  opening), triage actions in the header, the automation banner moved out
  of the composer, day dividers with time-only stamps, and a flex column
  so history scrolls in its own region instead of painting over the
  composer.
- Row order freezes while a conversation is open, with a "N new — refresh"
  pill, so a background poll cannot reorder rows mid-triage.

Two database tests rewound user_version by an offset from the latest
version, which silently re-targets a different migration whenever one is
appended. They now pin absolute versions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 10:06:03 +01:00
jjbrunton bf474dfe10 Add consent-gated media exchange library 2026-08-09 19:24:38 +01:00
jjbrunton b8e4a1bb88 Harden conversation replies and prioritize newest candidates 2026-08-09 18:16:57 +01:00
jjbrunton 9b86cee9be Prioritize conversation replies 2026-08-09 16:04:39 +01:00
jjbrunton df35648920 Add durable candidate funnel 2026-08-09 15:08:06 +01:00
jjbrunton 50f9f8a6aa Show Reddit post age in conversations 2026-08-09 09:54:53 +01:00
jjbrunton 83b5f1f5b6 Add attention inbox and AI usage observability 2026-08-09 08:52:32 +01:00
jjbrunton 5c01d7d9aa fix: prevent duplicate outreach and follow-ups 2026-08-09 07:48:39 +01:00
jjbrunton e8b730b592 feat: add agent API and operational analytics 2026-08-08 22:08:14 +01:00
jjbrunton 16a31335d0 feat: support concurrent Reddit accounts 2026-08-08 19:00:38 +01:00
jjbrunton d819a0f1e6 feat: track received image outcomes 2026-08-08 18:53:11 +01:00
jjbrunton 2c100d72b6 feat: persist settings and enrich conversation context 2026-08-08 18:18:28 +01:00
jjbrunton c483c7b8be feat: replace browser login with imported Reddit sessions 2026-08-08 16:48:59 +01:00
jjbruntonandClaude Opus 4.7 1b6dfd67e3 Persist t2→username mappings in reddit_users table
Adds a durable mapping so the UI never has to show raw t2_xxx IDs or
MXIDs just because the in-memory cache is cold after a restart.
ChatService seeds from the table on construction and writes through
every resolution path; cached chats whose username is still t2_xxx
get upgraded from the DB on loadCache.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 20:34:06 +01:00
jjbruntonandClaude Opus 4.7 05c95db6bd Record sent chats in messages repo and blur gallery by default
Threads MessagesRepository through ChatService so first outgoing chat
messages are persisted for stats, and extends the repo + DB client to
support chat-room-keyed lookups. Adds tests covering the new behavior.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 18:48:14 +01:00
jjbrunton 633bb0ec04 Restructure chat service, web routes, and add test suite
Split monolithic chat service into modular structure with Matrix client
support, extract web server into per-resource route modules, introduce
bootstrap/main-loop separation, and add comprehensive vitest coverage
across services, repositories, and utilities. Adds project docs and
CLAUDE.md agent instructions.
2026-05-21 01:32:10 +01:00
jjbruntonandClaude Opus 4.6 dfa0580859 Update source code and remove runtime data from tracking
Add gitignore rules for browser session data, SQLite databases,
media downloads, and build artifacts. Remove previously tracked
runtime files from the repository.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 18:54:07 +01:00
jjbrunton 7b3ea37127 Update 2026-01-05 00:17:06 +00:00
jjbrunton c552956516 Initial 2026-01-04 19:16:31 +00:00