mirror of
https://github.com/saltbo/zpan.git
synced 2026-09-19 01:51:11 +08:00
* feat(avatars): host avatars + team logos on Cloud via SDK 2.4.0; remove public-bucket mode Host user avatars and org logos on the ZPan Cloud avatar service (zpan-cloud-sdk ^2.4.0) instead of a public S3/R2 bucket, then remove the now-dead storages.mode / public-bucket concept entirely (#456 parts 2-3). - image-upload gateway: upload/delete via SDK uploadAvatar/deleteAvatar against a bound Cloud client; validate mime (AVATAR_CONTENT_TYPES) + size (MAX_AVATAR_BYTES) before the call; map cloud error codes to 400/403/413/500; unbound instance returns 503 cloud_required (delete is a best-effort no-op). - licensing-cloud: createAvatarUploadClient builds the client with a plain-object bearer header so both the image content-type and Authorization survive hono's per-request header merge (a Headers instance would be dropped). - drop storages.mode (migration via drizzle-kit), StorageRepo.select() no longer takes a mode, remove StorageMode / Storage.mode / mode schema+audit+UI+i18n and the PUBLIC_IMAGES bucket + PUBLIC_IMAGES_URL wiring. Agent-Profile: https://agent-kanban.dev/agents/f759c704c282d88a * ci(deploy): drop dead PUBLIC_IMAGES R2 provisioning from CF deploy The Cloud avatar migration removed the PUBLIC_IMAGES binding from wrangler.toml, so the deploy workflow's R2 public-images steps are dead and must go too — otherwise every CF deploy keeps re-provisioning a public-read zpan-public-images bucket (the footgun #456 eliminates) and sets an unused PUBLIC_IMAGES_URL secret. Removes the bucket-create, managed-public-URL, and secret steps (steps.r2 was only consumed by the secret step). Also drops a stale storage-modes line from the v2.0 roadmap. Agent-Profile: https://agent-kanban.dev/agents/f759c704c282d88a --------- Co-authored-by: Alex Chen <alex-chen@mails.agent-kanban.dev>
60 lines
2.2 KiB
Gherkin
60 lines
2.2 KiB
Gherkin
Feature: Avatar
|
|
Authenticated users upload a personal avatar image, hosted on the ZPan Cloud
|
|
avatar service and surfaced as a URL on their profile. Uploads are validated
|
|
locally (mime + size) before the Cloud call, and require the instance to be
|
|
paired to Cloud.
|
|
|
|
@avatar/auth-required @api
|
|
Scenario: Uploading an avatar requires authentication
|
|
Given an unauthenticated request
|
|
When it uploads an avatar
|
|
Then the API responds 401
|
|
|
|
@avatar/multipart-required @api
|
|
Scenario: Avatar upload must be multipart
|
|
Given an authenticated user
|
|
When they upload with a non-multipart content type
|
|
Then the API responds 415
|
|
|
|
@avatar/file-required @api
|
|
Scenario: Avatar upload must include a file
|
|
Given an authenticated user
|
|
When they submit with no file field
|
|
Then the API responds 400
|
|
|
|
@avatar/mime-validated @api
|
|
Scenario: Avatars must be a supported image type
|
|
Given an authenticated user
|
|
When they upload a non-image file
|
|
Then the API responds 400 before any Cloud call
|
|
|
|
@avatar/size-limit @api
|
|
Scenario: Avatars are size-limited
|
|
Given an authenticated user
|
|
When they upload a file larger than 1 MiB
|
|
Then the API responds 413 before any Cloud call
|
|
|
|
@avatar/needs-cloud @api
|
|
Scenario: Avatar upload needs the instance paired to Cloud
|
|
Given an instance with no active Cloud license binding
|
|
When an authenticated user uploads an avatar
|
|
Then the API responds 503 cloud_required
|
|
|
|
@avatar/upload @api
|
|
Scenario: A valid avatar is hosted on Cloud and returned
|
|
Given an authenticated user on a Cloud-paired instance
|
|
When they upload a valid image
|
|
Then it is sent to the Cloud avatar service with the image content type, recorded on the user, and its URL is returned
|
|
|
|
@avatar/delete @api
|
|
Scenario: A user clears their avatar
|
|
Given a user with an avatar on a Cloud-paired instance
|
|
When they delete it
|
|
Then the image is cleared and the Cloud avatar is deleted
|
|
|
|
@avatar/delete-unbound @api
|
|
Scenario: Clearing an avatar succeeds without a Cloud binding
|
|
Given a user with an avatar on an instance not paired to Cloud
|
|
When they delete their avatar
|
|
Then it succeeds and the Cloud delete is skipped
|