# Expo Chat Avatars Implementation Plan

> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Show participant avatars in the Expo chat timeline for both incoming and outgoing message groups with a clean initial fallback.

**Architecture:** Keep avatar data sourced from `useTabloMembers(channelId)` and the authenticated user already available in Expo state. Extract sender display resolution into a pure helper with tests, then update the channel screen to render remote images when present and initial badges when the URL is missing or fails to load.

**Tech Stack:** Expo SDK 54, React Native, Expo Router, TypeScript, Jest Expo, ESLint Expo.

**Spec:** `docs/superpowers/specs/2026-04-19-expo-chat-avatars-design.md`

---

## File Structure

### New files
- `xtablo-expo/features/chat/messageAuthor.ts` — pure sender display resolution helper for chat message groups
- `xtablo-expo/features/chat/messageAuthor.test.ts` — helper tests for avatar and name fallback behavior

### Modified files
- `xtablo-expo/app/(app)/channel/[cid].tsx` — render avatars for both sides and handle image fallback

### Existing files used as references
- `xtablo-expo/hooks/members.ts`
- `xtablo-expo/stores/auth.tsx`
- `xtablo-expo/app/(app)/user/index.tsx`

---

## Chunk 1: Add Sender Display Helper

### Task 1: Create a pure helper for author display data

**Files:**
- Create: `xtablo-expo/features/chat/messageAuthor.ts`
- Create: `xtablo-expo/features/chat/messageAuthor.test.ts`

- [ ] **Step 1: Write the failing test**

Add focused tests for:
- member data lookup by `userId`
- current-user fallback when member data is missing
- avatar suppression after a tracked image failure
- safe initial/name fallback when sender data is incomplete

- [ ] **Step 2: Run the test to verify it fails**

Run:

```bash
cd xtablo-expo && npx jest --runInBand --watchman=false features/chat/messageAuthor.test.ts
```

Expected: FAIL because the helper file does not exist yet.

- [ ] **Step 3: Write the minimal helper**

Implement a pure helper that returns:

```ts
type MessageAuthorDisplay = {
  name: string;
  avatarUrl: string | null;
  initial: string;
};
```

Rules:
- prefer member data from the current channel
- for the authenticated user, fall back to Expo auth user data
- if the avatar is marked failed for that user id, return `null`
- derive a stable initial with a default fallback of `U`

- [ ] **Step 4: Run the helper test to verify it passes**

Run:

```bash
cd xtablo-expo && npx jest --runInBand --watchman=false features/chat/messageAuthor.test.ts
```

Expected: PASS

---

## Chunk 2: Integrate Avatars Into The Channel Screen

### Task 2: Render message-group avatars on both sides

**Files:**
- Modify: `xtablo-expo/app/(app)/channel/[cid].tsx`
- Use: `xtablo-expo/features/chat/messageAuthor.ts`

- [ ] **Step 1: Confirm the current screen still uses initial-only avatars**

Run:

```bash
rg -n "avatarText|Image|avatar_url" "xtablo-expo/app/(app)/channel/[cid].tsx"
```

Expected: the file contains initial badge styles and member lookups, but no chat-avatar image rendering path.

- [ ] **Step 2: Update the screen to resolve sender display**

Add:
- authenticated user read from `useAuthStore`
- local failed-avatar state keyed by user id
- helper-based sender display resolution for each message group

- [ ] **Step 3: Render remote avatars with fallback**

Update the sender-row renderer to:
- use `Image` when `avatarUrl` exists
- fall back to the existing initial badge otherwise
- mark the user id as failed on `Image` load error
- show the sender row for both incoming and outgoing groups
- keep outgoing groups right-aligned

- [ ] **Step 4: Run verification**

Run:

```bash
cd xtablo-expo && npx jest --runInBand --watchman=false features/chat/messageAuthor.test.ts
cd xtablo-expo && npx tsc --noEmit
cd xtablo-expo && npm run lint
```

Expected:
- helper tests pass
- TypeScript passes
- lint reports no new errors from the chat screen change

---

## Chunk 3: Manual Validation

### Task 3: Check a live chat thread

**Files:**
- No additional file changes required

- [ ] **Step 1: Run the Expo app**

Run one of:

```bash
cd xtablo-expo && npm run ios
```

or

```bash
cd xtablo-expo && npx expo start --dev-client
```

- [ ] **Step 2: Validate avatar behavior**

Manual checks:
- participant avatars appear for both incoming and outgoing groups when URLs exist
- missing avatars fall back to initials
- broken avatar URLs fall back to initials after load failure
- sender-row alignment still looks correct on both sides
