โ† Pattern library

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.

collabactivityfeedauditlogtimeline
โœจ Built using these library patterns:
activity-feed

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

    StateDescriptionTransitions
    IdleNo new activities to record
    • User actionโ†’Recording
    RecordingPersisting activity event
    • Persistedโ†’Idle
    DisplayingUser viewing the feed
    • Closedโ†’Idle
    • New activity arrives via realtimeโ†’Displaying

    Easy-to-miss situations

    The kinds of edge cases that break demos.

    • What if a high-volume bot generates 10,000 activities per hour?

      medium

      Feed 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?

      medium

      Click 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?

      medium

      Queries 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?

      high

      User 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?

      high

      Conflict 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.

    Build a flow starting from this pattern โ†’