Collaboration
Activity Feed
A chronological stream showing what happened on a resource or for a user โ who changed what, when. Foundation of audit trails and "what's new" sections.
When to use this
When users need transparency on changes (collaborative tools, B2B SaaS, compliance-required apps). Always for sensitive actions.
What I assumed
I made these guesses to fill gaps. Let me know if any are wrong.
Flow diagram
Step-by-step recipe
Copy this and paste into Cursor, Claude Code, or v0.
PATTERN: Activity Feed
INPUT: actor, action_type, resource, metadata
OUTPUT: activity_record, optional_aggregated_view
EMIT_STEPS (every meaningful action):
1. Identify "feed-worthy" actions in your app (created, updated, deleted, shared, commented)
2. After action succeeds, emit activity event:
- actor_id (who did it)
- action_type (verb: created, edited, deleted, shared, etc.)
- resource_type + resource_id (what was acted on)
- metadata (e.g., before/after values for edits)
- timestamp
3. Persist in append-only activities table (never edit/delete activity records)
4. Optionally fan-out to subscribers via realtime channel
DISPLAY_STEPS (rendering feed):
1. User opens feed view (resource-scoped or personal)
2. Query activities, paginate (cursor-based, newest first)
3. For each activity, look up actor and resource details
4. Format as natural language: "Alice updated the design at 3:42pm"
5. Group similar consecutive actions: "Alice made 3 edits in last 5 min"
6. Render with link back to the resource state at that time (if possible)
AGGREGATION_STEPS (smart compaction):
1. Group by actor + resource + 5-min window
2. Show "Alice and 3 others edited" instead of 4 separate entries
3. Keep raw events queryable for audit even when aggregated for display
ERROR_HANDLING:
- Activity emit fails โ log error but don't block the user action (best-effort)
- Resource deleted โ show "Alice edited [deleted document]" with grayed-out link
- Actor deleted โ show "[deleted user] edited X"
- High-volume actor (bot) โ throttle display, keep raw events
EXTENSION_POINTS:
- Filter by actor / type / date (composable_with: ["filter-ui"])
- Subscribe to feed entries via email digest (composable_with: ["notification"])
- Real-time updates push new entries to viewers (composable_with: ["realtime-share"])
- Export for compliance / audit reports
States โ how things change
| State | Description | Transitions |
|---|---|---|
| Idle | No new activities to record |
|
| Recording | Persisting activity event |
|
| Displaying | User viewing the feed |
|
Easy-to-miss situations
The kinds of edge cases that break demos.
What if a high-volume bot generates 10,000 activities per hour?
mediumFeed becomes unreadable spam.
Suggested handling: Aggregate by actor + action type into single line: "Bot Alice did 247 edits in last hour [expand]". Keep raw events accessible for audit but hide from default view.
What if an activity references a deleted resource?
mediumClick leads to 404, breaks user trust.
Suggested handling: Soft-delete resources OR keep "tombstone" record for activity feed. Show "Alice edited [Document โ deleted on date]" with grayed-out link. Don't render broken links.
What if the activity log grows to billions of rows?
mediumQueries become slow, storage costs balloon.
Suggested handling: Time-based partitioning (monthly partitions). Archive >1yr old to cold storage. Index by (resource_id, created_at desc) for fast feed queries. Use cursor pagination, not offset.
What if the feed displays sensitive info to unauthorized viewers?
highUser B sees that user A renamed a file they shouldn't even know exists.
Suggested handling: Filter activity rendering by viewer's permission to see the resource. Don't expose existence by listing the activity at all if viewer lacks resource access. Server-side enforcement, not client-side.
What if a user wants to delete their own activity history?
highConflict between user privacy (GDPR right to erasure) and audit/compliance.
Suggested handling: For GDPR/CCPA compliance, anonymize (replace actor_id with "[deleted user]") rather than delete records. Keep action records for audit but strip personal identifiers. Document this in privacy policy.
Composes well with
Combine these patterns when you need a richer flow.