Pallets For Sale
The Pallets For Sale tool lives at /sales/pallets on the ReturnPro dashboard. It was ported from Alejandro's Lovable project so the rules round-trip between the two apps; both teams edit the same rule set, both apps read the same trend snapshots.
What it does
Sales reps upload a fresh FMSI XLSX export. The tool streams-parses the file in the browser via a Rust/WASM module, applies eight exclusion-rule groups that decide which pallets are available for sale, and writes back the rule decisions plus a snapshot for trend analysis.
Auth: dual Supabase
The page is gated behind ReturnPro auth, but the data lives in the legacy Lovable Supabase.
| Concern | Backend |
|---|---|
Auth (session, role, sales_access flag) | ReturnPro Supabase (vvutttwunexshxkmygik.supabase.co). |
| Pallet data, exclusion rules, trend snapshots | Sales (Lovable legacy) Supabase (tgysafeenbcosudycymw.supabase.co). |
The middleware at dashboard-returnpro/middleware.ts enforces auth on all /sales/* routes; the page-level permission check uses usePermissions().hasSalesAccess which reads user_profiles.sales_access from the ReturnPro instance.
The Sales (Lovable) client is constructed with plain createClient (not createBrowserClient) and persistSession: false — it is a data-only client and does not own the auth session.
Streaming XLSX parser
FMSI exports run >400 k rows. Loading the whole workbook into memory crashes mobile Safari. The tool ships a Rust/WASM streaming parser built on the calamine crate that:
- Parses the XLSX in the browser (no server upload).
- Emits zero-copy
TransferableArrayBufferbatches to the React side viapostMessage. - Streams rows past the dim transformations and rule engine without ever materializing the whole sheet.
This keeps memory flat at a few MB regardless of the file's row count.
Exclusion rule groups
The tool implements eight exclusion rule groups. Each group operates on a different dimension of the pallet record:
- Sorting category.
- Place name.
- Consignment facility.
- Owned-program exclusion.
- Exclusion reasons.
- B2B exclusions.
- Conditional sorting.
- Stored-to-non-listable.
Rules are stored in the Sales Supabase. Editing rules in either ReturnPro's /sales/pallets UI or in Alejandro's Lovable app round-trips because both apps point at the same rules table.
Trend snapshots
After each run, the tool writes a snapshot of the rule-decision counts to the Sales Supabase. The trend chart on the page reads recent snapshots so you can see how the available-pallet count has shifted over time without re-running the parser on historical files.
Operational notes
- The page is at
/sales/pallets. The auth middleware redirects unauthenticated users to login; users withoutsales_accesssee a forbidden page. - The Rust/WASM module is pre-built and committed; rebuilding it requires the Rust toolchain (
wasm-pack build). - Because data lives in the Sales (Lovable) Supabase, dropping that instance breaks the tool. There is no failover; if the legacy DB is decommissioned, the rules and snapshots need to migrate first.
For full background, see the project memory entry for Pallets For Sale (project lead notes, Rust/WASM tradeoffs, and Lovable-app interop) at dashboard-returnpro/CLAUDE.md.