feat(ADM-018): completed feature

This commit is contained in:
chattie
2026-08-17 22:23:10 +02:00
parent cf1c69fc8b
commit d595b4871f
871 changed files with 47411 additions and 281 deletions

View File

@@ -0,0 +1,55 @@
# Architect — F-014 Storefront catalog pages (SSG/ISR)
## Decision
Implement catalog pages in the existing `project/storefront/` Next.js App Router package. Keep the frontend isolated from backend internals and consume only public HTTP endpoints through `src/lib/api.ts`.
## Routes
Add server-rendered catalog routes:
- `app/productos/[slug]/page.tsx`: product detail at `/productos/<slug>`.
- `app/categoria/[slug]/page.tsx`: category listing at `/categoria/<slug>`.
- `app/marca/[slug]/page.tsx`: brand listing at `/marca/<slug>`.
- `app/products/search/page.tsx`: search results page using `q`, `brandSlug`, `categorySlug`, `limit`, `offset` query params.
## Rendering model
- Use React Server Components only for this slice.
- Export `revalidate = 300` on catalog pages for ISR.
- Do not generate static params from backend at build time yet; return `[]` from `generateStaticParams()` and allow dynamic ISR generation on first request.
- Backend unavailable at build must not fail the build.
## On-demand revalidation
Add `app/api/revalidate/route.ts`:
- POST-only JSON body `{ "path": "/productos/foo" }`.
- Require `REVALIDATE_SECRET`; request must send matching `x-revalidate-secret` header.
- Validate path is local and belongs to supported public catalog routes.
- Call `revalidatePath(path)` and return JSON.
## API client
Extend `src/lib/api.ts`:
- Add typed `CategoryDto` and `BrandDto`.
- Add `getCategoryBySlug(slug)` and `getBrandBySlug(slug)`.
- Extend `searchProducts` input with `categorySlug`.
- Keep client `server-only`.
Backend support:
- Add optional `categorySlug` filter to public product search so category pages can list products without importing backend internals.
- Preserve existing `/products/search` API shape.
## Metadata and OpenGraph
Each route must export `generateMetadata`:
- Product: title/description from SEO fields or product name/description, canonical `/productos/<slug>`, OG title/description/url/images when product image exists.
- Category: title/description from SEO fields or category name, canonical `/categoria/<slug>`.
- Brand: title/description from SEO fields or brand name, canonical `/marca/<slug>`.
- Search: title reflects the query when present and canonical `/products/search`.
## SEO/Lighthouse basics
- Use semantic headings, descriptive links, visible text content, metadata and OG tags.
- Avoid client JavaScript in this slice.
- No cart, checkout UI, auth UI, or full structured-data module here.
## Quality evidence
Required:
- `cd project/storefront && npm run lint && npm run typecheck && npm run build && npm run lint`
- `cd project && npm run lint && npm run typecheck && npm test`
- `./scripts/verify.sh`
Lighthouse evidence can be structural/build evidence in this environment unless browser Lighthouse tooling is available.

View File

@@ -0,0 +1,17 @@
# Documenter — F-014 Storefront catalog pages (SSG/ISR)
## Documentation updated
- Updated `project/README.md` catalog section to document `categorySlug` search filtering.
- Updated `project/README.md` storefront section to document:
- Product detail pages at `/productos/<slug>`.
- Category pages at `/categoria/<slug>`.
- Brand pages at `/marca/<slug>`.
- Search results at `/products/search`.
- ISR settings for product/category/brand pages and search results.
- Metadata, canonical URL and OpenGraph behavior.
- On-demand revalidation via `POST /api/revalidate` with `REVALIDATE_SECRET` and `x-revalidate-secret`.
- Cart and checkout UI remain out of scope.
## Evidence
- `cd project && npm run lint` — PASS after README update.
- `./scripts/verify.sh` — PASS after README update.

View File

@@ -0,0 +1,47 @@
# Implementer — F-014 Storefront catalog pages (SSG/ISR)
## Summary
Implemented storefront catalog pages for product detail, category listing, brand listing and search results using Next.js App Router server components, ISR, per-page metadata/OpenGraph, typed public API client functions and on-demand revalidation.
## Code changes
- Extended backend public search filter:
- `project/src/modules/catalog/domain/product.ts` adds `categorySlug` to search criteria.
- `project/src/modules/catalog/application/product-use-cases.ts` forwards `categorySlug`.
- `project/src/modules/catalog/api/catalog.routes.ts` accepts/logs `categorySlug` on `/products/search`.
- `project/src/modules/catalog/infrastructure/pg-product-search-repository.ts` filters products by category slug through public catalog/category tables.
- `project/src/modules/catalog/tests/product-use-cases.test.ts` covers forwarding `brandSlug` and `categorySlug` through the search port.
- Extended storefront API client:
- `project/storefront/src/lib/api.ts` adds `CategoryDto`, `BrandDto`, `getCategoryBySlug`, `getBrandBySlug`, `listCategoryTree`, and `categorySlug` search input.
- `project/storefront/src/lib/seo.ts` centralizes site URL/title helpers.
- Added catalog UI:
- `project/storefront/src/components/product-card.tsx`.
- `project/storefront/src/app/productos/[slug]/page.tsx` product detail route.
- `project/storefront/src/app/categoria/[slug]/page.tsx` category listing route.
- `project/storefront/src/app/marca/[slug]/page.tsx` brand listing route.
- `project/storefront/src/app/products/search/page.tsx` search results route.
- Added on-demand revalidation:
- `project/storefront/src/app/api/revalidate/route.ts` validates `REVALIDATE_SECRET` with `timingSafeEqual`, accepts supported catalog paths only, and calls `revalidatePath`.
## Rendering/SEO behavior
- Product/category/brand pages export `revalidate = 300` and `generateStaticParams() { return []; }`, allowing SSG/ISR generation without requiring a live backend at build time.
- Search page exports `revalidate = 120`.
- Search page bounds displayed/metadata query text to 200 characters before rendering or metadata generation.
- Product/category/brand/search pages export `generateMetadata` with title, description, canonical URL and OpenGraph data.
- Product page uses `/productos/<slug>` and never exposes internal ids in the URL.
- All pages are server components; no client components added.
## Evidence
- `cd project/storefront && npm run lint` — PASS.
- `cd project/storefront && npm run typecheck` — PASS.
- `cd project/storefront && npm run build` — PASS; Next output shows SSG routes for `/productos/[slug]`, `/categoria/[slug]`, `/marca/[slug]` and dynamic `/products/search` plus `/api/revalidate`.
- `cd project/storefront && npm run lint` after build — PASS.
- `cd project && npm run lint` — PASS.
- `cd project && npm run typecheck` — PASS.
- `cd project && npm test` — PASS: 17 files passed, 7 skipped; 64 passed, 33 skipped.
- `./scripts/verify.sh` — PASS.
- Internal review correction run: bounded search query text in search page, then storefront lint/typecheck/build/lint, backend lint/typecheck/test and verify all reran and passed.
- Security correction run: revalidation secret comparison changed to timing-safe comparison, then storefront lint/typecheck/build/lint, backend lint/typecheck/test and verify all reran and passed.
## Notes
- Lighthouse tooling is not installed; SEO score criterion is evidenced structurally: SSR/SSG pages, semantic content, metadata/OpenGraph, canonical URLs and no client JavaScript added for these pages.
- No cart or checkout UI added.

View File

@@ -0,0 +1,23 @@
{
"feature_id": "F-014",
"agent": "leader",
"verdict": "APPROVED",
"summary": "F-014 closed with storefront catalog pages for products, categories, brands and search, ISR/SSG metadata, protected on-demand revalidation, backend categorySlug search support, documentation, and all gates approved.",
"gates": {
"reviewer": "APPROVED",
"security": "APPROVED",
"qa": "APPROVED"
},
"evidence": [
"work/artifacts/F-014/architect.md",
"work/artifacts/F-014/implementer.md",
"work/artifacts/F-014/reviewer.json",
"work/artifacts/F-014/security.json",
"work/artifacts/F-014/qa.json",
"work/artifacts/F-014/documenter.md",
"cd project/storefront && npm run lint/typecheck/build/lint: PASS",
"cd project && npm run lint/typecheck/test: PASS",
"./scripts/verify.sh: PASS final close"
],
"closed_at": "2026-08-15T15:53:00Z"
}

View File

@@ -0,0 +1,16 @@
{
"feature_id": "F-014",
"agent": "qa",
"verdict": "APPROVED",
"summary": "QA approved. Product/category/brand/search catalog pages exist with ISR metadata and OpenGraph, product URL remains /productos/<slug>, revalidation endpoint exists and is protected, and all configured checks are green. Lighthouse is evidenced structurally because browser Lighthouse tooling is not installed.",
"evidence": [
"Acceptance: Product page served at /productos/<slug> with no internal id -> project/storefront/src/app/productos/[slug]/page.tsx uses product.url and route slug; no id in URL",
"Acceptance: Catalog update revalidation -> project/storefront/src/app/api/revalidate/route.ts accepts supported catalog paths and calls revalidatePath with REVALIDATE_SECRET protection",
"Acceptance: Each page carries title/description/OpenGraph -> generateMetadata present on product/category/brand/search pages with canonical URL and OG fields",
"Acceptance: Lighthouse SEO >= 90 -> structural evidence: server/SSG pages, semantic h1/nav/sections, metadata, canonical URLs, OpenGraph and no client components; Lighthouse binary not available in this environment",
"cd project/storefront && npm run lint/typecheck/build/lint: PASS; build output shows SSG for product/category/brand routes",
"cd project && npm run typecheck: PASS",
"./scripts/verify.sh: PASS"
],
"timestamp": "2026-08-15T15:52:28Z"
}

View File

@@ -0,0 +1,19 @@
{
"feature_id": "F-014",
"agent": "reviewer",
"verdict": "APPROVED",
"summary": "F-014 review approved. Storefront now has server-rendered product, category, brand and search pages with ISR/SSG configuration, metadata/OpenGraph, a protected revalidation endpoint, typed public API access, and backend categorySlug support without frontend backend-internal imports.",
"evidence": [
"Read work/current.md and work/artifacts/F-014/architect.md/implementer.md",
"Inspected product/category/brand/search App Router pages and metadata generation",
"Inspected /api/revalidate route: secret required, supported local catalog paths only, calls revalidatePath",
"Inspected storefront API client extensions for category/brand/categorySlug and server-only boundary",
"Inspected backend categorySlug search propagation through route/use case/repository/test",
"Next build output shows SSG routes for /productos/[slug], /categoria/[slug], /marca/[slug], dynamic /products/search and /api/revalidate",
"cd project/storefront && npm run lint/typecheck/build/lint: PASS",
"cd project && npm run lint/typecheck/test: PASS",
"./scripts/verify.sh: PASS",
"gentle-ai review mode status: receipt-driven development off globally, ordinary gates used"
],
"timestamp": "2026-08-15T15:50:59Z"
}

View File

@@ -0,0 +1,16 @@
{
"feature_id": "F-014",
"agent": "security",
"verdict": "APPROVED",
"summary": "Security approved. Public catalog pages use server-only API access, search/category inputs are bounded or slug-validated, backend SQL remains parameterized, and on-demand revalidation is protected by env secret, timing-safe comparison and strict local path allowlist.",
"evidence": [
"Checked /api/revalidate: REVALIDATE_SECRET required, x-revalidate-secret checked via timingSafeEqual, invalid/missing secret rejected, only /productos/<slug>, /categoria/<slug>, /marca/<slug>, /products/search paths allowed",
"Checked storefront API client remains server-only and uses public HTTP endpoints only",
"Checked search page bounds display/metadata query text and numeric pagination; backend route validates q/categorySlug/brandSlug with zod constraints",
"Checked backend categorySlug filter uses parameterized SQL values and no frontend backend-internal imports are needed",
"cd project/storefront && npm audit --audit-level=high --omit=dev: found 0 vulnerabilities",
"rg secret patterns: only intentional env/header names and redaction pattern code findings; no committed credentials",
"Post-hardening storefront lint/typecheck/build/lint, backend lint/typecheck/test and verify all passed in build evidence"
],
"timestamp": "2026-08-15T15:52:05Z"
}