206 Commits

Author SHA1 Message Date
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
shawn 34da18530f Remove auto-visit GPS tracking
- Removed startVisitTracking / stopVisitTracking functions
- Removed checkProximityToAssets and haversineM
- Removed logAutoVisit and all visit timer logic
- Removed visitTracker UI div on Map tab
- Removed GPS watchPosition call (was polling at ~1-5s intervals)
- Kept server-side /api/visits endpoints (used by heatmap) and one-shot GPS for scan check-in

Reason: GPS auto-tracker can't distinguish machines above/below each other
on different floors.
2026-05-24 17:41:43 -04:00
shawn 839fcdedc5 docs: update FEATURES.md and USER_GUIDE.md for scan redirect feature 2026-05-24 17:18:01 -04:00
shawn f4cbe00f7f feat: scan existing asset redirects to detail view instead of scan result card
When a user scans a barcode that matches an existing asset:
- Redirect directly to the asset detail view (Assets tab)
- Auto-checkin still runs in background if GPS available
- Show a toast notification with the asset name

When scanning a barcode not in database:
- Switch back to Add Asset tab and show the create form
- Deferred status update survives async startScanning

No backend changes needed.

Closes #39
2026-05-24 17:17:13 -04:00
shawn b896a5680d feat: enlarge asset list cards — bigger icons, padding, prominent floor/building/room display 2026-05-23 20:31:48 -04:00
shawn 9fe615c76b clean up asset names: strip addresses/floors/parks/building prefixes from names (353/1848 cleaned) 2026-05-23 20:24:51 -04:00
shawn 76e28614ae feat: tag Disney assets with park/resort codes and display names
- Script: scripts/tag_disney_properties.py (supports dry-run + --apply)
- Maps 112 Disney location IDs to park/resort/office/other codes
- Updated 994 assets: disney_park column + appended display name with emoji
- Added disney_park column to locations table, populated 112 rows
- Covers all 364 locations via case-insensitive substring matching
2026-05-23 19:50:16 -04:00
shawn a5708623cc feat: show address, floor, building, room in asset list items
- Add .ai-address and .ai-location CSS classes
- Increase .asset-item padding to 14px, align-items to flex-start
- Reduce .ai-name font to 14px, allow wrapping
- Render address line (📍 icon) when present
- Render floor · building · room location line when any field present
- Keep existing icon and meta line unchanged
2026-05-23 19:46:25 -04:00
shawn 13bf61d856 feat: extract floor/building/room/trailer from asset names
Adds scripts/extract_asset_location_data.py which:
- Extracts floor, building_number, room, trailer_number, building_name from names
- Detects and removes duplicated name segments
- Updates both assets (1848) and locations (364) tables
- Dry-run mode by default, --apply to write changes
2026-05-23 19:41:55 -04:00
shawn a305766d65 fix: show '— No report yet' for assets without dex_report_date 2026-05-23 18:46:58 -04:00
shawn 6016f6a5e6 feat: add No DEX (5d) filter toggle to asset list filter panel
- Add .filter-toggle.warn CSS styles (amber border/text with active bg)
- Add Data Health row with toggle button in filter panel HTML
- Add noDexFilterActive state variable and toggleNoDexFilter() function
- Wire no_dex_days=5 into API URL builder when toggle active
- Integrate into getActiveFilterCount, renderActiveFilterTags, removeFilter, clearAllFilters
2026-05-23 17:41:04 -04:00
shawn 9d9e50834c feat(import_machines): add dex_report_date, deployed, pulled_date extraction
- Extract from row[7] (Col 8), row[34] (Col 35), row[35] (Col 36)
- Handle datetime -> ISO conversion for date columns
- Include in UPDATE and INSERT statements

Kanban: t_3bef3c9c
2026-05-23 17:30:10 -04:00
shawn 4ebe3a5076 feat: add dex_report_date to AssetCreate model + test for no_dex_days filter
- Add dex_report_date field to AssetCreate Pydantic model
- Include dex_report_date in _build_asset_insert columns/values
- Add test_list_assets_filter_no_dex_days test (11/11 pass)
2026-05-23 17:29:37 -04:00
shawn 900f912147 v5 migration: add dex_report_date and install_date columns to assets table 2026-05-23 17:26:11 -04:00
shawn c9c6317900 fix: larger park/resort labels (13px bold), allow 2-line wrap, center-aligned 2026-05-23 00:41:35 -04:00
shawn 0be50e7957 fix: revert chips to emoji, Snack pins use 🍿 fallback (img→emoji), bigger markers 28px 2026-05-23 00:37:10 -04:00
shawn 1bb03eb964 feat: SVG icons for map toolbar chips — flame/crosshair/outline, 13px, with label spans 2026-05-23 00:34:54 -04:00
shawn 384a0b842b fix: simple colored circle pins, no transforms — 22px dot with emoji and white border 2026-05-23 00:33:53 -04:00
shawn 71de462040 fix: teardrop pin markers (smaller, 24px) with category emoji on white dot 2026-05-23 00:31:46 -04:00
shawn 26311e7fe6 feat: text labels on Leaflet.draw toolbar — Area/Box/Circle/Edit/Delete instead of bare icons; revert chip changes 2026-05-23 00:29:56 -04:00
shawn 0401e45ea4 feat: category-based icon pins on map — 🥤🍔🔧 etc instead of blue dots 2026-05-23 00:27:54 -04:00
shawn 796914b089 feat: clearer map control icons with SVG + label spans, replace emoji chips 2026-05-23 00:25:43 -04:00