Person pages need a direct way to answer which attachments a contact sent,
received, or shared in a conversation without filtering the archive-wide
Files workspace by hand.
- Add bounded person-scoped attachment search with exact identity, role,
conversation, source, and deletion provenance.
- Expose the search through the API and generated Go and web clients, with
compatible defaults for clients that omit direction filters.
- Add separate Media and Files presentations with safe bounded previews and
links back to each attachment's owning message.
- Page scalar entry data before participant enrichment and restrict person
role aggregation to attachment-bearing messages.
- Preserve direct-chat and broad conversation-roster relationships across
legacy conversation types.
- Publish schema version 1.45.0 and accept valid empty filename and MIME
metadata in generated clients.
- Rebind virtual-grid measurement and resize observation whenever conditional
Media and Files views replace their DOM elements.
Attachments remain message-owned, so identity linking and splitting changes
gallery membership without moving or duplicating blobs.
Refs kenn-io#612
Generated with Codex
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Wes McKinney <wesmckinn+git@gmail.com>
Co-authored-by: Codex <noreply@openai.com>
# Conflicts:
# internal/api/openapi.go
# internal/api/openapi_test.go
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Author: salmonumbrella <182032677+salmonumbrella@users.noreply.github.com>
#
# interactive rebase in progress; onto f07c23a
# Last command done (1 command done):
# pick 207ef003 # feat(web): add person attachment galleries
# No commands remaining.
# You are currently rebasing branch 'feat/person-attachment-gallery' on 'f07c23a8'.
#
# Changes to be committed:
# modified: api/openapi.yaml
# modified: internal/api/explore_e2e_test.go
# modified: internal/api/files.go
# modified: internal/api/files_test.go
# modified: internal/api/openapi.go
# modified: internal/api/openapi_test.go
# modified: internal/codegenfix/fix.go
# modified: internal/codegenfix/fix_test.go
# modified: internal/query/explore_fastpath_test.go
# modified: internal/query/files.go
# modified: internal/query/files_test.go
# modified: pkg/client/client_test.go
# modified: pkg/client/generated/enums.go
# modified: pkg/client/generated/payloads.go
# modified: pkg/client/generated/responses.go
# modified: pkg/client/generated/types.go
# modified: pkg/client/openapi.yaml
# modified: web/src/lib/api/generated/schema.d.ts
# modified: web/src/lib/components/files/FilesWorkspace.svelte
# modified: web/src/lib/components/files/FilesWorkspace.test.ts
# new file: web/src/lib/components/files/MediaThumbnail.svelte
# new file: web/src/lib/components/files/MediaThumbnail.test.ts
# new file: web/src/lib/components/files/PersonMediaGallery.svelte
# new file: web/src/lib/components/files/PersonMediaGallery.test.ts
# modified: web/src/lib/components/files/preview-bytes.test.ts
# modified: web/src/lib/components/files/preview-bytes.ts
# new file: web/src/lib/components/files/thumbnail-queue.ts
# modified: web/src/lib/components/relationships/RelationshipsWorkspace.svelte
# modified: web/src/lib/components/saved-views/SavedViewsWorkspace.test.ts
# modified: web/src/lib/components/shell/AppShell.svelte
# modified: web/src/lib/explore/models.ts
# modified: web/src/lib/explore/state.svelte.ts
# modified: web/src/lib/explore/state.test.ts
# modified: web/tests/e2e/accessibility.spec.ts
# modified: web/tests/relationships.spec.ts
#
What changed
POST /api/v1/people/{id}/files/searchand regenerate the Go and web clients from the OpenAPI spec. SQLite and PostgreSQL behavior stays equivalent, and there is no schema or migration change.Why
A person page could not answer "what files did this contact send me?" without falling back to the archive-wide Files workspace and filtering by hand, which cannot follow one person across linked identities and channels. Scoping the existing file search to an identity cluster answers it directly, and because the attachment occurrence stays with its message, linking or splitting identities changes gallery membership without moving or duplicating blobs.
Usage
Open a person in the web UI and use the Files view. Results default to files received from that person; the direction controls add files sent to them or exchanged in group conversations, and the Media/Files toggle switches between the thumbnail gallery and the existing table.
Semantic search inside the person-scoped result set is deliberately out of scope here — it depends on the document and multimodal indexes in #608 and #609.
Refs #612