Opens the 2.2.0 line. Eleven issues closed, one outside contribution, and a pull request finished on the contributor's behalf after review.
Security
System API tokens now carry scopes and an expiry (#217). A token issued for uptime monitoring no longer reaches the whole admin surface, including run-migration.
Two real bugs turned up while building it, both of which were in released code:
- The token creation response was returning the token's bcrypt hash.
INSERT ... RETURNING *went straight into the response body. generate-api-token.tspassedadmin_id: undefined, so every token minted by the documented CLI route silently became user 1.
Token verification also no longer bcrypt-compares against every row in the table — a CPU cost on an unauthenticated path that grew with the number of tokens stored.
Scraper
Akamai's behavioural interstitial, DataDome, PerimeterX and Imperva are now recognised as challenges rather than scraped as product pages with no price (#234, #235, #67). The browser timeout is the budget for the whole scrape rather than for navigation alone, so a page that loads slowly but succeeds is no longer aborted by the backend before the scraper can answer.
The phrase list driving this is admin-editable and bounded to the document title plus a size-gated body. Matching bare vendor names would have flagged every working page on a protected retailer, since the sensor script ships on all of them, not only on challenges.
Dashboard
- Sorting now applies in the By Product view, where every option previously did nothing (#241). Price sorts use the item's best price across its stores in your own currency.
- Tracking status is now separate from stock status, with both filters working in both views (#246, #248).
The recurring defect behind all three of those was the same: the grouped view not consuming state the flat view did.
Settings
- A configurable default check interval — instance-wide under Admin, per-user under Settings (#239). The Add Product form pre-fills from it instead of always starting at 12 hours.
- A dedicated Appearance section (#237), and save/cancel bars that finally agree with each other across every section (#183).
- Toast notifications name the product they refer to (#232).
Upgrading
ghcr.io/mikeknight85/pricestalker-backend:2.2.0-beta.1
ghcr.io/mikeknight85/pricestalker-frontend:2.2.0-beta.1
ghcr.io/mikeknight85/pricestalker-scraper:2.2.0-beta.1
Three new migrations — 021 seeds the challenge phrases, 022 the default check interval, 023 token scopes and prefixes. All idempotent with down paths, and each was run against a real Postgres rather than only typechecked. Take a database backup first, as always.
Token scopes are backwards compatible by design. Existing tokens backfill to * and keep working, flagged in Admin as deprecated with a prompt to regenerate. The fallback lookup survives for them, because a prefix cannot be retrofitted from a bcrypt hash.
One behaviour change: the CLI token script now requires a linked administrator — pass --user <email>, or it picks the longest-standing admin and prints which.
This is a prerelease: it publishes :2.2.0-beta.1 and moves :beta. stable and latest stay where they are.
If you are coming from 2.1.0-beta.10 or earlier
2.1.0-beta.11 added an SSRF guard that refuses loopback and link-local URLs. Any product tracking such a URL will start failing its scheduled refresh — set ALLOW_INTERNAL_SCRAPING=true if you have any. LAN addresses are unaffected. It also added a tini entrypoint to the scraper image, so recreate that container rather than restarting it if your stack pins its own Entrypoint, Command or User.
Not in this release
The expensive half of the Akamai work, the MCP server (#163, now unblocked by token scopes), suppressed-buy-box extraction (#236), and the resilience audit still awaiting verification on a real instance (#169).