This commit is contained in:
+9
-2
@@ -123,9 +123,10 @@ an available listing to `CLOSED`; pending changes are available from draft or
|
||||
available listings.
|
||||
|
||||
`POST /api/v1/admin/inventory/:id/images` stores validated image metadata for an
|
||||
owned physical inventory item. File bytes are handled by the future
|
||||
owned physical inventory item. File bytes are handled through the
|
||||
`ImageStorage` adapter; JSON metadata and multipart image uploads are accepted.
|
||||
Multipart uploads require `width` and `height` fields and validate the binary
|
||||
Multipart uploads derive dimensions from image bytes; supplied `width` and
|
||||
`height` fields are ignored. They validate the binary
|
||||
signature before storage. Publication counts persisted inventory images rather
|
||||
than trusting a listing request field.
|
||||
|
||||
@@ -218,3 +219,9 @@ Image update payloads are strict:
|
||||
Malformed, missing, mistyped, oversized, or extra fields return
|
||||
`400 VALIDATION_ERROR` without a persistence write. The service also enforces
|
||||
these constraints for non-HTTP callers. Existing ownership and CSRF checks apply.
|
||||
|
||||
|
||||
Multipart image uploads inspect and decode JPEG/PNG/WebP bytes before storage.
|
||||
Responses contain measured width/height and actual byte size. Invalid decoding
|
||||
returns `400 IMAGE_DECODE_INVALID`; existing file-size, signature and dimension
|
||||
limits remain enforced. The JSON metadata-registration path is unchanged.
|
||||
|
||||
+22
-2
@@ -56,8 +56,10 @@ Validate:
|
||||
The metadata service currently enforces JPEG, PNG, and WebP MIME types, a
|
||||
10 MiB default file-size limit, and a 10,000-pixel maximum width and height.
|
||||
Multipart upload validation now checks the declared MIME type against JPEG,
|
||||
PNG, and WebP signatures before storage. Image dimensions are supplied by the
|
||||
upload transport until a decoder-backed dimension extractor is added.
|
||||
PNG, and WebP signatures before storage. The injected image inspector reads
|
||||
dimensions and format from the bytes; the service validates those dimensions
|
||||
and the actual buffer length, then verifies decoding before writing storage or
|
||||
metadata. Multipart client dimensions are ignored.
|
||||
|
||||
Generate:
|
||||
- thumbnail
|
||||
@@ -137,3 +139,21 @@ Explicit empty text or null may clear it; missing fields are invalid. The editor
|
||||
shows the limit, prevents typing past it, and flags oversized pre-existing drafts
|
||||
until corrected. Legacy absolute sort-order updates require a non-negative
|
||||
PostgreSQL integer; ordinary Move controls continue using the atomic move API.
|
||||
|
||||
|
||||
## Server-side upload inspection
|
||||
|
||||
The production `ImageInspector` uses the existing Sharp dependency behind
|
||||
`readMetadata(data)` and `validateDecoding(data)` methods. The service checks
|
||||
actual byte size before inspection, validates the 10,000-pixel dimension limit
|
||||
against inspected metadata, and only then requests decoding. Sharp rejects
|
||||
warnings/corruption and has a 100-million-input-pixel ceiling, matching the
|
||||
maximum permitted dimension product. The tiny decoded output is discarded;
|
||||
original storage and asynchronous derivatives retain their existing flow.
|
||||
|
||||
Malformed or undecodable images return `400 IMAGE_DECODE_INVALID`; format mismatch
|
||||
uses `IMAGE_SIGNATURE_INVALID`, and inspected dimension violations use
|
||||
`IMAGE_DIMENSIONS_INVALID`. Rejections happen before storage, metadata, or job
|
||||
creation. No dependency or database migration is required. The separate JSON
|
||||
metadata-registration endpoint has no uploaded bytes to inspect and retains its
|
||||
existing required dimensions; multipart uploads no longer require them.
|
||||
|
||||
@@ -120,7 +120,7 @@ docker context use orbstack
|
||||
| HTTP | Product and inventory creation, validation, authentication/recovery, CSRF, rate limiting, and session management |
|
||||
| Integration | PostgreSQL catalog/session/audit/password recovery persistence and Redis-shared login throttling |
|
||||
|
||||
Verified locally: `npm test` passes 174 tests with no failures (24 domain, 81 application, and 69 HTTP); worker tests, web tests, web build, Storybook build, Storybook interaction/accessibility checks, integration tests, and authenticated E2E workflows also pass when their required local services and credentials are available.
|
||||
Verified locally: `npm test` passes 178 tests with no failures (24 domain, 84 application, and 70 HTTP); worker tests, web tests, web build, Storybook build, Storybook interaction/accessibility checks, integration tests, and authenticated E2E workflows also pass when their required local services and credentials are available.
|
||||
|
||||
### Public Seller Description
|
||||
|
||||
@@ -184,14 +184,21 @@ Verified locally: `npm test` passes 174 tests with no failures (24 domain, 81 ap
|
||||
- Tests cover invalid requests, ownership, CSRF, missing images, boundary moves, tied positions, rollback after the first write, concurrent moves, and UI success/failure recovery.
|
||||
- Validation: 171 API tests, 26 isolated PostgreSQL/Redis integration tests, 11 web tests, production web build, Storybook build, and 32 Storybook suites / 126 tests. No migration required.
|
||||
|
||||
### Latest Vertical Slice: Image Update Validation
|
||||
### Image Update Validation
|
||||
|
||||
- Legacy order updates require a non-negative PostgreSQL integer; alt-text updates require trimmed text up to 1,000 characters or explicit null. Missing/extra/mistyped fields are rejected before persistence.
|
||||
- Domain validation protects non-HTTP service callers as well. Authentication, CSRF and seller ownership remain unchanged.
|
||||
- The alt-text editor shows its limit, trims saved drafts, prevents oversized input and gives associated accessible feedback for oversized pre-existing text.
|
||||
- Validation: 174 API tests, 26 isolated integration tests, 11 web tests, production web build, Storybook build, and 32 Storybook suites / 128 tests. No migration required.
|
||||
|
||||
Next bounded slice: server-derived upload dimensions. `docs/IMAGES.md` identifies that upload dimensions are still supplied by the client. Decode image metadata behind an injected image-inspection interface, enforce dimension limits on actual bytes, and test forged dimensions and malformed images through upload validation.
|
||||
### Latest Vertical Slice: Server-Derived Upload Dimensions
|
||||
|
||||
- Multipart uploads ignore client dimensions and persist inspected width/height plus actual buffer length. An injected Sharp inspector validates metadata and decoding before storage, metadata writes or job creation.
|
||||
- Existing MIME signatures, 10 MiB byte limit and 10,000-pixel dimension bounds remain enforced; decoder work is pixel-bounded. JSON metadata registration retains its separate existing contract.
|
||||
- Tests use actual JPEG/PNG/WebP data and cover forged/missing dimensions, forged byte counts, oversized dimensions, signature-only images and truncated pixel data whose header remains readable.
|
||||
- Validation: 178 API tests, 26 isolated integration tests, 11 web tests, production web build, Storybook build, and 32 Storybook suites / 128 tests. Existing Sharp dependency reused; no migration or visual changes.
|
||||
|
||||
Next bounded slice: enforce the configured per-item image count limit. `docs/IMAGES.md` requires configurable image counts and Settings exposes the limit, but image creation currently checks only individual-file metadata. Enforce the seller's limit atomically for uploads/metadata registration, reject excess images clearly, and cover concurrent uploads and UI feedback.
|
||||
|
||||
## Next Milestone
|
||||
|
||||
|
||||
Reference in New Issue
Block a user