## Implementation Plan
### 1. Fix Profile Posts Tab – Add Attachment Fetch
**File:** `routers/profile/index.py`
**Location:** After the posts query (lines ~170–195), where `posts` is the list of post row objects returned from the database.
**Action:** Insert a batch attachment fetch identical to `routers/feed.py:97–106`.
- Extract the list of `post_uid` values from the fetched posts.
- Call `get_attachments_by_type("post", post_uids)` (or `get_attachments_batch(post_uids)`) from the attachments service.
- Map the returned attachments to each post by UID.
- Attach the list of attachment dictionaries to each post item under the key `"attachments"` (matching the structure expected by `_post_card.html:20`).
**Rationale:** The profile template already uses `_post_card.html`, which renders attachments when the `attachments` key is present. The only missing piece is populating that key in the profile route.
---
### 2. Keep Truncation Separately Scoped (No Change)
The 300-character truncation of post body (`_post_card.html:18`) is a known limitation that affects inline embeds (YouTube URLs, etc.) beyond the 300th character. While it can cause user confusion, it is **not** the reported bug (which is about file attachments). To minimise risk of layout regressions and unrelated test failures, do **not** alter the truncation length in this change.
---
### 3. Add Tests for Attachment Rendering on Profile Posts Tab
**File:** `tests/api/profile.py` (or a new module `tests/e2e/profile.py` if e2e structure exists)
**Minimum test coverage:**
- Create a user, create a post with at least one file attachment (e.g., an image upload).
- Request the profile posts tab (`/profile/{username}?tab=posts`) via the API client.
- Assert that the response body contains the post, and under the `attachments` field (or `item.attachments`) the attachment metadata is present.
Optionally write an e2e test that uses `page.goto` to verify the HTML actually renders the attachment’s `
` or `