Commit Graph

177 Commits

Author SHA1 Message Date
shawn 2d232941da Fix single checkin GET to include username via JOIN 2026-06-01 00:27:29 -04:00
shawn e325981b17 Fix check-in user tracking
- Backend: create_checkin now auto-resolves user_id from auth token
  when not provided in the request body
- Backend: list_checkins now JOINs users table to return username
  alongside each check-in
- Frontend: all 4 check-in functions now pass user_id from
  AppState.currentUser
- Frontend: check-in history shows 👤 username next to each entry
- Also made work order count clickable: shows WO detail modal
- Added work_orders list to MSFS asset response

Closes #62
2026-05-31 23:54:13 -04:00
shawn 07539b683e feat: add script to import machines from Cantaloupe Excel export
Adds scripts/import_from_excel.py that reads Cantaloupe .xlsx exports
and imports missing machines into the canteen-asset-tracker DB.
- Dry-run by default, --write to commit, --prod for production DB
- Maps all 62 spreadsheet columns to assets table schema
- Stores full raw row as JSON in seed_data table
- Backs up DB before import
2026-05-31 11:09:27 -04:00
shawn 8713169e84 feat: add My GPS button to asset detail GPS editor
Adds a '📍 My GPS' button to the GPS Map Editor card in the asset
detail screen that:
- Grabs device GPS via navigator.geolocation.getCurrentPosition
- Places map marker at current device position
- Auto-unlocks the GPS editor if locked, shows Save button
- Displays accuracy in status text
- Provides clear error messages for denied/timed-out/unavailable

Includes enableHighAccuracy: true, 15s timeout, 60s cache.
2026-05-31 09:53:23 -04:00
shawn 2a92c4e71b Swap all UI icons to game-icons SVGs via sprite
- Created SVG sprite with 49 game-icons symbols (58KB)
- Added .gi CSS class for icon sizing/fill
- Replaced 77 emoji in static HTML with <use href='#gi-{name}'>
- Skip <option> elements (can't render SVG there)
- Added JS gi() helper for 33 dynamic icon assignments
- Replaced 📍🔒🔓📷📋↕️⚠ in JS-driven content
- Zero network requests, zero console errors
- Pairs with existing CATEGORY_MAP game-icons SVGs
2026-05-31 02:40:52 -04:00
shawn cc4f3b7dcf Swap all category icons to game-icons
All 8 categories now use Game Icons from game-icons.net:
- Bev:     game-icons:soda-bottle (glass soda bottle)
- Snack:   game-icons:chips-bag (crinkly chip bag)
- Food:    game-icons:hamburger (stacked burger)
- Equip:   game-icons:wrench (adjustable wrench)
- Appl:    game-icons:cooler (ice chest)
- Markets: game-icons:shop (storefront with awning)
- Coffee:  game-icons:coffee-cup (paper cup with steam)
- Other:   game-icons:cargo-crate (industrial crate)

Zero external deps — inline SVGs from Iconify CDN
2026-05-31 02:26:01 -04:00
shawn dc11ac75d2 Swap Bev and Snack icons to game-icons
- Bev: hugeicons:soda-can → game-icons:soda-bottle
- Snack: mdi:chips → game-icons:chips-bag
- Other categories unchanged
2026-05-31 02:24:21 -04:00
shawn b444009593 Replace emoji icons with Iconify SVG icons
- Bev: hugeicons:soda-can (soda can with pull tab, outline style)
- Snack: mdi:chips (bag of chips)
- Food: mdi:hamburger
- Equipment: mdi:wrench
- Appliances: mdi:fridge-outline
- Markets: mdi:store
- Coffee: mdi:coffee
- Other: mdi:package-variant
- Removed stale <img guard in map sidebar rendering
- Added SVG sizing CSS for asset list icons
- Zero external deps — inline SVGs from Iconify CDN
2026-05-31 02:15:49 -04:00
shawn 18743ffdde Add GPS Map Editor to asset detail view
Add a GPS map editor card at the top of asset details, allowing users to
manually set an asset's GPS coordinates via an interactive Leaflet map.

- GPS card with Leaflet map and draggable marker
- 🔒 Lock/unlock toggle (locked by default when GPS exists)
- 💾 Save GPS button (visible only when unlocked)
- Saves via PUT /api/assets/{id} with lat/lng
- Click on map or drag marker to set position
- Fallback to Orlando coords (28.5383, -81.3792) when no GPS
- Auto-refresh detail view after save

Closes #61
2026-05-31 01:47:54 -04:00
shawn 064fc43fe3 fix: remove all address-geocoded GPS, keep only original check-ins
All GPS from MSFS account addresses and Cantaloupe seed data removed.
Only 5 authentic app check-in GPS entries remain.
Reverts the bulk restore from earlier commit (gps restore was address-based).
2026-05-31 01:45:53 -04:00
shawn 616769e805 feat: restore GPS data from pre-MSFS backup + MSFS account data
- 221 GPS entries restored via serial_number match from pre-MSFS backup
- 5,730 GPS entries restored via MSFS account address data
- Coverage improved from 1.6% (124) to 80.4% (6,075) of 7,560 assets
- Remaining 1,485 have no GPS in MSFS account records
2026-05-31 01:40:03 -04:00
shawn 55a21e981f Recategorize: Markets (🏪) replaces Kiosk; 106 coffee machines Bev→Coffee
- Renamed Kiosk category → Markets (includes 365 Retail Markets,
  Intuitivo, Panoptyc, Smart Market, Micro-Market-Ave C)
- Moved 106 coffee brands from Bev to Coffee: Nespresso (36),
  Curtis (23), Krea (14), EVERSYS (12), Bloomfield (6),
  Segafredo (4), Bravilor (4), Simonelli (2), Starbucks (2),
  Marco (2), Cafection Digi-cup (1)
- Updated CATEGORY_MAP
2026-05-31 01:09:40 -04:00
shawn fff2b6a52a feat: add Coffee category () — move 63 De Jong Duke / Impressions vending machines from Equipment
- New Coffee category with amber (#a16207) branding
- 63 coffee vending machines recategorized from Equipment
- CATEGORY_MAP updated in main app
2026-05-31 00:52:02 -04:00
shawn 955e489977 Add Kiosk category, re-categorize 207 assets, fix .gitignore
- New Kiosk category (🏪, purple) for 365 Retail Markets, Panoptyc, Intuitivo,
  Smart Market, Micro-Market — 1,100 assets moved from Equipment/Other
- CRANE (114) → Equipment (was wrongly 'Other')
- Vendo, Royal, DN, DIXIE NARCO (52) → Bev (beverage vending machines)
- USI (2) → Snack
- Cafection Digi-cup, Echostream, Purelogix, Avalon (4) → Bev
- CoolServ, Cold Snap, KoolTek (3) → Appliances (cooling/refrigeration)
- De Jong Duke, AC, Impressions, Lektro-Vend (11) → Equipment
- Remaining 'Other' reduced from 221 to 14 genuine unknowns
- Zero unmapped categories — Category Health clean
2026-05-31 00:40:21 -04:00
shawn f1a3bb9f00 feat: revised category icons + unknown type detection
- Cleaned CATEGORY_MAP: removed dead entries (Furniture, GF Bev,
  Snack/bev, Snack/food), fixed duplicate 'Food' key, proper
  distinct icons for all 6 real categories
- Added categoryInfo() helper: 🥤/🍿/🍔/🔧/🔌/📦 for known cats,
   (red) for unmapped categories, 📦 for null
- Updated all render sites (list, map pins, map list, detail view,
  scan result, OCR result) to use categoryInfo()
- Added category icons to detail view and scan/OCR result headers
- Synced categories DB table: added Equipment/Appliances with icons,
  removed unused Unknown
- Updated seed data in both server.py and admin_server.py to match
  real asset categories
- Added category_health to /api/stats with unmapped category detection
- Added Category Health card to admin dashboard (shown only when
  unmapped categories exist)
- Updated CSS backgrounds for all real categories + .cat-unmapped
2026-05-31 00:28:03 -04:00
shawn 5c2e15e28b ux: persist help overlay dismissed state via localStorage 2026-05-30 21:20:50 -04:00
shawn 474a618f79 UX fixes: fix Map tab crash, remove Edit/Delete buttons, update Help dialog and menu labels 2026-05-30 20:56:28 -04:00
shawn 9ae0f271ea chore: remove accidentally committed gps backup file 2026-05-29 23:17:53 -04:00
shawn 17b870e4cc feat: wire vision/OCR results back into asset records
- Auto-save photo_path to matched assets when photo uploaded via /api/ocr
- Auto-extract and save serial_number from OCR text to blank-serial matched assets
- Add _extract_serial_from_text helper for serial number pattern matching
- Create scripts/backfill_vision_photos.py for batch-processing unlinked photos
- Add docs/OCR_PIPELINE.md documenting the full OCR/vision pipeline
- Fix test DB schema: add connect_id, equipment_id, barcode, customer_name
- Fix OCR test assertions to match actual endpoint behavior
2026-05-29 10:03:51 -04:00
shawn 99cef94153 Cross-reference photos against assets DB
- Scanned all 15 photos in uploads/photos/ via vision + Tesseract OCR
- Matched keurig_label.jpg → Asset #5144 (machine_id 636671)
- Updated Asset #5144 photo_path in assets.db
- Created scripts/crossref_photos.py for reusable batch matching
- Reported unmatched IDs for coca_cola_label.jpg and telemetry_device.jpg
- Generated crossref_report.md with full findings
2026-05-29 09:56:49 -04:00
shawn e2db719fd7 docs: update OCR description to reflect Ollama vision primary 2026-05-29 09:00:27 -04:00
shawn b80ed4b483 feat: Ollama vision OCR via Windows PC for label photo matching
- Add persistent SSH tunnel (systemd service) to Windows PC Ollama
- Add _HAS_OLLAMA check at server startup (qwen2.5vl:3b)
- Replace Tesseract-only OCR with Ollama-first strategy
- Ollama (qwen2.5vl:3b) handles dark/complex labels Tesseract can't read
- Keurig serial 2500.0100.0025534 now correctly matched as Asset #5144
- Add ocr_source field to /api/ocr response ('ollama' or 'tesseract')
- Fix match_label_photo.py argparse bug (image_paths -> images)
- Update match_label_photo.py CLI to read vision key from Hermes config
2026-05-29 08:59:53 -04:00
shawn 8022c77b70 feat: add normalized matching for label photos → asset DB lookup
- normalize_identifier() strips dots/dashes/prefixes, keeps alphanumeric
- find_asset_by_normalized_id() searches serial_number, connect_id,
  equipment_id, barcode with normalized comparison
- /api/ocr now returns matched_assets in addition to legacy machine_id
- New /api/match-text endpoint for client-side text matching
- scripts/match_label_photo.py CLI tool for OCR + DB matching
- Vision model fixed (mimo-v2-omni at opencode.ai, was using
  truncated placeholder key)
2026-05-29 08:37:06 -04:00
shawn e10e226743 Add serial_number to barcode search
- /api/assets/search now also matches serial_number column
  so scanning a sticker with just the serial number works
2026-05-29 07:59:37 -04:00
shawn 8c8f8a261c Add 2D barcode scanning + connect_id search
- Add QR_CODE, DATA_MATRIX, PDF_417, AZTEC to barcode scanner hints
  so serial number stickers with 2D barcodes can be scanned
- Update /api/assets/search to also match connect_id so full
  Connect IDs (e.g. VM-05912-0000068454) work when scanned
- Bump SW cache v5→v6, footer v3.2→v3.3
2026-05-29 07:55:44 -04:00
shawn 2bdcfe0bae feat: branch fallback for assets without account linkage
- 1,606 more assets now get company from branch/territory name
  (e.g. 'Canteen Corp/Orlando, FL') when the connect_id exists
  in extraction DB but has no linked account name
- Coverage: 7,349/7,488 (98.1%) have company + customer_name
- Only 139 remain empty (4 prefixes not in branch cache)
- Updated AGENTS.md with data population docs
2026-05-29 07:51:02 -04:00
shawn 4f9c0d0b75 feat: populate company/place/customer_name from MSFS extraction DB
- New script: scripts/populate_asset_company_place.py maps connect_id →
  account name (company/customer_name) + city (place) + address via
  extraction DB (msdyn_customerasset + account join)
- 5,743/7,488 assets now have company + customer_name populated
- 5,647/7,488 assets now have place (city) populated
- Fix: SELECT COALESCE(c.name, a.customer_name) so stored customer_name
  isn't overridden to NULL when customer_id FK is missing
- Bump SW v4→v5, version v3.1→v3.2 to force cache refresh
2026-05-29 07:45:01 -04:00
shawn 5180d811a8 fix: add place/building/floor fields to main detail view
The detail view's Asset Details card was missing location fields
(place, building_name, building_number, floor, room, trailer_number)
that were visible in the list cards. Added them alongside Model
so building/floor info appears in the main card rather than only
in the collapsed Directions & Access section below.
2026-05-29 00:25:10 -04:00
shawn f1eb453a19 fix: keep GUEST/CAST visible in asset names
- clean_customer_name() no longer strips GUEST/CAST suffixes
- Re-ran migration: 967 asset names updated with GUEST/CAST preserved
- Format: '95301 - Animal Kingdom CAST / address / building'
  vs previous: '95301 - Animal Kingdom / address / building'
2026-05-29 00:13:08 -04:00
shawn 9ee8de8578 fix: add/find tab now lookup-only, nav fix, route techs fix
- Add/Find tab: removed check-in card and add-asset form, now pure lookup
- OCR: stop camera after capture, added GPS capture at photo time
- OCR: increased timeout from 8s to 15s to reduce 500 errors
- Nav tab: added GPS prompt + asset search when navigating directly
- Route: include all 26 techs from bookableresource table (not just Shawn)
2026-05-29 00:10:30 -04:00
shawn 1db6475f83 feat: asset naming, location extraction, and location display
- New asset naming: {MID} - {Customer} / {Address} / {Building details}
- Extracted 660 building_names from customer data (Disney resorts, hotels)
- 1,704 assets now have location data (building_name, floor, etc.)
- Location section in detail view now shows building, floor, trailer, room
- Added has_gps filter to API for map loading
- Added location_source column to track GPS origin
2026-05-28 23:58:56 -04:00
shawn ae3b114ebc feat: import Seed (mycantaloupe.com) data — 1,655 assets enriched
- Added import_seed.py — reads Machine List(8).xlsx, matches by Asset ID → machine_id
- 51 new columns on assets table (route, barcode, sales, contact info, etc.)
- seed_data table with full 62-field JSON per asset for detail enrichment
- Seed data card in frontend asset detail view
- GET /api/assets/{id} now returns result.seed and result.seed_imported_at
- GPS columns from Seed ignored per request
- 1,654 matched, 199 unmatched (Seed-only assets not in MSFS)

Refs #47
2026-05-28 23:28:08 -04:00
shawn 908c67a26c docs: update msfs-data-import.md after clean-slate reset
- Cleared all MSFS-derived (address-geocoded) GPS
- Only real field GPS (28 assets from photo EXIF) remains
- Documented backup locations and clean-slate process

Refs #46
2026-05-28 23:01:17 -04:00
shawn a8158566ac feat: OCR auto-saves GPS to asset + MSFS enrichment in detail view
OCR endpoint (/api/ocr) now auto-saves EXIF GPS from the photo
to the asset's latitude/longitude fields when they are blank,
so the first photo scan at a machine permanently records its location.

GET /api/assets/{id} now includes an 'msfs' block enriched from
the merged Dynamics 365 Field Service data (merged-assets.json)
loaded at server start (1,834 matched assets). Fields shown:
equipment_id, connect_id, compass_asset_number, manufacturer,
model_text, dex_model, install_date, software_version, etc.

Frontend updates:
- New 'Field Service Data' card in asset detail view when MSFS
  data is available (manufacturer, Connect ID, install date, etc.)
- '📍 GPS saved to asset' confirmation shown after OCR auto-save
- AppState.ocrGpsSaved flag to track the auto-save event
2026-05-28 22:28:34 -04:00
shawn 3a8f89432a fix: stray closing brace broke entire JS script + remove login gate for guest mode 2026-05-28 22:16:43 -04:00
shawn b07c30da5e docs: MSFS data import pipeline — extraction → merge → assets.db 2026-05-28 22:07:14 -04:00
shawn 77ffb0ab2a Remove unused exifr CDN from index.html 2026-05-28 22:04:27 -04:00
shawn 7c1ceafc6b Remove auth: fall back to default admin user when no token provided (field tool mode) 2026-05-28 22:03:58 -04:00
shawn f3d176116a Major app overhaul: MSFS data import, lookup-only Find tab, OSRM nav, cleanup 2026-05-28 21:57:58 -04:00
shawn a9f2f88604 ux: Increase map max-height from 60vh to 70vh for better square ratio 2026-05-27 19:51:45 -04:00
shawn 855976e2b6 ux: Map tab enhancements + toast replacements
- Replace 9 native alert()/confirm() calls with showToast()
- Add search bar over map (name, machine_id, category, description)
- Add filter chips with category counts (Bev, Food, Snack, etc.)
- Make map container square (aspect-ratio 1/1)
- Add asset list below map showing filtered results
- Increase asset limit from 1000 to 2000
- Fix missing closing brace in .geofence-panel CSS
- Zero console errors on all tabs
2026-05-27 19:33:43 -04:00
shawn e66bf2638b fix: route planner fetch calls now use api() wrapper with auth token
Root cause: rpLoadTechs() and all other route planner API calls used
raw fetch() instead of the api() wrapper, so no Authorization header
was attached. Auth middleware returned 401, technician list never
loaded, users saw 'Select at least one technician'.

Fixed by replacing all 6 fetch('/api/...') calls in the route planner
with api('/api/...') and removing redundant .json() parsing (api()
returns parsed data directly).

Tested in browser: technician checkboxes populate, Load Today's Route
returns 3 optimized stops with 12.5km route, map renders correctly,
search tab queries return Disney WO results via auth.

Closes: #issue-to-be-created
2026-05-27 19:08:58 -04:00
shawn 3eb09bd861 ux: 5.0 heuristic scorecard — loading states, help modal, keyboard shortcuts, guided empty states, error recovery 2026-05-27 18:57:28 -04:00
shawn b2ceac1594 ux: improve login loading state, toast timing, tab label consistency, enable location filter 2026-05-27 18:35:49 -04:00
shawn da2a23f6da Inline route optimization into canteen server (remove proxy to daily-route on port 8912)
- Added extraction DB config and _get_extraction_db() helper
- Added _status_label, _haversine, _solve_tsp (nearest-neighbor + 2-opt)
- Added GET /api/workorders/search (native)
- Added POST /api/workorders/lookup (native)
- Added GET /api/workorders/today (native, reads bookableresourcebooking)
- Added GET /api/workorders/technicians (native)
- Added POST /api/route/optimize (native TSP solver)
- Removed httpx dependency, _proxy_route, _get_route_client
- Removed all proxy endpoints
2026-05-27 18:18:24 -04:00
shawn a1022b300e Sync prod: customer_name JOIN, search debounce, parent company filter, asset detail card with map 2026-05-26 15:54:07 -04:00
shawn 6cb76d8a33 Remove redundant drawer triggers — keep only hamburger ☰
- Removed onclick=openDrawer() from user badge
- Removed '⋯ More' bottom tab (also opened drawer)
- Header hamburger ☰ remains the single drawer trigger
2026-05-25 23:22:17 -04:00
shawn d3e1068e1f Fix bottom tab text clipping — increase horizontal padding 2px→6px 2026-05-25 23:17:07 -04:00
shawn faacf0bce9 Rename 'Add Asset' tab to 'Add / Find Asset' across nav + tabs
- Drawer nav: 'Add Asset' → 'Add / Find Asset'
- Bottom tab bar: 'Add Asset' → 'Add / Find Asset'
- Updated e2e_browser_test.py assertions to match
2026-05-25 23:14:52 -04:00
shawn 7c965b4262 Add AGENTS.md for AI agent context 2026-05-25 20:18:57 -04:00