/shop/audio-tracks/{id}: resolves each track's preview from its Apple song id via iTunes lookup
(au), cached in disc_release_track.apple_preview. /shop/audio validates YouTube via oembed (200=live),
caches dead in disc_release_video.dead, returns one live id. release.html + kiosk.html get a per-track
▶ on each tracklist row feeding a mini-player with a jog/seek bar (falls back to a single Listen).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Same audio affordance as the kiosk on release.html — Apple 30s preview (instant audio),
else YouTube embed, else Beatport/Bandcamp embed, + country-scoped Apple Music link.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
site/kiosk.html: full-screen themed kiosk (idle attract cover-wall → tap → browse with
big search + genre chips + record grid → detail with tracklist, in-store locator (crate ·
rack) and a QR to buy on the customer's phone). 75s idle returns to attract. /shop/release
copies enriched with crate/rack location (public-safe). Route /kiosk. Better than WowPlatter's
kiosk: locate + phone-QR front and centre. Audio previews deferred (no internal audio yet).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ST.viewRot quarter-turns: drawRack remaps cells (rcell), edge labels (BACK/FRONT/L/R) and
facing-arrow glyphs per rotation while keeping all text upright; drawStore rotates rack
positions+yaw around centre with a matching unrotPt() so rack drag-to-move stays correct.
🔄 rotate button in the toolbar. Lets the diagram match where you're physically standing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
/nav/insert: drop one record (release id/sku/barcode) into a crate at a chosen slot,
shifting items at>=slot down by one. Scanner: click a contents row to set the insert
anchor (before/after toggle) — drives both the bulk 'Insert at picked slot' mode and a
new Quick Insert one-record panel. Picked row highlighted; anchor is per-crate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Admin-only /admin/system; no maintenance buttons (PG autovacuums, infra owns backups).
The useful 10% of WowPlatter's System page; the WP cache/transients/WP-CLI/debug rest dropped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Dashboard: fast KPI tiles (instant /stats) + lazy 30-day revenue line + stock-by-format
donut. Reports rebuilt into a parameterized workbench — date presets (7d/30d/90d/12mo/all
+ custom from/to) × dimension (trend/genre/style/format/condition/payment/weekday/hour +
top releases/artists/labels/customers) × metric (revenue/count), each chart fetched ON
DEMAND. New /admin/report/{kpis,series,breakdown,top,stock} (whitelisted dims, bound dates).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
app/square.py (Terminal Checkout API: device-code pairing, create/poll/cancel checkout;
creds in vault, device_id in sales_setting). /sales/terminal/{status,pair,pair/{id},
checkout,checkout/{id},checkout/{id}/cancel}. POS: 📟 Terminal payment method (shown when
paired) → pushes total to the terminal, polls, finalises the sale only on COMPLETED;
Settings → Pair a terminal (device-code flow). square_* added to admin Connections.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The 1-segment parametric route was swallowing the literal GET routes (int-parse 422,
silently masked before). Moved it after all literals.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
receipts.py renders store_logo (img) above the title; store_logo added to sales
settings (get/save) + a Logo URL field in POS Settings. Logo hosted at
site/receipt-logo.webp (Monster Robot, from WowPlatter receipt_templates). Print
window now waits for window.onload so the logo prints. Deploy via /opt/recordgod/deploy.sh.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
staff_shift table (one open shift per staff via partial unique index). /admin/clock
(status+today total), /clock/in (idempotent), /clock/out; /admin/timecards (admin)
= per-staff hours + recent shifts over a window. search.html top bar gets a live
clock widget (🟢 On 2h14m · Clock off · Log out; Clock on when off) ticking every 30s;
Log out warns if still clocked on. admin Staff tab gains a Timecards report.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Token resolver now checks the env owner-token (admin) then a staff table (name/token/
role). New require_admin gates /settings/* (API keys/connections) + staff CRUD; everything
operational (search/scan/inventory/labels/intake) stays on require_token so staff can do it.
admin.html: /admin/me drives ROLE; data-admin nav (Staff + Connections) hidden for staff +
go() blocks the views; new Staff tab to add operators, set role, reset/show token once,
deactivate. Tokens shown once on create.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
/nav/rack returns each crate's virtual_crate_type.material_color + type name;
drawRack fills/strokes/arrows each crate in its real colour (Blue Crate #0000FF,
Wooden Rack Bin #BA906A, White Tub #FFFFFF, Black Tub #191970, Shelf #C0C0C0…)
instead of all-blue. Legend lists the crate types present on the rack.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per-crate panel under Crate Contents: rename (label_text) + a Facing segment
(↑back/↓front/←left/→right) that rotates the crate live — the map arrow flips on
click. CrateEditIn gained 'direction'. Restores the crate editing my tabbed rewrite
dropped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sources stay the pick-ordered crates; targets default to those same real crate IDs
sorted ascending (4,3,2,1 → pour A–Z into 1,2,3,4), shown in an editable field so you
can consolidate/spread. Plan now shows where items land per crate. Drops the Start+Count
inputs (which could target non-existent crate IDs and orphan items).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
One persistent central store/rack map with a top tab strip (Scanner / Returns /
Reorganize / Collections / Stock Finder) all driving the shared map, + Store/Rack/
Crate/Item view buttons and an omni scan bar (release/SKU/c12/r3). Reorganize: click
crates IN ORDER (numbered pick badges feed the A–Z distribution planner) + drag racks
to move them on the store map (persists pos_x/pos_z; RackEditIn gained position fields).
Collections edit highlights picked crates on the map. Returns = stub (manual path via
Scanner + Release Info for now).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Storefront /wantlist form (themed, email-keyed, guest-friendly) posts to
/shop/wantlist → wantlist table (lazy DDL). Release pages deep-link to it
(prefilled; 'not in stock — request this record' when no copies). Admin gets
a Wantlist tab: pending/found/fulfilled queue with one-click status actions.
Default storefront menu → Records + Wanted.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
records.html reads /artist|label|genre|style/{val} from the path, sets the
filter + an entity header (artist/label name via /shop/{kind}/{id}). /shop/browse
gains artist/label EXISTS filters + primary artist_id; release page links
artist→/artist/{id} and genre/style pills→/{kind}/{name}.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>