Commit Graph
5 Commits
Author SHA1 Message Date
Kevin L'Hereec 9702d24a01 fix: allow gstatic.com in CSP img-src for merchant favicons
Build & Deploy / build (push) Failing after 5s
Build & Deploy / docker (push) Skipped
The favicon service used to show a merchant's icon in the price
comparison UI (www.google.com/s2/favicons) redirects to Google's gstatic
CDN (t0-t3.gstatic.com), which wasn't allowlisted — CSP silently blocked
the redirected image request (reported by some browsers as an opaque
response block rather than a clear CSP violation), so the 'Compare
prices' cheapest-offer favicon never rendered.

Added https://*.gstatic.com to img-src.
2026-07-23 15:38:00 +02:00
Kevin L'Hereec 25d6222df0 fix: add worker-src to CSP to fix broken HMR connection
Build & Deploy / build (push) Failing after 3s
Build & Deploy / docker (push) Skipped
Without an explicit worker-src directive, browsers fall back to
script-src ('self' only) for Web Workers, which blocks the blob: worker
spawned internally by Vite's HMR client / Tuyau's client. This caused the
dev HMR websocket connection to drop intermittently ('server connection
lost. Polling for restart...'), leaving the Vue app in an inconsistent
state after a failed hot reload — components using the Link component
(internally named TuyauLink, from @tuyau/core) would throw 'You must
wrap your app in a TuyauProvider' because the provide/inject context set
up at the app root was lost.

Added worker-src 'self' blob: to config/shield.ts. Verified: dev server
restarts cleanly with the HMR socket connecting without CSP violations,
full test suite (30/30) still passes.
2026-07-23 15:30:01 +02:00
Kevin L'Hereec 62ec796e05 fix: repair broken CSP and compare live merchant prices for new parts
Build & Deploy / build (push) Failing after 4s
Build & Deploy / docker (push) Skipped
CSP fix:
- The previous shield.ts config used '@viteDevUrl'/'@viteHmrUrl' CSP
  keywords that don't exist in this version of @adonisjs/shield (only
  '@viteUrl' is registered by @adonisjs/vite, and it resolves to an empty
  string here since Vite assets are proxied through AdonisJS on the same
  origin). Both placeholders were sent to the browser literally, breaking
  Google Fonts, the Vite HMR websocket, and pc-builder.io/favicon images.
- Replaced with concrete directives: 'self' covers same-origin Vite
  assets, ws://localhost:{VITE_HMR_PORT|24678} is added only in dev for
  the HMR socket, and explicit allowlists for Google Fonts
  (fonts.googleapis.com/fonts.gstatic.com), pc-builder.io product images,
  and Google's favicon service (www.google.com) used by the merchant
  comparison UI

Real purchase links + live price comparison:
- part_scraper_service.ts: ScrapedPart.sourceUrl now stores the actual
  Amazon.fr purchase link scraped from pc-builder.io's category pages
  (https://www.amazon.fr/dp/{ASIN}?tag=... or a search fallback), instead
  of the pc-builder.io product page, which isn't a place anyone can buy
  anything from
- New merchant_price_service.ts: on-demand live price lookup across
  Amazon, LDLC, Grosbill and TopAchat. Of 6 requested merchants,
  Materiel.net (search requires JS/Turbo, no results via plain GET) and
  Cdiscount/PCComponentes (empty body / 403) were dropped as not scrapable
  without a headless browser or paid API
- Matching strategy: pc-builder.io's full product names (e.g. "AMD Ryzen 3
  3200G 3.6 GHz Quad-Core Processor") return zero results on every
  merchant's search engine, so we search on a short brand+series query
  and then pick the specific result whose label contains the extracted
  model token (e.g. "3200G"). No token match means no offer returned,
  rather than risk quoting the price of a different, unrelated product
- Fixed price parsing for LDLC/Grosbill, which render prices as nested
  price/sup elements for whole euros vs cents (and LDLC additionally
  wraps that in a duplicate outer .price div) - naive text concatenation
  was misreading "64,95" as "6495"
- New GET /scraped-parts/compare endpoint (authenticated), called on
  demand per search result rather than for every row, since it makes
  several outbound requests and can take a few seconds
- NewPartSearch.vue: "Compare prices" button per result shows the
  cheapest merchant with its favicon and links to the actual offer;
  importing a part now prefers the live cheapest price/link over
  pc-builder.io's potentially stale catalog price (confirmed stale in
  practice: pc-builder.io listed a Ryzen 3 3200G at 128 euros while
  Amazon sells it for 66.89 euros)
- 3 new functional tests for the compare endpoint (auth required, 404 on
  unknown part, 422 on invalid id)
2026-07-23 14:58:33 +02:00
Kevin L'Hereec 94f89be605 chore: harden config, strengthen frontend typing, fix UTF-8 mojibake
Security config (3.1):
- config/session.ts: cookie.secure now follows app.inProduction instead of
  being hardcoded to false
- config/shield.ts: enable CSP with baseline directives compatible with
  Vite dev server and Inertia (self + @viteDevUrl/@viteHmrUrl)

Frontend typing (3.2):
- Replace 'any' props with concrete types (Computer, Component, ComponentType,
  ComputerState) across computers/*.vue and components/*.vue, using the
  existing inertia/pages/types/UITypes.ts definitions
- Fix UITypes.ts: export ComponentType/ComputerState, switch from interface
  to type (interfaces are never assignable to Inertia's ComponentProps index
  signature), drop the stale componentTypeId/componentStateId fields that
  didn't match the actual Lucid schema (real field is typeId, no component
  state exists)
- Add an asPageProp() boundary cast in the two controllers: Lucid's
  serialize() returns a loosely typed ModelObject that isn't structurally
  assignable to the concrete page prop shapes (and the inertia/** tree is
  excluded from the backend tsconfig, so real types can't be imported
  directly across that boundary)

UTF-8 mojibake fixes (3.3):
- Repair broken accented characters (├®/├á/├┤ -> é/à/ô, Ôé¼ -> €) left over
  from a bad encoding during the GWT->Inertia migration, across
  ComponentEditor.vue, ComputerComponentsTable.vue, SimpleGallery.vue,
  TableComponent.vue, isAdminMode.ts and the custom directives

Misc cleanup (3.5):
- computer.ts: replace console.warn with the app logger (includes
  computerId) when .cost is accessed without preloading components
2026-07-23 11:10:37 +02:00
Kevin 648d0af538 Initial commit: PC Builder AdonisJS project 2026-06-28 10:41:51 +02:00