FloCafe
FloCafe is the free, local-first restaurant POS in the FloPOS ecosystem. Run orders, tables, kitchen display, and local data without a software subscription.
Find the best price on lumber, electrical, plumbing and tools across Home Depot, Lowe's, Menards, Ace, Harbor Freight and Amazon.
CommerceTypeScript · CSSGitHub @SailTheUniverseOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Price comparison for construction materials. Search or browse lumber, electrical, plumbing and tools, filter by real specs (wire gauge, length, lumber size, PEX diameter…), and see what each item costs at Home Depot, Lowe's, Menards, Ace Hardware, Harbor Freight and Amazon. Includes in-store prices at your nearest stores and online prices with shipping, plus unit prices (per ft, per sheet, per 100 ct).
Draft: all prices come from a mock provider that generates believable sample data. See Real price data for the plan to plug in real sources.
@prisma/adapter-pg)Requirements: Node 20+ and a PostgreSQL database. Local Postgres works, or use a free hosted tier (Neon, Supabase, Prisma Postgres).
npm install
cp .env.example .env # then edit DATABASE_URL
npm run db:migrate # create tables
npm run db:seed # load sample catalog + prices
npm run dev # http://localhost:3000
Other scripts:
| Script | What it does |
|---|---|
npm run prices:refresh [-- <retailer-slug>] | Pull fresh quotes from each retailer's provider |
npm run amazon:match [-- --apply] | Find Amazon ASINs for products (needs Amazon credentials) |
npm test | Unit tests (optimizer, Amazon provider) |
npm run db:reset | Drop, re-migrate and re-seed the database |
npm run typecheck / npm run lint | Checks |
The app needs a Node server and Postgres, so it runs on Vercel's free Hobby plan with a free Neon database added through Vercel. Deploys come straight from GitHub.
SailTheUniverse/2by4, and click Deploy. This first deploy fails because there's no
database yet. That's expected.DATABASE_URL, DATABASE_URL_UNPOOLED).CRON_SECRET with a long random value.vercel.json schedules /api/cron/refresh-prices weekly (Mondays). It refreshes prices and trims history older than
120 days, which keeps the database at roughly 130–150 MB, well under Neon's free 0.5 GB. Every push to draft-mvp
redeploys. If the seed data changed (prisma/seed/*), the deploy reseeds the catalog automatically. Project lists are
kept and re-linked to products by slug.
Category (tree) ──< AttributeDef filterable specs per category (ENUM / NUMBER / BOOLEAN)
Product (specs JSON, unitLabel/unitQty) one canonical item, matched across retailers
└─< Listing (product × retailer, url, retailerSku e.g. ASIN)
├─< Offer (current price per location: a Store id or "online"; source = mock | live)
└─< PricePoint (price history)
Retailer ──< Store (zip)
ProjectList ──< ProjectItem (product, quantity)
/c/wire?gauge=12+AWG&length=250&sort=unit), so every view can be shared.
Facet counts are disjunctive: each one ignores its own selection. See src/lib/filters.ts.prisma/seed/categories.ts with its attributes. Product
specs are JSON keyed by attribute key, so no migration is needed.src/lib/location.ts and src/lib/pricing.ts./list, shareable at /lists/[id]): there are no accounts yet, so the list id lives in a cookie.
src/lib/optimizer.ts tries every combination of retailers and pickup vs. online and returns the cheapest plan
overall, with up to 2 stops, and with one stop. Shipping is one fee per online order: free if any item in the order
ships free on its own, otherwise the largest single-item fee.PricePoints. The product page charts each retailer's best price per day for
your location (30/90 days) and flags "Lowest price in 90 days". The seed back-fills 90 days of sample history.prisma/schema.prisma data model
prisma/seed/ sample retailers, stores, categories, products
scripts/refresh-prices.ts price refresh job
scripts/amazon-match.ts ASIN matching for Amazon listings
src/lib/providers/ PriceProvider interface, mock + Amazon providers
src/lib/catalog.ts queries (products, prices, history)
src/lib/filters.ts filter parsing, facets, sorting
src/lib/optimizer.ts cheapest-plan search for project lists
src/app/ pages: / , /c/[slug], /p/[slug], /search, /list, /lists/[id]
src/components/ UI
Each retailer gets a PriceProvider (src/lib/providers/types.ts). Providers are picked per retailer in
src/lib/providers/index.ts, and every offer records its source, so the UI tags live prices with LIVE. Options,
roughly in order of cost:
Product matching across retailers should key on UPC, then brand + model number.
Amazon retired PA-API 5 in spring 2026; the Creators API replaces it, with new credentials.
AMAZON_* variables in .env (see .env.example).npm run amazon:match: searches Amazon for each product and shows proposed ASINs. Matches where the model number
appears in the Amazon title are saved with --apply; review the rest and save them with
npm run amazon:match -- --set <product-slug> <ASIN>.npm run prices:refresh -- amazon fetches live prices (10 ASINs per request, about 1 request/second).Amazon links go straight to the product page (amazon.com/dp/<ASIN>). The verified ASINs live in
prisma/seed/amazon.ts; each was matched by brand, model and pack size. A product only gets an Amazon listing when
it has an ASIN there, so there are no search-page links. Once credentials are set, Amazon listings without an ASIN
show no Amazon price, rather than sample data. The request
format (token endpoints, getItems/searchItems fields, offersV2 response) was taken from published Creators API
client SDKs, because Amazon's docs site wasn't reachable while building this. Unit tests cover it with a mocked API.
Check the first live run against Amazon's current docs, since it hasn't run against real credentials yet.