Commit Graph

32 Commits

Author SHA1 Message Date
spouliot d9bf80cc9a Update help docs and AI knowledge base for SMS notifications
- Settings help article: add SMS Notifications subsection covering company opt-in, TCPA terms agreement, compose-before-send vs auto-send, and STOP opt-out
- Customers help article: add Mobile Phone and SMS Opt-In fields to the Adding a Customer field list
- HelpKnowledgeBase: remove stale "ready for pickup" SMS event, add company opt-in flow, customer opt-in requirement, compose modal for Admin/Manager, auto-send for ShopFloor, Send SMS button, and STOP opt-out behavior; remove SuperAdmin-only SMS Platform Setting content

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 22:32:55 -04:00
spouliot 6569d9c4ea Add SMS gating, TCPA terms agreement, and compose-before-send modal
- Three-tier SMS gate: platform kill-switch → admin force-disable → plan AllowSms → company opt-in
- CompanySmsAgreement entity records admin acceptance of TCPA terms with IP, user agent, and terms version
- SMS terms of service modal on Company Settings with versioned re-agreement (AppConstants.SmsTermsVersion)
- Dev redirect: non-production SMS routed to Twilio:DevRedirectPhone to protect real customer numbers
- Removed redundant Ready for Pickup SMS (Job Completed covers it)
- Role-based compose modal on job completion: Admin/Manager reviews and edits before send; ShopFloor auto-sends
- Send SMS button on job details for ad-hoc messages (Admin/Manager only)
- SendJobSmsAsync auto-appends STOP opt-out language if missing
- Migrations: AddSmsGating, AddCompanySmsAgreement

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 22:29:39 -04:00
spouliot 0b798cadb4 Add Cancel button to inventory QR scan usage page
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 20:26:39 -04:00
spouliot 49e3d73c67 Add click-to-enlarge lightbox for inventory product image
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 20:20:01 -04:00
spouliot 90a06c6acd Add product image to powder inventory via AI lookup
When AI Lookup fetches a manufacturer product page, it now extracts the
og:image (Open Graph) meta tag before stripping HTML tags. The image URL
is returned in InventoryAiLookupResult.ImageUrl and automatically shown
as a preview on the Create/Edit form alongside the other filled fields.

The preview includes a Remove button to clear the image, and the Wrong
Match? button clears it along with the other AI-filled fields.

On the inventory Details page a product image card is rendered above the
Stock & Pricing card whenever ImageUrl is set. The field is nullable so
existing records and powders without an image are unaffected.

New field: InventoryItem.ImageUrl (nvarchar, nullable).
Migration: AddInventoryItemImageUrl.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 18:15:55 -04:00
spouliot 9221fcc783 Add quote-changed banner with re-sync to job details
When a source quote is edited after a job was created from it, the job
details page now shows a warning banner with the date of the change and
a link to the quote. Two actions are offered:

- Re-sync from Quote: replaces all job items, coats, prep services, and
  pricing from the current quote. Only available while the job is still
  in a pre-production status (Pending, Quoted, Approved); hidden once
  shop work has started (InPreparation or beyond).
- Dismiss: acknowledges the change without altering the job, clearing
  the banner by advancing the stored snapshot timestamp.

Implemented via Job.QuoteSnapshotUpdatedAt (new nullable column), set at
quote→job conversion time. The banner fires when quote.UpdatedAt exceeds
this baseline. Migration: AddJobQuoteSnapshotUpdatedAt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 18:02:46 -04:00
spouliot 8de9cd04b8 Add server-side dismiss persistence and SuperAdmin onboarding progress page
Progress widget dismiss now POSTs to Dashboard/DismissProgressWidget, writing
GuidedActivationDismissedAt to the DB so the widget stays hidden across devices
and cache clears (localStorage alone wasn't enough). BuildShopProgressWidgetAsync
suppresses the widget server-side when AllDone + dismissed.

New SuperAdmin page at /OnboardingProgress shows the activation funnel across
all tenant companies: wizard status, chosen path, milestone progress bar, key
dates (first job/quote, first invoice, workflow completed, widget dismissed),
and a status badge (Not Started / In Progress / Complete / Dismissed). Nav link
added under Users & Activity in the Platform Management sidebar.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 09:23:20 -04:00
spouliot 73df72ab97 Add dismiss button to progress widget completion state
Shows an × button in the top-right of the completion card so users can
permanently hide the widget once they've seen the success message. Dismissal
is stored in localStorage (same pattern as the collapse state) so it persists
across page loads without requiring a DB migration. The widget hides itself
on the next load before any layout is shown, avoiding a flash.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 21:37:53 -04:00
spouliot b1337d3b61 Update help docs and AI knowledge base for onboarding overhaul
GettingStarted.cshtml: updated Setup Wizard description from 10-step to
5-step, revised time estimate (5–10 min), added new "After the Wizard"
section explaining the guided activation first-workflow flow and the
progress widget (what it tracks, how the highlight works, when it
disappears, Admin-only visibility).

HelpKnowledgeBase.cs (AI assistant): updated Setup Wizard entry to 5 steps,
replaced old step list (removed steps 5–8, 10), updated new company
quick-start checklist to reference the 5-step wizard and the post-wizard
progress widget. Added new GUIDED ACTIVATION section covering the two
onboarding paths (Quote First / Job First), the Daily Board intro experience,
and how the banner auto-dismisses. Updated Common Workflows to reflect the
new onboarding order. Dashboard section now describes the progress widget
and its six tracked steps.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 21:10:59 -04:00
spouliot 8aae30765f Onboarding overhaul: slim wizard, progress widget, guided activation UX
Setup Wizard: reduced from 10 steps to 5 (Company Info → QB Migration →
Pricing Defaults → Named Ovens → Notifications). Removed Doc Numbering,
Job Settings, Payment Terms, Pricing Tiers, and Team Members steps — these
all have sensible defaults and are accessible any time in Company Settings.
Wizard now completes in ~5 minutes instead of 15–20.

Dashboard progress widget (new): "Get the most out of your shop" checklist
appears for Company Admins after wizard completion. Tracks six post-setup
activation tasks with dynamic progress badge, motivating subtitle copy,
collapsed-state persistence via localStorage, and a full completion state
("Your shop is fully set up 🎉") that replaces the checklist at 100%.
The next recommended step is highlighted with a solid CTA button and a
subtle blue row tint. Completed steps show encouraging green subtext instead
of just "Done". Widget disappears from controller when AllDone would have
caused a silent vanish — now renders the completion state instead.

Guided activation (Daily Board): rewrote the BoardIntroStep callout to lead
with "This is your shop in real time" and a plain-English description of the
board's purpose. Added a separate InstructionText field to
GuidedActivationCalloutViewModel so the "Move this job to the next stage"
action prompt renders as a distinct bold line with an arrow icon rather than
being buried in the body copy. After the stage change, the confirmation
callout now reads "Nice — your workflow just updated" to reinforce what just
happened before prompting the invoice step.

All copy passes the "shop owner, not SaaS" test: no technical jargon,
benefit-driven descriptions, natural language throughout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 21:10:47 -04:00
spouliot 5631d1d57a Add WarningPermanent toast type and upgrade invoice failure notifications
Email delivery failures and PDF generation errors now show a permanent
warning/error toast that requires manual dismissal, so users cannot
accidentally miss critical action-blocking feedback.

- ToastHelper: WarningPermanent TempData key + Warning/WarningPermanent
  extension methods on both ITempDataDictionary and Controller
- SetNotificationResultToast: NotificationStatus.Failed now uses
  ToastWarningPermanent (previously auto-dismissed in 5 s)
- InvoicesController.Send: TempData["Warning"] → TempData["WarningPermanent"]
  when PDF generation or email dispatch fails
- InvoicesController.DownloadPdf: TempData["Error"] → TempData["ErrorPermanent"]
  with the actual exception message so root cause is visible
- _Layout.cshtml: WarningPermanent hidden div
- toast-notifications.js: WarningPermanent handler (timeOut: 0)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 16:02:16 -04:00
spouliot cad728ba66 Fix passkey login tracking, add email opt-out UI guards, and add Quick/Full quote mode toggle
- PasskeyController: set LastLoginDate on passkey sign-in so Company Health
  and audit pages show accurate last-login times (was always showing 'Never')
- Jobs/Index status modal: disable 'Notify customer' email toggle and show
  warning when customer has notifications turned off; CustomerNotifyByEmail
  added to JobListDto + JobProfile mapping + data-customer-notify attribute
- Quotes/Create: disable 'Send quote via email' checkbox with 'Notifications
  off' badge when selected customer has email opt-out; ViewBag.CustomerEmailOptOutIds
  added alongside existing CustomerTaxExemptIds pattern
- Quotes/Create: Quick Quote / Full Quote segmented toggle at top of form;
  hides non-essential fields (dates, notes, tags, oven, discount, photos) in
  Quick mode; selection persisted in localStorage
- InvoicesController Send action: improved error logging and user-facing
  warning when PDF generation or email dispatch fails after status is saved
- item-wizard.js: guard item restoration with try/catch; ensure writeHiddenFields
  always runs on form submit via capture-phase listener
- Help docs and AI knowledge base updated for all new features

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 13:32:34 -04:00
spouliot 8491b308eb Add admin email wizard and logging 2026-04-26 17:01:09 -04:00
spouliot a4b8ae611a Add passkey prompt dismissal and consolidate company admin navigation
- Add "Don't ask me again" to passkey enrollment prompt (PasskeyPromptDismissed
  field on ApplicationUser; DismissPrompt POST action; migration applied)
- Add Subscription & Features button to Companies/Index btn-group and
  Companies/Edit header for direct navigation to SubscriptionManagement/Manage
- Add Edit Company back-link on SubscriptionManagement/Manage
- Remove duplicate AI Features section from Companies/Edit (managed exclusively
  via Subscription & Features page)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 10:34:50 -04:00
spouliot f03a198e79 Make AiCatalogPriceCheckEnabled a plan-override toggle
Company-level toggle now grants access regardless of plan tier, checked
before the plan gate. Useful for enabling the feature on individual
Pro/Basic companies without upgrading their plan.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 08:41:27 -04:00
spouliot cb7bbc37bd Add three-layer feature gating for AI Catalog Price Check
Adds platform-level, plan-level (Enterprise only), and per-company
toggles for the AI Catalog Price Check feature. Includes:
- Company.AiCatalogPriceCheckEnabled per-company flag
- SubscriptionPlanConfig.AllowAiCatalogPriceCheck plan-level flag
- PlatformSetting 'AiCatalogPriceCheckEnabled' global kill switch
- IPlatformSettingsService.GetBoolAsync helper
- ISubscriptionService.CanUseAiCatalogPriceCheckAsync
- UI controls in Companies/Edit, PlatformSubscription/Edit+Index,
  and SubscriptionManagement/Manage
- Migration AddAiCatalogPriceCheckGating applied

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 08:29:51 -04:00
spouliot fa9fa76231 Document AI Catalog Price Check in knowledge base and help article
- HelpKnowledgeBase: full AI price check section (verdicts, confidence,
  category paths, run limit, how to use, common questions)
- Inventory help article: new 'AI Catalog Price Check' section with
  verdicts, step-by-step instructions, caveats, and on-page nav link

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 22:55:05 -04:00
spouliot 4128c15bbb Remove 'Claude' brand references from all user-facing views
Replace with generic 'AI', 'AI agent', or 'AI system' throughout.
Keeps the underlying vendor implementation details off the UI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 22:51:36 -04:00
spouliot 6d9111b448 Rename button and add explanatory blurb to AI price check page
- Button: 'Run/Re-run Price Check' -> 'Analyze Catalog with AI'
- Add info card explaining what the analysis does, verdict meanings,
  and the disclaimer to verify operating costs before running

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 22:49:49 -04:00
spouliot 37c95192ca Enforce quarterly run limit on AI price check
- GET: sets ViewBag.NextRunAvailable if last run was within 90 days;
  view disables the button and shows the next eligible date
- POST: returns early with a warning if called before the 90-day window

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 22:48:39 -04:00
spouliot 9943c11571 Add progress overlay to AI Catalog Price Check
Shows a modal overlay with animated progress bar and batch-aware status messages
while Claude is analyzing. Progress animates in two phases: ease-out to ~85%
over the estimated duration, then a slow crawl to 99% so it never falsely
"completes" before the server responds.

- Overlay driven by CSS (hidden until .active added by JS)
- Item count passed from controller as data-item-count on the run button
- Batch count derived from item count (batches of 25) to show accurate
  "Analyzing batch N of M…" messages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 19:27:08 -04:00
spouliot 360edace72 Fix EnrollPrompt page layout squished on desktop
The auth panel CSS (brand panel gradient, form panel flex centering, feature list,
subtext color) was only defined in Login.cshtml's @section Styles — not in the
shared auth layout. EnrollPrompt used the same class names but had no styles behind
them, so the two-column layout collapsed. Added matching styles in EnrollPrompt's
own @section Styles block.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 19:16:40 -04:00
spouliot 54f444d981 Add AI Catalog Price Check feature
Claude reviews every active catalog item against the shop's own operating costs
and returns a per-item verdict (below-cost / thin-margin / high / ok) with a
suggested price range, cost floor, and assumptions.

- New entity: CatalogPriceCheckReport (JSON blob, archived per company)
- New service: IAiCatalogPriceCheckService / AiCatalogPriceCheckService
  batches items 25 at a time to stay within model context limits
- Two new controller actions: GET AiPriceCheck (view report) + POST RunAiPriceCheck
- AiPriceCheck view: summary cards (counts by verdict), color-coded item cards
  with Edit Price link, assumptions detail, and loading spinner on submit
- AI Price Check button added to catalog Index header
- Migration AddCatalogPriceCheckReport applied

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 18:41:56 -04:00
spouliot edce8e8c4a Move passkey enrollment prompt to post-login dedicated page
After password login, users are routed through /Passkey/EnrollPrompt
before reaching the dashboard. The page shows an Enable / Maybe later
choice using the auth layout for a clean full-screen experience.
Users who already have a passkey are skipped past instantly.

Removes the floating bottom-right card from _Layout — the dedicated
page is a better UX touchpoint (one moment, right after login, rather
than a floating card on every page).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 16:41:01 -04:00
spouliot 90a5a028ad Update docs and AI assistant for passkey biometric login
- HelpKnowledgeBase: passkey entry under USER PROFILE section with
  full how-it-works detail (setup, login flow, browser requirements,
  account-lock enforcement, per-device management)
- UserProfile help article: new Passkeys & Biometrics section between
  Two-Factor Auth and Appearance, with setup steps, login steps,
  browser compatibility note, and lost-device warning
- TOC nav link added to UserProfile article sidebar

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 15:08:46 -04:00
spouliot 0bb96a502a Add passkey / biometric login (WebAuthn FIDO2)
Shop floor workers can log in once with a password, enroll a passkey,
and use Face ID / Windows Hello / fingerprint for all future logins.

- UserPasskey entity + AddUserPasskeys migration (Fido2 v4.0.1)
- PasskeyController: RegisterOptions, Register, LoginOptions, Login,
  Manage, Remove endpoints
- Login page: platform-aware button (Face ID / Windows Hello / etc.)
  hidden automatically if browser doesn't support WebAuthn
- Post-login floating prompt to enroll on first use; session-dismissed
- Passkeys & Biometrics link in user dropdown menu
- Manage page: list registered devices, add new, remove individual
- passkey.js: targeted base64url conversion (only challenge + user.id
  + credential IDs) — fixes "Required parameters missing" error caused
  by blindly converting rp.id and other string fields to ArrayBuffers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 15:07:01 -04:00
spouliot 4f976b1332 Require auth on all work order QR codes and add top view QR
- StatusBump (GET + POST) now requires authentication; routes by job ID
  instead of anonymous ShopAccessCode GUID; records actual user name in
  status history instead of anonymous token string
- WorkOrder action generates a second "View Job" QR in the header linking
  to the authenticated Details page (for verifying specs and seeing catalog
  images on mobile); status bump QR updated to ID-based URL
- WorkOrder view: top QR added to header alongside job number; status bump
  label updated (removed "no login required" copy)
- StatusBump view: updated form routing from asp-route-token to asp-route-id
- HelpKnowledgeBase and Jobs help article updated with two-tier QR docs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 13:27:43 -04:00
spouliot 00bf8a4cd0 Add catalog item images with thumbnail preview in wizard
Each catalog item now supports one optional image (jpg/jpeg/png/gif/webp,
max 10 MB). Uploading generates a 200x200 JPEG thumbnail automatically via
SixLabors.ImageSharp. Images are stored in Azure Blob Storage under a new
catalogimages container, keyed by {companyId}/catalog/{itemId}/.

- CatalogItem entity: ImagePath + ThumbnailPath (nullable string fields)
- Migration: AddCatalogItemImages applied
- ICatalogImageService / CatalogImageService: upload, thumbnail generation,
  delete; old blobs replaced atomically on re-upload
- CatalogItemsController: Create/Edit accept optional IFormFile image;
  Image(id, thumbnail) action serves blobs with [Authorize] so wizard users
  can load thumbnails without CanManageProducts policy
- Catalog index (_CategoryNode): 40x40 thumbnail (or placeholder icon)
  left of each item name
- Details view: image card in right column with click-to-full-size link
- Create/Edit views: file picker with live preview; Edit shows current
  thumbnail with Remove checkbox
- Wizard (item-wizard.js): thumbnails in product list with hover preview
  that follows the cursor (showCatalogPreview / moveCatalogPreview);
  fixed Bootstrap d-flex !important bug that broke the filter box by
  moving flex layout to an inner wrapper div

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 09:33:59 -04:00
spouliot 3327c86909 Add AI Profile draft generator and hide AI Quick Quote for release
- GenerateAiProfileDraft endpoint builds suggested AI Profile text from
  existing company config (ovens, workers, inventory categories, rates)
- "Generate from my settings" button wired in Company Settings AI Profile tab
- Add "hrs" unit label to Billable Hours/Month input in Company Settings and Setup Wizard Step 3
- Hide AI Quick Quote widget (commented out in _Layout) pending next release

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 21:29:42 -04:00
spouliot 4153acf3aa Add facility overhead (rent + utilities) to operating costs and pricing engine
Adds MonthlyRent, MonthlyUtilities, and MonthlyBillableHours to CompanyOperatingCosts so fixed shop occupancy costs are recovered on every quote. The pricing engine converts these into a per-hour rate and applies it as a transparent "Facility Overhead" line between oven batch cost and shop supplies. UI added in Company Settings Operating Costs tab and Setup Wizard Step 3; migration AddFacilityOverheadFields applied. Help docs and AI knowledge base updated to cover the new fields and the revised quote pricing calculation order.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 19:35:00 -04:00
spouliot 8d94013895 Add AI Quick Quote widget and inline customer reassignment
- New AI Quick Quote floating button: staff type a verbal description to
  get an instant price estimate for phone/walk-in customers; detected
  color names are fuzzy-matched against inventory for stock status;
  saves draft quote under a Walk-In / Phone customer with one click
- Inline customer change on Quote Details and Job Details: always-visible
  native select with inline confirmation banner (no TomSelect dependency);
  ChangeCustomer AJAX endpoints on QuotesController and JobsController
- Quote Edit page: customer dropdown is now editable (lock removed)
- Fix AutoMapper missing CatalogCategory -> UpdateCategoryDto mapping
  that caused a crash on the catalog category Edit page
- Help docs and AI knowledge base updated for all three features

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 17:02:03 -04:00
spouliot 63e12a9636 Initial commit 2026-04-23 21:38:24 -04:00