← back to Estimate Instant
README.md
41 lines
# Project
Scaffolded by the Claude web-dev accelerator. Storefront starter with a
server-side-sorted product grid + density slider (both persist in localStorage).
## Run
```bash
PORT=3900 node server.js # open http://localhost:3900
BASIC_AUTH="admin:DW2024!" PORT=3900 node server.js # gated
```
## Room coverage API
`POST /api/calculate-coverage` accepts:
```json
{"sku":"DW-GRAS-01","room_width_ft":10,"room_height_ft":8,"num_walls":4}
```
It returns `rolls_needed`, `waste_pct`, `total_cost`, and calculation notes. The
endpoint is read-only and uses the checked-in `data/rolls.json` snapshot; its
response labels that provenance and warns callers to confirm current product
specifications and price before quoting. It does not query or mutate Shopify or
`dw_unified`. Inputs must be JSON number primitives: width is capped at 1,000 ft,
height at 100 ft, and `num_walls` must be an integer from 1 through 100. These
conservative bounds prevent coercion and overflow. A Shopify SKU alias is accepted
only for an exact `shopify_match:true` record. Prototype/stand-in rows still return
coverage metrics, but return null prices with `quote_authoritative:false`. JSON request
bodies are capped at 16 KiB (`413` when exceeded; malformed JSON is `400`). At process
startup the entire checked-in roll snapshot is schema-validated before the server binds;
an empty, malformed, duplicate-SKU, or invalid-spec snapshot fails closed.
## Fill it in
- `data/products.json` — array of `{ title, sku, price, hex, image }`.
- `server.js` `sortProducts()` — add sort modes as needed.
- `public/index.html` — the grid + controls.
## Preview publicly
From the accelerator dir: `scripts/preview-tunnel.sh <slug> <port>` stands up
`<slug>.agentabrams.com` (basic-auth gated). The DNS step is Steve-gated.