Skip to content

write-api: implement POST /api/people/:slug/avatar (multipart attachment + image resize) #32

Description

@themightychris

Deferred from write-api (PR #29). The plan listed POST /api/people/:slug/avatar under People mutations but didn't ship it — multipart attachment handling needs server-side image processing + gitsheets setAttachment plumbing that wasn't in scope.

Per specs/api/people.md: max 5 MB, jpeg/png/webp, store at people/<slug>/avatar.jpg, with a 128×128 thumbnail.

Required pieces:

  • @fastify/multipart plugin (or equivalent) in the API skeleton
  • Image-resize pipeline (sharp or similar) — size-cap 5MB, transcode to jpeg, write a 128×128 thumbnail
  • tx.public.openSheet('people').setAttachment(person, 'avatar.jpg', buffer) per gitsheets API
  • Auth: requireAuth('self | staff')
  • The Person.avatarKey field gets set to the attachment key on commit

Activity

  1. themightychris commented on May 16, 2026

    @themightychris
    MemberAuthor

    Heads-up: gitsheets v1.1.0 just shipped useful APIs for this

    The avatar route can now lean on first-class attachment APIs instead of poking at internals:

    • Sheet.setAttachment(record, name, blob) — already existed
    • Sheet.deleteAttachment(record, name) — new in v1.1; needed for "replace avatar" / "remove avatar" semantics
    • Sheet.deleteAttachments(record) — new in v1.1; bulk
    • Sheet.attachments(record) iterator — new in v1.1; returns {name, mimeType, blob} with .read() (Buffer) and .stream() (Readable) per blob

    Together these make the implementation cleaner:

    // upload: set the new attachment
    await tx.public.sheet('people').setAttachment(person, 'avatar.jpg', buffer);
    await tx.public.sheet('people').upsert({ ...person, avatarKey: 'people/<slug>/avatar.jpg' });
    
    // remove old (if replacing): use the new explicit delete
    await tx.public.sheet('people').deleteAttachment(person, 'avatar.jpg');

    Implementation order should still wait until the deploy plan establishes how multipart uploads land (Fastify @fastify/multipart is the obvious choice), but the storage-side primitives are now ready.

    Release notes: https://github.com/JarvusInnovations/gitsheets/releases/tag/v1.1.0

  2. added this to the Post-cutover milestone on May 20, 2026
  3. added a commit that references this issue on May 30, 2026
    80c4277
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions