Commit Graph
15 Commits
Author SHA1 Message Date
bermudalambandClaude Opus 5 9222e97deb feat(api): categories, tags, and storefront item filters (#23)
Adds a self-referencing categories tree, a tag registry with
deterministic colours, and item_tags, plus admin CRUD for both.

GET /api/items now accepts category, tags, min_price and max_price.
Category matching walks the subtree with a recursive CTE so selecting a
parent includes everything filed beneath it; tags match with AND via a
count check, since ANY() alone would return items carrying only one of
them. Malformed filter params return 400 rather than being ignored, so a
broken link doesn't quietly list the whole catalogue.

GET /api/filters serves the drawer its tree, tags, and price bounds in
one request.

Item image/tag aggregation moves from LEFT JOIN + GROUP BY to scalar
subqueries. Joining two one-to-many relations multiplies their rows, so
an item with 2 images and 3 tags would have repeated every image three
times once tags were added.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-17 09:13:51 -05:00
bermudalambandClaude Opus 5 977489cbc0 refactor: delete superseded checkout routes and dedupe cart checkout
routes/paypal.ts and routes/demo.ts were the pre-cart single-item
checkout flow. Nothing has imported them since the cart flow landed:
app.ts mounts only cartCheckout, the frontend calls /api/checkout/cart/*,
and no test touches them. They duplicated PAYPAL_BASE, getAccessToken,
and a second handler for the /webhooks/paypal mount.

Also extract openCheckout() from /paypal/create and /demo/purchase in
cartCheckout.ts, which repeated the same address-ownership check, cart
lock, and checkouts/checkout_items inserts. It returns a discriminated
union so callers keep control of the transaction and the response. Add
CartItem/LockedCart interfaces, dropping the (it: any) casts.

Note: paypal.ts was the only writer of items.reserved_until and
items.paypal_order_id. Those columns are now write-dead; the schema is
left alone for a separate migration.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 17:59:42 -05:00
bermudalambandClaude Opus 5 b0a38d0ac6 chore: sync package-lock with declared dependencies
node-cron, node-pg-migrate, and @types/node-cron are declared in
package.json but were missing from the lockfile, so npm ci fails and a
plain npm install silently rewrites the lock. Regenerated to match.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 17:58:14 -05:00
bermudalambandClaude Opus 5 ab1024a1b6 fix: resolve SonarQube hotspots for upload size and X-Powered-By
SonarQube Analysis / sonarqube (pull_request) Successful in 7m11s
Tests / backend-unit (pull_request) Successful in 2m18s
Tests / backend-integration (pull_request) Successful in 2m28s
Tests / frontend-e2e (pull_request) Failing after 59s
- S5693: MAX_IMAGE_BYTES was 8 * 1024 * 1024 (8,388,608), just over the
  8,000,000-byte ceiling the rule treats as safe, so the hotspot on the
  multer storage config never cleared. Use 8_000_000.
- S5689: Express advertises its stack in X-Powered-By by default, which
  tells an attacker what to aim exploits at. Disable the header.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 17:18:42 -05:00
bermudalamb 1c46632e8f fix: remove stale single-item demo-checkout tests, add cart integration tests
SonarQube Analysis / sonarqube (pull_request) Successful in 13m27s
Tests / backend-integration (pull_request) Successful in 6m32s
Tests / frontend-e2e (pull_request) Failing after 2m57s
Tests / backend-unit (pull_request) Successful in 1m19s
2026-08-14 16:11:20 -05:00
bermudalamb b73b472d80 fix: TypeScript type mismatch between UspsValidationResult and local fallback object
SonarQube Analysis / sonarqube (pull_request) Successful in 3m12s
Tests / backend-unit (pull_request) Successful in 57s
Tests / backend-integration (pull_request) Failing after 1m7s
Tests / frontend-e2e (pull_request) Failing after 38s
2026-08-14 14:47:52 -05:00
bermudalamb 9ab689e624 feat: add customer cart with expiry, shipping addresses with USPS validation, and multi-item PayPal checkout
SonarQube Analysis / sonarqube (pull_request) Failing after 59s
Tests / backend-unit (pull_request) Successful in 34s
Tests / backend-integration (pull_request) Failing after 1m33s
Tests / frontend-e2e (pull_request) Failing after 1m5s
2026-08-14 14:02:25 -05:00
bermudalamb 845b1f29b9 fix: Dockerfile
SonarQube Analysis / sonarqube (pull_request) Successful in 3m3s
Tests / backend-unit (pull_request) Successful in 2m0s
Tests / backend-integration (pull_request) Successful in 1m50s
Tests / frontend-e2e (pull_request) Failing after 1m0s
2026-08-14 10:58:07 -05:00
bermudalamb 7f4479605a chore: replace manual SQL migrations with node-pg-migrate
SonarQube Analysis / sonarqube (pull_request) Successful in 2m42s
Tests / backend-unit (pull_request) Successful in 34s
Tests / backend-integration (pull_request) Successful in 50s
Tests / frontend-e2e (pull_request) Failing after 38s
2026-08-14 10:05:09 -05:00
bermudalambandClaude Opus 5 aba47c81e3 fix: bound admin image uploads and use a CSPRNG for stored filenames
SonarQube Analysis / sonarqube (pull_request) Successful in 3m49s
Tests / backend-unit (pull_request) Successful in 33s
Tests / backend-integration (pull_request) Successful in 1m6s
Tests / frontend-e2e (pull_request) Failing after 1m7s
SonarQube flagged three hotspots in the admin router: multer was
configured with no content length limits, and stored filenames were
derived from Date.now() plus Math.random().

- Cap the multipart body on every dimension: 6 files, 8 MiB per image,
  8 fields, 64 KiB per field. Without limits a single request could
  fill the uploads volume.
- Generate stored filenames with crypto.randomUUID() so paths are not
  predictable. Image ordering is unaffected; sort_order already drives it.
- Wrap the upload middleware to translate MulterError into 413/400 JSON.
  The app mounts no error handler, so a limit rejection would otherwise
  surface as an HTML 500.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 09:22:45 -05:00
bermudalamb 81118245ce fix: sonarqube denial of service issue 2026-08-14 08:43:37 -05:00
bermudalamb 4b524e0da3 fix: move scripts folder to correct location
SonarQube Analysis / sonarqube (pull_request) Successful in 4m31s
Tests / backend-unit (pull_request) Successful in 59s
Tests / backend-integration (pull_request) Failing after 4s
Tests / frontend-e2e (pull_request) Failing after 1s
2026-08-14 08:15:52 -05:00
bermudalamb 234330e482 Add CI test workflow with job summaries
SonarQube Analysis / sonarqube (push) Successful in 3m55s
Tests / backend-unit (push) Failing after 55s
Tests / backend-integration (push) Failing after 2s
Tests / frontend-e2e (push) Failing after 1s
2026-08-13 19:10:30 -05:00
bermudalamb 921022c658 Add backend unit/integration tests, Playwright e2e tests, README, cookie Secure fix
SonarQube Analysis / sonarqube (push) Successful in 4m20s
2026-08-13 22:35:38 +00:00
bermudalamb 9be4986dd3 Initial commit: redefined-designs storefront 2026-08-13 21:07:54 +00:00