Wire PostHog funnel events (started, step viewed/completed, mode, workspace, sources, ingest, team, completed) across the brain onboarding flow, and drop stale pre-brain event defs from analytics.ts.
---
**Session Details**
- Session: [View Session](https://supermemory.us1.vorflux.com/agent-sessions/5b48bbe4-422a-4577-b6bf-fd9416a6846b)
- Requested by: Sreeram Sreedhar (sreeram@supermemory.com)
- Address comments on this PR. Add `(aside)` to your comment to have me ignore it.
## Summary
- Delay opening the delete organization dialog until after the Danger zone popover begins closing
- Explicitly focus the organization confirmation input when the dialog opens
- Prevent intermittent focus loss where users could not type the org name
## What
The X bookmarks ("Import X bookmarks") card on the integrations page never reflected any state, even after importing tweets — unlike connectors and plugins, which show "Connected"/"Active".
After this change, once you've imported at least one tweet the card shows an **"Imported · {last import time}"** pill (mirroring the plugin "Active · {time}" style) and is included in the **Connected** filter.
Since importing X bookmarks is a one-time/occasional action rather than a live connection, it intentionally says **"Imported"** with the last-import timestamp, not "Connected".
## Why
The page's status logic (`isItemConnected` + `renderStatus`) only handled the `plugin` and `connector` item kinds. The X bookmarks card is an `import` kind, so it always rendered just "Connect". This was a regression from #979 (the integrations overhaul), which rebuilt the page around item kinds and dropped the previous "{N} tweets imported" indicator.
## How
- Add a single documents query (`@post/documents/documents`, `categories: ["tweet"]`, `limit: 1`, newest first) that yields both the org-wide tweet count (`pagination.totalItems`) and the latest tweet's `createdAt`.
- `isItemConnected` returns `true` for `import` when the count is `> 0`.
- `renderStatus` renders a new `ImportedPill` ("Imported · {relative time}") for `import` when there's ≥1 tweet.
## Testing
- `tsc` and Biome pass; no new errors introduced by this change.
- Verified the status source of truth against a local backend by seeding `type='tweet'` documents — the count/latest-timestamp the pill renders reflect them.
> Note: `tsc` reports two **pre-existing**, unrelated `granola` errors in this file (`CONNECTOR_META` + an icon record missing the `granola` provider). They exist on `main` and are not touched by this PR.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
### TL;DR
Adds a Weekly Digests view to the web app, allowing users to browse and read their personalized weekly memory recaps directly in the UI, along with a notification preference toggle to opt out of digest emails.
### What changed?
- Added a new `digests` view mode that renders a `DigestsView` component, accessible from the dashboard via a new weekly digest preview card that appears when a digest exists.
- `DigestsView` displays a master-detail layout: a scrollable list of past weekly digests on the left, and a full digest content pane on the right. The detail pane renders the intro (with a floating brain illustration), numbered highlights, and feature recommendations styled to mirror the email layout.
- Added thumbs-up/thumbs-down feedback controls and an optional free-text input on each digest, wired to analytics events.
- Added `useDigests` and `useDigest` hooks that fetch digest list and detail data from the API, with 5- and 10-minute stale times respectively.
- Registered four new API schema endpoints: `GET /digests`, `GET /digests/:id`, `GET /digests/preferences`, and `POST /digests/preferences`.
- Added a `DigestPreferences` section to the account settings page with a toggle that lets users opt in or out of the weekly digest email.
- Extended the `viewModeChanged` analytics event and the `viewLiterals` search param list to include `"digests"`, and added `digestViewed`, `digestFeedback`, and `digestFeedbackDetail` analytics events.
- Added documentation for the `SUPERMEMORY_EMBEDDING_RAM_LIMIT` and `SUPERMEMORY_INGEST_CONCURRENCY` environment variables, explaining the memory-bounded ingestion queue and its live terminal status output.
### How to test?
1. Navigate to the dashboard and confirm the weekly digest preview card appears when a digest exists, and clicking it transitions to the `digests` view.
2. In the digests view, verify the list renders past digests with the most recent highlighted by a gradient border, and selecting a row loads the correct detail content.
3. Confirm the empty state renders correctly when no digests exist.
4. Use the thumbs-up/thumbs-down buttons and the detailed feedback textarea on a digest, verifying the toast confirmation appears on submission.
5. Open account settings, locate the "Notifications" section, and toggle the weekly digest switch on and off, verifying the preference persists without errors.
6. Confirm the `digests` view mode is reflected in the URL search params when active.
### Why make this change?
Users currently receive weekly digest emails but have no way to revisit past digests within the app. This change surfaces digest history directly in the UI, adds in-product feedback collection on digest quality, and gives users control over whether they receive the emails — improving discoverability, engagement, and preference management.
## Problem
On the integrations page → **Knowledge bases** section, a connected connector card (e.g. Google Drive) rendered the green **"Connected"** pill **twice** — once on the bottom-left, and again on the bottom-right next to the `+` button.
## Cause
The `ConnectionsCountPill` was rendered in two slots of the card:
- `renderStatus()` → left `statusSlot`
- `renderRight()` → right `actionSlot` (alongside the `+` add-source button)
The `renderStatus` connector case was added recently (#1065) and duplicated the pill that `renderRight` already shows.
## Fix
Removed the `connector` case from `renderStatus()` so the pill renders **only on the right**, in place of the Connect button. The logic is keyed on `kind === "connector"`, so this fixes every Knowledge-bases card uniformly — **Google Drive, Notion, OneDrive, Granola**.
- Non-connected cards still show the **Connect** button (unchanged).
- The info modal is unaffected — it renders `infoActionSlot ?? actionSlot` and never `statusSlot`.
```diff
- case "connector": {
- const count = connectionsByProvider[item.provider].length
- if (count <= 0) return null
- return <ConnectionsCountPill count={count} />
- }
default:
return null
```
## Testing
Minimal, self-contained deletion (no new code, no unused symbols). Local `tsc` not run in this worktree because `node_modules` isn't installed here; the change leaves valid syntax and `ConnectionsCountPill`/`connectionsByProvider` remain used by `renderRight`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
- move Granola from Max-gated to Pro-gated in Nova integrations and add-connection flows
- add Granola to Pro plan card connector copy in billing
- update Granola connector docs to say Pro Plan or higher
## Testing
- bunx biome check apps/web/components/settings/billing.tsx apps/web/components/integrations-view.tsx apps/web/components/add-document/connections.tsx apps/docs/connectors/granola.mdx
- git diff --check
Note: onboarding-brain was intentionally left unchanged.