Commit graph

305 commits

Author SHA1 Message Date
justin
d51a2f61b4 fix Iowa: remove wrong Socrata dataset (was liquor stores), mark SOS as WAF-blocked 2026-05-30 19:28:41 -05:00
justin
a6c7d2aef8 increase SOS lookup timeout to 20s for slower state portals 2026-05-30 19:23:41 -05:00
justin
e8a98b1130 corporate check: live SOS lookup via state adapters for all 51 states
- Formal entities: queries workers /entity-status endpoint for real-time
  Secretary of State status (ACTIVE/dissolved/revoked/delinquent)
- Green if active, red if not active, yellow if not found or lookup failed
- Sole proprietors: yellow 'form an LLC' upsell
- 12s timeout so compliance check doesn't hang on slow state portals
2026-05-30 19:21:06 -05:00
justin
e2313bcc5e add blur detection + Ollama ID validation + corporate check for all carriers
- Client-side: Laplacian variance blur detection in photo quality check
  (very blurry / somewhat blurry / acceptable / good)
- Server-side: async Ollama vision model validates uploaded image is a
  real government ID (minicpm-v:8b), flags non-ID uploads
- Corporate check: sole proprietors now get yellow 'form an LLC' upsell,
  formal entities get annual report/RA reminder
2026-05-30 19:17:31 -05:00
justin
e40f359693 fix photo upload: add synchronous /jobs/presign and /jobs/minio-upload endpoints to workers 2026-05-30 19:13:51 -05:00
justin
ca7af40ceb update photo ID instructions: suggest QR code first for desktop users 2026-05-30 19:07:13 -05:00
justin
592b9875da fix TS build: use rawDot not dotNumber in pending filing query 2026-05-30 19:03:15 -05:00
justin
ffc5a16b5c add corporate compliance check (#15) to DOT checker + annual report/RA/reinstatement services
- Check 15: detects LLC/Inc/Corp/LTD/LP in entity name, shows yellow warning
  about annual reports, franchise tax, and registered agent requirements
- New services: annual-report-filing (49), registered-agent (9/yr),
  entity-reinstatement (99)
- Upsell opportunity: 1.31M formal entities in FMCSA database
2026-05-30 19:02:37 -05:00
justin
a3a546abff add FMCSA confirmation email monitor: IMAP watcher links confirmations to orders, Telegram notify 2026-05-30 19:01:42 -05:00
justin
b90d443667 add submit_filing(): 3x web retry then fax fallback, fix success detection, shared attestation helper 2026-05-30 18:58:14 -05:00
justin
4a4bbd048e fix FMCSA form: wait for lvl2 dropdown, update selectors 2026-05-30 18:54:34 -05:00
justin
99a53ad970 add FMCSA web submitter: Playwright automation for ask.fmcsa.dot.gov ticket form 2026-05-30 18:47:48 -05:00
justin
1f1113d63c add fax filing pipeline: VitalPBX sender, attestation cover page with digital signature, compliance checker pending filing override
- filing_attestation.py: generates cover page attesting PW submitted document
  to recipient with date/time stamp, contact info, and digital signature
- fax_sender.py: sends PDFs via VitalPBX API, polls for delivery, generates
  attested copy for customer records
- dot-lookup.ts: if DOT has pending MCS-150 order, show green 'UPDATE SUBMITTED'
  instead of red 'OVERDUE' in compliance checker
- requirements.txt: add pyhanko + cryptography for PDF digital signatures
2026-05-30 18:32:01 -05:00
justin
e2c7cc582b increase font sizes in photo ID section for readability (min 14px) 2026-05-30 18:15:22 -05:00
justin
e0fc4810d1 show proper error on phone when photo ID upload fails to MinIO 2026-05-30 18:13:18 -05:00
justin
7ef509c247 fix photo ID upload: use workers for MinIO storage + public presigned URLs
- id-upload.ts: replace broken direct minio import with workers presign/upload
- job_server.py: add minio-upload handler for API to store files via workers
- rewrite presigned URLs from internal minio:9000 to public minio.performancewest.net
- fixes: thumbnail not showing after phone upload, base64 fallback storage
2026-05-30 18:12:06 -05:00
justin
f60c5229ab Fix mobile photo upload: resize large camera images + increase body limit
Mobile cameras produce 8-12MB photos. Now:
- Canvas-based resize to max 2000x1500 before upload
- JPEG compression at 0.7-0.85 quality
- Express body limit increased to 5MB for id-upload route
- Falls back to raw upload for small images and PDFs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 17:24:16 -05:00
justin
04861ccfe0 Fix QR code: add inline script right at image element for immediate generation
Previous approach relied on the main is:inline script block which
could be blocked by FCC step crashes. New approach: tiny self-contained
script right next to the QR img element, runs immediately, fetches
upload token and generates QR. Falls back to page URL on failure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 17:20:04 -05:00
justin
6b874ea72b Add ts-nocheck to id-upload.ts (minio optional dep)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 16:42:41 -05:00
justin
0ba8730487 Add Telegram notifications for tickets, quotes, and insurance leads
Tickets: 📩 for support, 🏥 for insurance leads, 💰 for quotes
Quotes: 💰 with name, email, company, service, details
All fire-and-forget to Telegram bot — non-blocking.

Previously these only went to ERPNext with no real-time alert.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 16:35:11 -05:00
justin
66bd1306e3 Accept TIFF images for photo ID upload (scanner default format)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 16:28:22 -05:00
justin
d2f9e642d4 Hide QR code on mobile phones, auto-trigger camera on mobile
QR code hidden via CSS on screens < 640px (phones). On mobile,
file input gets capture=environment so tapping the button opens
the camera directly. Tablets still show QR code.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 16:25:52 -05:00
justin
1535acb413 Complete phone-to-desktop photo ID upload pipeline
- API: POST /api/v1/id-upload/token generates upload token
- API: POST /api/v1/id-upload/:token receives base64 image, stores in MinIO
- API: GET /api/v1/id-upload/:token/status returns upload status + thumbnail
- Mobile page: sends image as base64 with upload_token
- Desktop intake: requests token, generates QR with upload URL, polls
  every 3s for phone upload, auto-shows thumbnail when detected
- MinIO storage with presigned URLs for thumbnails
- Compliance order intake_data updated with photo_id_uploaded flag

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 16:24:35 -05:00
justin
1611b67543 Add mobile photo ID upload page at /portal/upload-id/
Dedicated mobile-friendly page for phone camera ID capture:
- Big "Take Photo of ID" button with camera capture
- Image preview with basic quality check
- Submit uploads to API with JWT auth
- Success/error states with retry
- QR code on desktop intake links here instead of full form

Still needs: API upload endpoint, polling from desktop, OCR validation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 16:20:27 -05:00
justin
daf6d1f831 Always show QR code for phone photo upload — no click to reveal
QR code displayed inline below the upload button so truckers can
immediately scan with their phone to take a photo of their ID.
Clear instructions: 'Scan with your phone camera to take a photo'

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 16:17:17 -05:00
justin
73a10d4a0f Simplify photo ID upload: clear instructions for truckers
- Yellow instruction box explains 3 methods in plain English
  (phone photo, computer upload, scanner)
- One big orange "Add Photo of Your ID" button
- Webcam + QR code kept in code but simplified UI
- Accepted formats note

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 16:11:49 -05:00
justin
3423b4914a Relabel photo ID buttons: Upload File/Scan + Use Webcam + scanner instructions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 16:09:47 -05:00
justin
39fb1c9998 Webcam capture for photo ID via getUserMedia
Desktop users can now use their webcam to photograph their ID:
- Click "Use Camera" → browser requests webcam permission
- Live video preview with orange guide rectangle for ID placement
- Capture button takes high-res JPEG (1280x720)
- Cancel button stops webcam and returns to upload options
- Captured image goes through same quality check flow
- Works on Chrome, Firefox, Edge, Safari (desktop + mobile)
- No libraries needed — native WebRTC API

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 16:09:02 -05:00
justin
c40dfb552e Auto-save intake data to server after every step
Intake data now persists to DB after each step completion (non-blocking).
If browser crashes, data is recoverable from compliance_orders.intake_data.

Partial saves (_partial: true) only update intake_data without changing
payment_status or marking intake_data_validated. Final submit still
triggers the full validation + worker dispatch flow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 16:01:20 -05:00
justin
beb23d777e Photo ID quality check after upload
Shows uploaded image at larger size with automated quality checks:
- File size (too small = low quality warning)
- File type validation (JPEG, PNG, PDF, HEIC)
- Resolution check (minimum 400x250 for readable text)
- Aspect ratio check (should look like an ID card)

Green checkmark for passing checks, red X for issues.
Yellow warning box for quality problems with specific guidance.
Accept & Continue button to confirm, Retake to re-upload.
After accept, collapses to small preview with "Change ID" option.

Front of ID only (sufficient for FMCSA MCS-150 filing).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 15:59:27 -05:00
justin
e8769e4d5d Photo ID upload: add QR code for phone + scanner device support
Three upload methods:
- Upload File: standard file picker
- Camera / Scanner: uses capture attribute for camera on mobile
  or TWAIN/WIA scanner devices on desktop
- QR Code: generates QR with current page URL so user can scan
  with phone and take a photo of their ID on mobile

QR generated via api.qrserver.com (no library dependency).
Remove button restores all upload options.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 15:56:00 -05:00
justin
b8a52303b3 DOT intake: use is:inline script to avoid hoisted bundle crash
FCC step scripts crash on DOT pages due to missing elements. By
using is:inline, DOT intake script runs independently, not in the
hoisted bundle. Stripped TypeScript annotations for plain JS compat.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 15:38:04 -05:00
justin
db96af53bf Guard DOT intake script — skip on non-DOT pages
Wraps entire script in element existence check to prevent running
on FCC pages where other step scripts crash from missing elements.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 15:35:52 -05:00
justin
989ccaec93 Fix MCS150Step null crash — was breaking ALL DOT intake pages
MCS150Step script compiled into hoisted JS for all order pages.
Non-null assertions on photo ID elements crashed on non-MCS150 pages,
preventing DOTIntakeStep's showRelevantSections from running.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 15:33:56 -05:00
justin
c98ac9ae54 Fix DOT intake crash: null-safe photo ID element refs
Script crashed on 'Cannot read properties of null' because photo ID
elements are inside a hidden section. All element refs now use
optional chaining instead of non-null assertions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 15:31:15 -05:00
justin
d55384975e Fix DOT intake: retry init until wizard found + null-safe PWIntake
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 15:29:42 -05:00
justin
7fe3311921 Fix DOT intake: wait for DOMContentLoaded before showing sections
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 15:27:39 -05:00
justin
897554fa4e Fix DOT intake: hide all sections by default, show on load
Sections were visible by default in HTML. Now all hidden, then
showRelevantSections() runs immediately + on pw:step-shown.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 15:26:41 -05:00
justin
ee4ea70beb Fix DOT intake section visibility — read slug from wizard data attribute
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 15:25:02 -05:00
justin
8ce9e2e118 Unified DOT intake form — one form for all trucking services
Single DOTIntakeStep shows/hides sections based on services ordered:
- Company info + address + signer (always)
- Entity & operations (MCS-150, USDOT, MC Auth, bundles)
- Fleet info (MCS-150, UCR, bundles)
- UCR fleet bracket + base state (UCR)
- Cargo types (MCS-150, bundles)
- D&A program (CDL drivers, DER, consortium)
- BOC-3 docket info (BOC-3)
- Photo ID upload (MCS-150, MC Auth)
- Security/encryption notices

All DOT services now use ["dot-intake", "review"] instead of ["review"].

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 15:23:48 -05:00
justin
72d1b336c5 Add --where filter to email verifier for targeted scrubs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 15:06:02 -05:00
justin
97f6a08183 Bind email verifier to secondary IP (.72) for SMTP probes
Campaign emails send from .71 via Postfix (now explicitly bound).
Verification RCPT TO probes go from .72 to protect sending reputation.
Configurable via VERIFY_SOURCE_IP env var.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 14:52:22 -05:00
justin
2dacf1ea0e FMCSA enrichment: OOS orders bulk download + authority/insurance API lookup
- Downloads 389K OOS orders from Socrata, merges into fmcsa_carriers
- Batch enriches authority status + insurance filing via FMCSA API
- Adds columns: oos_active, authority_status, insurance_*_on_file, etc.
- Rate limited to 1 req/sec for API calls
- Prioritizes campaign-eligible for-hire carriers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 14:46:40 -05:00
justin
6f3ad1b686 Customer dashboard: order tracking + portal login
- New page: /portal/dashboard/ — customer can view all orders
- Auth: cookie-based login, shows auth modal if not logged in
- Orders grouped by batch, filtered by DOT/FCC tabs
- Shows service name, amount, discount, status badge, payment method
- Portal API: /api/v1/portal/me now returns compliance_orders

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 14:20:58 -05:00
justin
1cfda2c119 Fix census download crash at 100K: integer out of range
safe_int now clamps values to PostgreSQL INTEGER max (2.1B) and
handles scientific notation. Mileage columns changed to BIGINT
on prod since carriers can have >2B annual miles.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 13:41:24 -05:00
justin
b59b266a80 MCS-150 intake: add encryption notice, EIN field, photo ID upload
- Security notice: SSL encryption, encrypted at rest, no third-party sharing
- EIN field added (required for MCS-150 form field 19)
- Photo ID upload with camera capture on mobile
- ID auto-deleted after filing processed
- Preview with remove button

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 13:28:43 -05:00
justin
a265990351 Add official FMCSA MCS-150 fillable PDF forms
MCS-150 (standard), MCS-150B (hazmat), MCS-150C (intermodal).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 13:08:32 -05:00
justin
d32ef991b8 Fix Dockerfile: use JSON array syntax for filenames with spaces
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 13:07:26 -05:00
justin
02b65fc37a Fix Dockerfile: quote MCS-150 filenames with spaces
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 13:06:58 -05:00
justin
8ab5768606 Add MCS-150 PDF forms to workers Docker image
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 13:05:26 -05:00