{"slug":"new-items-dashboard","total":7,"limit":100,"offset":0,"since":null,"commits":[{"hash":"03f8a8c","date":"2026-05-20 00:27:41 -0700","author":"Steve","subject":"add: pre-stage Meta Pixel snippet (placeholder; flip via _dw-batch set-fb-pixel.sh)","body":"Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"},{"hash":"ed3ed84","date":"2026-05-19 22:13:46 -0700","author":"Steve Abrams","subject":"test: auth gate smoke test (boots server, asserts 401/200 matrix)","body":"7 assertions covering unauth-401 on /, /api/new-wines, /api/new-handbags,\n/api/stats, WWW-Authenticate present, valid-creds non-401, wrong-creds 401.\nStandalone (no framework dep); wired to npm test.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"},{"hash":"b447df1","date":"2026-05-19 22:12:50 -0700","author":"Steve Abrams","subject":"secure: basic-auth gate on all routes (server was public on 0.0.0.0:7201)","body":"Mounts an Express middleware before any route declaration so /api/new-wines,\n/api/new-handbags, /api/stats and the HTML dashboard all require credentials.\nCredentials come from env BASIC_AUTH (user:pass form); placeholder is left in\ncode with a SECURITY: rotate-before-deploy comment. In dev (NODE_ENV !=\nproduction) with no BASIC_AUTH set, the gate fails open for local convenience.\nUses crypto.timingSafeEqual to dodge length-leak side channels.\n\n.env.example documents BASIC_AUTH + NODE_ENV. .gitignore exempts .env.example\nso the template can be tracked.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"},{"hash":"7d0b816","date":"2026-05-19 21:20:29 -0700","author":"Steve Abrams","subject":"feat: sort + density controls on wines & handbags grids","body":"Per Steve's standing rule, every product/item grid must have a working\nsort <select> + density slider, both persisted to localStorage and\nhydrated BEFORE the first fetch.\n\nFrontend (public/index.html):\n- New .grid-controls toolbar above each tab grid with sort select\n  (Newest / Vendor / Series / SKU / Title) + density range input\n  (180-480px card-min via CSS var --card-min).\n- hydrateControls() reads localStorage and sets control values BEFORE\n  loadWines/loadHandbags fire, so the first paint already reflects the\n  saved user choice instead of flashing default→saved.\n- Change handlers persist to namespaced keys (newItemsDash.<tab>.<ctl>)\n  then either re-fetch (sort) or just re-apply CSS var (density).\n- Grids now render into dedicated <div id=wines-grid> / handbags-grid\n  containers so re-renders don't blow away the toolbars.\n- applyDensity re-runs after every grid re-render to survive the\n  innerHTML wipe.\n\nServer (server.js):\n- New applySort(items, sort, type) helper. Honors ?sort=newest|vendor|\n  series|sku|title on both /api/new-wines and /api/new-handbags.\n- 'vendor' falls back to brand / source when an item lacks vendor;\n  'series' falls back to vintage / model. Keeps shape consistent\n  across the two heterogeneous data sources.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"},{"hash":"793d2e2","date":"2026-05-19 21:17:54 -0700","author":"Steve Abrams","subject":"harden: broaden .gitignore + 404-guard for snapshot files","body":"- .gitignore now covers *.bak.*, *.pre-*, *.orig, *.rej, *.swp, *~\n  (was only *.bak). Prevents editor scratch + Claude pre-edit snapshots\n  from sneaking into the repo.\n- New Express middleware before express.static returns 404 for any\n  request to a snapshot/editor-scratch path so even if one accidentally\n  lands under public/ it never serves to a browser.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"},{"hash":"56106db","date":"2026-05-13 08:57:58 -0700","author":"Steve","subject":"snapshot: 1 file(s) changed, ~1 modified","body":""},{"hash":"d4a4408","date":"2026-05-06 10:25:43 -0700","author":"Steve Abrams","subject":"initial scaffold (gitify-all 2026-05-06)","body":""}]}