# Polymorphic Feed Item Rendering

- **Pattern:** `ab-000768` (`community-social-engagement.activity-feeds.polymorphic-feed-items`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000768
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000768)

## Why it matters

A feed schema that only supports a single activity type (`post`) cannot evolve to include likes, comments, follows, or shares without a full schema migration. When type support is added ad-hoc through `if/else` chains in the renderer, each new type adds a branch, tests, and cognitive overhead — the component becomes a maintenance liability under ISO 25010:2011. More concretely, the absence of a `type` discriminator on the Activity model means you cannot query or filter by activity type, which blocks every notification and analytics feature that depends on distinguishing activity kinds.

## Severity rationale

Medium because the maintainability impact is indirect — code still works for the single type — but adding any second activity type without this structure triggers a disruptive schema migration.

## Remediation

Add a `type` discriminator field to your activity or post schema, then replace branching renderer logic with a component factory in `components/feed/ActivityRenderer.tsx`.

```ts
// Prisma schema
model Activity {
  id        String   @id @default(cuid())
  type      String   // 'post' | 'like' | 'comment' | 'follow'
  userId    String
  targetId  String?
  content   String?
  createdAt DateTime @default(now())
  user      User     @relation(fields: [userId], references: [id])
}

// components/feed/ActivityRenderer.tsx
const renderers: Record<string, React.FC<{ activity: Activity }>> = {
  post: PostActivity,
  like: LikeActivity,
  comment: CommentActivity,
  follow: FollowActivity
}

export function ActivityRenderer({ activity }: { activity: Activity }) {
  const Component = renderers[activity.type]
  return Component ? <Component activity={activity} /> : null
}
```

This pattern lets you add new activity types by registering a new entry in `renderers` without touching the router or switch logic.

## Detection

- **ID:** `polymorphic-feed-items`
- **Severity:** `medium`
- **What to look for:** Enumerate all relevant files and Examine feed components and the Post/Activity schema. Check for support of multiple activity types: posts, comments, likes, shares, follows, reactions, etc. Look for either: (a) a type discriminator field (e.g., `activity_type`, `kind`), (b) a component factory pattern that routes render logic, or (c) a schema with different tables per activity type. Verify the component avoids excessive `if` statements for each type.
- **Pass criteria:** At least 1 implementation must be present. Multiple activity types are supported by the schema (evidenced by a `type` field, separate tables, or extensible design). Components use a factory or discriminator pattern to render different activity types cleanly.
- **Fail criteria:** Only one activity type (posts) is supported, or the rendering component is a giant `if/else` block with hardcoded logic for each type.
- **Skip (N/A) when:** Feed only shows posts (single activity type).
- **Detail on fail:** `"Post table has no type field; feed only supports post activities"` or `"FeedItem component has 20+ if/else branches for different activity types"`
- **Remediation:** Use a polymorphic schema and factory component:

  ```ts
  // Prisma schema
  model Activity {
    id String @id
    type String // 'post', 'like', 'comment', 'follow'
    userId String
    targetId String? // Post ID if type is 'like'/'comment'
    content String?
    createdAt DateTime
    user User @relation(fields: [userId], references: [id])
  }

  // Component factory
  function ActivityRenderer({ activity }) {
    switch (activity.type) {
      case 'post':
        return <PostActivity activity={activity} />
      case 'like':
        return <LikeActivity activity={activity} />
      case 'comment':
        return <CommentActivity activity={activity} />
      default:
        return null
    }
  }
  ```

## External references

- iso-25010 maintainability

Taxons: code-quality

HTML version: https://auditbuffet.com/patterns/ab-000768
