Skip to content

Merge AP DM chat feature into master#66

Merged
outlaw-dame merged 34 commits into
masterfrom
merge/ap-dm-chat-to-master
May 5, 2026
Merged

Merge AP DM chat feature into master#66
outlaw-dame merged 34 commits into
masterfrom
merge/ap-dm-chat-to-master

Conversation

@outlaw-dame

Copy link
Copy Markdown
Collaborator

Merges feature/ap-dm-chat into master, including Pod-authoritative chat commits, server-side Pod token hardening, bookmark uniqueness hardening, and the accumulated Memory app chat/feed work carried by the feature branch.

Damon Outlaw and others added 30 commits April 6, 2026 10:58
…atus, unified feed, OIDC auth, new specs and utils
…, reply root reconciliation

Sprint 1:
- Add i18n keys for popular feed heading/subtitle
- Carousel navigation via navigateToPost with URI filter
- DB indexes 0007 (engagement), 0008 (ap_remote quoted_post_uri)
- AP quote_counts CTE: fan-out-safe UNION with outer GROUP BY
- Engagement weight constants in feedMetrics utils

Sprint 2 (test coverage + migrations + self-healing):
- extractQuotedPostUri: 18 unit tests (vendor precedence, scheme security, length boundary)
- UnifiedFeedList carousel: navigateToPost and no-URI exclusion tests
- atBridge UNION fan-out integration test (5th test, mode=chronological)
- Migration 0009: partial index on ap_remote_posts(reply_parent_uri)
- reconcileApRemoteReplyRoots(): chain-walk (max depth 50, cycle-safe), idempotent batch UPDATE
- startApRemoteReconciliationService(): 5-min background sweep, wired in index.ts

All tests pass: 61 API / 27 frontend. Typecheck clean.
useKeywordRules composable: typed CRUD wrappers for the sidecar
GET/POST/PUT/DELETE /internal/admin/spam/keyword-rules endpoints with
pending/error reactive state and consistent error message extraction.

DashboardFederationView: keyword rules panel slides in when the
Keyword Reject MRF module card is toggled on — shows the live rule
list (semantic/literal badge, threshold, whole-word/case flags) and
an add/edit form with a semantic toggle, threshold slider, and literal
options. Rules refresh automatically after every mutation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- switch moderation reads to /api/dashboard/apps/moderation/{blocks,mutes,filters}
- switch block/mute writes to delegated app moderation endpoints
- keep existing retry/backoff behavior and auth headers
- Add chat_convos, chat_members, chat_messages tables (migration 0010)
- Add 8-endpoint chatRoutes plugin (listConvos, getConvo, getMessages,
  sendMessage, getConvoForMembers, createGroup, addMember, removeMember)
- Add maybePersistDirectMessage in ActivityPodsNotifications:
  - Detects Solid Notifications Add envelope, fetches full AP activity
    from pod using recipientUser.podToken, then applies DM detection
    (Create(Note), no public audience)
  - All inserts wrapped in a single db.transaction for atomicity
  - Idempotent via onConflictDoNothing + stable msgId from activity IRI
- Wire DM persistence into /activitypods/webhooks/inbox/:userId (fire-and-forget)
- Register chatPlugin in main app
- 24/24 tests pass, 0 TypeScript errors
- Add unit tests for maybePersistDirectMessage
- Cover Add envelope with embedded transient Create(Note) activity
- Cover non-Add ignore path
- Cover public-audience ignore path
- Cover self-message ignore path
- at_identities: add display_name, avatar_url, banner_url columns
- ap_actor_cache: new table (TTL=24h, in-flight guard) populated
  fire-and-forget from ApRemoteIngestionService on each remote AP ingest
- resolveAndCacheHandles: persist displayName/avatar/banner from
  bsky getProfiles batch response into at_identities
- unifiedFeedView / unifiedFeedCandidatesView: emit author_avatar from
  at_identities (AT branch) and ap_actor_cache (AP remote branch)
- UnifiedFeedRow + mapDbRowToFeedRow + Elysia schema: thread authorAvatar
  through serialisation path
- UnifiedFeedItem (frontend): add authorAvatar optional field
- local_posts (PGlite): add author_avatar column (DDL + Drizzle schema +
  ALTER TABLE IF NOT EXISTS migration guard)
- syncStore: upsert author_avatar into local_posts on sync
- local_follows (PGlite): new table for offline follow state
- useFollow: onMounted rehydration + fire-and-forget persist on follow
- migration 0011 generated for at_identities columns + ap_actor_cache
… relationship cache

- Add followersCount/followsCount/postsCount to at_identities; populated from
  getProfiles batch fetch in resolveAndCacheHandles
- Add followersCount/followingCount/postsCount to ap_actor_cache; populated by
  extractCollectionCount() helper in cacheApActorIfStale (works for Misskey/Pleroma
  actors that expose totalItems inline; gracefully null for Mastodon URI-only actors)
- Add isRead/readAt to notifications table (matches Mastodon read-state semantics)
- Add bookmarks table (schema.ts) with per-user bookmark rows and userId/uri indexes
- Add bookmarks route (GET/POST/DELETE /bookmarks) wired into protectedRoutes
- Add viewer_relationship_cache table tracking isFollowing/isFollowedBy/isMuted/
  isBlocked/isBlockedBy per viewer+subject pair with refreshedAt TTL column
- Add local_bookmarks PGlite table + DDL for offline bookmark persistence
- Add useBookmark.ts composable (toggleBookmark, isBookmarked, PGlite rehydration)
- Drizzle migration 0012 (20 tables)
- Add server-side grouped notifications endpoint with boost/like aggregation by subject
- Derive semantic notification kinds from Solid inbox envelopes and nested AP activity payloads
- Add notification read-state mutation endpoints: single, grouped set, and mark-all
- Add grouped notification state/actions in frontend notifications store
- Update notifications view to render grouped cards with unread highlighting and mark-read controls
- Add i18n strings for grouped notification labels and actions
- Add grouped notification query options: includeFollows, includeMentions, windowHours
- Apply relevance window to grouping so stale events render as singles
- Persist notification grouping preferences in notifications store local settings
- Add Appearance section on Settings page for follow/mention grouping toggles and time window
- Localize new appearance/settings labels in EN and ES
…fications, unread badge, XRPC skeleton

- ActivityPodsNotifications: add 'reply' and 'quote' NotificationKind.
  deriveNotificationKind now inspects nested Note for inReplyTo (→ reply)
  and quoteUrl/_misskey_quote/quoteUri/FEP-e232 tag (→ quote).
  getNotificationLabel maps both new kinds.

- i18n: add notifications.group.kind.reply/quote (EN + ES),
  home.tabs.following (EN + ES).

- NotificationsView: getGroupedNotificationLabel handles reply + quote cases.

- notificationsStore: add totalUnreadCount computed (sum of group.unreadCount).

- BottomNav: import notificationsStore, render numeric badge on bell icon
  when totalUnreadCount > 0 (capped at 99+).

- atBridgeStore: extend TimelineMode to include 'following'.

- HomeView: add 'Following' third tab → <UnifiedFeedList mode='following' />.

- atBridge API: extend feedQuery mode union to include 'following'.
  Feed route handler: when mode='following', calls resolveFollowedAuthorIds
  and filters candidateRows to followed authors only (chronological slice).
  Following feed renders chronologically like Home, not balanced.

- atBridge API: new GET /at/notifications endpoint.
  Queries atRecords targeting the current user's posts/DID for likes,
  reposts, follows, replies, quotes, and mention facets.
  Groups by kind+subjectUri, returns shape compatible with GroupedNotification.

- XRPC: new named export xrpcFeedPlugin with public
  GET /xrpc/app.bsky.feed.getFeedSkeleton endpoint.
  Accepts feed AT URI (rkey: memory-unified | memory-following | memory-latest),
  limit, and cursor. Returns { feed: [{post: atUri}], cursor? }.
  Registered on publicRoutes in index.ts.
Notifications are AP-canonical in Memory. AT-native interactions from
pure Bluesky users should be translated into AP activities by the AT→AP
bridge and delivered via ActivityPods Solid Notifications, not read
directly from the AT firehose tables.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c6717f64f8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread api/src/routes/conversations.ts Outdated
Comment thread api/src/routes/chat/chatRoutes.ts
@outlaw-dame outlaw-dame merged commit 8122510 into master May 5, 2026
1 check passed
@outlaw-dame outlaw-dame deleted the merge/ap-dm-chat-to-master branch May 5, 2026 13:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant