feat(F-056): completed feature
This commit is contained in:
87
work/artifacts/F-056/implementer.md
Normal file
87
work/artifacts/F-056/implementer.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# F-056 — Implementer evidence
|
||||
|
||||
## Scope delivered
|
||||
|
||||
Two distinct defects were addressed in this branch:
|
||||
|
||||
1. **Uploads 404 / 502 on freshly uploaded files.** Next.js caches the
|
||||
`public/` directory listing at server start, so any file written to
|
||||
`public/uploads/` after `next start` returns 404 from the static handler and
|
||||
`next/image` answers 502 because its upstream fetch fails.
|
||||
2. **Product detail image overflows its container** because the wrapper had
|
||||
no positioning context for `next/image fill`.
|
||||
|
||||
## Changes
|
||||
|
||||
### 1. Dynamic uploads route (per app)
|
||||
|
||||
Three new route handlers were added — one per Next.js frontend
|
||||
(`apps/admin`, `frontend`, `storefront`). Each reads uploads from the local
|
||||
`public/uploads/` and the canonical `apps/admin/public/uploads/` directory on
|
||||
every request, so a freshly uploaded file resolves without restart or rebuild:
|
||||
|
||||
- `project/apps/admin/src/app/uploads/[...path]/route.ts`
|
||||
- `project/frontend/src/app/uploads/[...path]/route.ts`
|
||||
- `project/storefront/src/app/uploads/[...path]/route.ts`
|
||||
|
||||
Each handler:
|
||||
|
||||
- Sets `dynamic = 'force-dynamic'` so Next.js does not cache the route at build.
|
||||
- Validates the path against `SAFE_SEGMENT = /^[A-Za-z0-9._-]+$/` to block traversal.
|
||||
- Maps a known extension to a content type and serves the file with
|
||||
`Cache-Control: public, max-age=31536000, immutable`.
|
||||
- Generates the `40` and `200` thumbnails on demand via `sharp` and caches them
|
||||
on disk, so `/uploads/40/<file>` and `/uploads/200/<file>` resolve without
|
||||
requiring `generate-thumbnails.sh`.
|
||||
|
||||
### 2. Inline thumbnail generation on upload
|
||||
|
||||
`project/apps/admin/src/app/api/upload/route.ts` now calls `generateThumbnails`
|
||||
immediately after `mirrorToPeers`, producing the 40 and 200 px variants in every
|
||||
mirror location. Failures are non-fatal: the dynamic handler above regenerates
|
||||
the missing thumbnail on the next request.
|
||||
|
||||
### 3. Product detail image container
|
||||
|
||||
`project/frontend/src/app/products/[slug]/page.tsx` adds the `relative` class
|
||||
to the image wrapper so `next/image fill` is positioned correctly inside the
|
||||
`max-h-[500px] overflow-hidden` container. The image stays inside its box on
|
||||
all viewports.
|
||||
|
||||
## Acceptance traceability
|
||||
|
||||
| Acceptance criterion | How it is met |
|
||||
| -------------------- | ------------- |
|
||||
| New upload file loads 200 without server restart | Dynamic `/uploads/[...path]/route.ts` reads from disk per request. Verified with curl on a freshly uploaded file. |
|
||||
| Thumbs 40 and 200 exist right after upload | `generateThumbnails` runs inline in `/api/upload` after `mirrorToPeers`. |
|
||||
| `next/image` no more 502 for fresh uploads | Static 404 (which became 502 upstream) is replaced by the dynamic handler that returns 200 from disk. |
|
||||
| Product detail image stays inside its box | `relative` class added so `next/image fill` is contained by `aspect-square max-h-[500px] overflow-hidden`. |
|
||||
|
||||
## Commands run during build
|
||||
|
||||
- `pnpm --filter ./project/apps/admin exec tsc --noEmit` — typecheck pass.
|
||||
- `pnpm --filter ./project/frontend exec tsc --noEmit` — typecheck pass.
|
||||
- `pnpm --filter ./project/storefront exec tsc --noEmit` — typecheck pass.
|
||||
- `./scripts/verify.sh` — exit code 0.
|
||||
- Manual curl: `/uploads/40/8223b962-642c-4c95-bc2e-37c2d2fad4ac.jpg` →
|
||||
HTTP 200, 568 bytes.
|
||||
|
||||
## Files touched
|
||||
|
||||
```
|
||||
project/apps/admin/src/app/api/upload/route.ts (modified)
|
||||
project/apps/admin/src/app/uploads/[...path]/route.ts (new)
|
||||
project/frontend/src/app/uploads/[...path]/route.ts (new)
|
||||
project/frontend/src/app/products/[slug]/page.tsx (modified)
|
||||
project/storefront/src/app/uploads/[...path]/route.ts (new)
|
||||
```
|
||||
|
||||
## Artifacts produced
|
||||
|
||||
- `project/apps/admin/public/uploads/40/<file>.jpg` — generated inline by upload route.
|
||||
- `project/frontend/public/uploads/40/<file>.jpg` — generated inline by upload route.
|
||||
- `project/storefront/public/uploads/40/<file>.jpg` — generated inline by upload route.
|
||||
|
||||
## Status
|
||||
|
||||
Build completed. Ready for reviewer/security/qa gates.
|
||||
Reference in New Issue
Block a user