Alpaca QA Review

Automated + code review against QA sheet — March 18, 2026 — Tested with Playwright + source code analysis

0
Fixed
0
Not Fixed
0
Archived
Status:
Impact:
UI / General GUI
#PageBug DescriptionStatusAnalysis / Suggested Fix
3 GUI Dropdowns - include up and down keystroke shortcut FIXED UI Using Radix UI Select/Combobox primitives which natively support keyboard navigation (arrow keys, type-ahead). Verified in shadcn/ui components.
4 Logo Put the name → "Alpaca" FIXED UI Header shows "Alpaca" text. Sidebar shows "Alpaca" with AnimatedLogo component. Confirmed via Playwright screenshot.
5 Quote Fulfilled quote step - summary aligned with table NOT FIXED UI Layout uses grid-cols-[1fr,280px] with right column having mt-6 causing slight misalignment.
Remove the mt-6 from the right column in QuoteDetail.tsx:960 or use items-start on the grid for proper top-alignment.
26 Forms Mandatory fields "*" should be in red, currently gray NOT FIXED UI Red asterisks (text-red-500) exist in CustomerForm.tsx, CustomerSelector.tsx, and LicenseDetail.tsx. But the QuoteWizard form fields do NOT have red asterisks.
Add <span className="text-red-500">*</span> to all required fields in QuoteWizard.tsx (customer, dates, etc.).
29 Sidebar Include a collapse/expand like in the portal FIXED UI Collapse button exists (title="Collapse sidebar") in Sidebar.tsx. State persisted in localStorage. Collapsed width is w-14, expanded is w-56.
40 GUI Skin all the confirmation modals NOT FIXED Manual Modals use shadcn/ui AlertDialog/Dialog components with consistent styling. Visual review needed to confirm they match the design system.
49 Tables Column filtering - checkmark with no label when right-clicking FIXED UI Column toggle uses ContextMenuCheckboxItem with {col.label} text. Each item shows the column name + checkmark. Verified in data-grid.tsx:256-268.
50 Tables When adding columns, the table header is broken NOT FIXED Manual Column toggle logic recalculates widths. Needs manual test with real data to verify header alignment after toggling columns on/off.
Dashboard
#PageBug DescriptionStatusAnalysis / Suggested Fix
27 Dashboard Make recent customers, quotes, invoices entries clickable FIXED UI Quote IDs link to /quotes/:id, Invoice IDs link to /invoices?id=.... Confirmed in Dashboard.tsx:171 and :222.
46 Dashboard Remove Customer search / end customer from top bar FIXED UI Top bar only contains "Alpaca", search (Cmd+K), and user menu. No customer/end-customer selectors in the header.
Customers
#PageBug DescriptionStatusAnalysis / Suggested Fix
7 Customers Impersonate customer action → "Page cannot be found" NOT FIXED Manual Impersonate logic implemented in CustomerDetail.tsx:649-672. Opens returned URL rewritten to dev.hex-rays.io or my.hex-rays.com.
Needs manual test with real backend — "page not found" may come from the target portal. Verify the returned URL is valid.
8 Cust > Licenses Actions should include: Revoke, Reissue, Resend NOT FIXED Manual Could not test with empty data. License actions exist in LicenseDetail.tsx and Licenses.tsx. Needs verification with real customer data.
9 Cust > Licenses Include advanced filters like in Retool NOT FIXED UI
The customer license tab within CustomerDetail does not have its own filter bar. Add status, type, and search filters to the license sub-tab.
10 Cust > Quotes Include advanced filtering like in Retool NOT FIXED UI
The customer quotes tab within CustomerDetail does not have filters. Add status, date range, and search filters.
11 Cust > Invoices Include advanced filtering like in Retool NOT FIXED UI
Same — add filters to the invoices sub-tab in CustomerDetail.tsx.
12 Cust > Licenses Clicking license in customer tab redirects to license view but doesn't persist customer NOT FIXED UI License detail page has a "View Customer" icon button but no breadcrumb trail showing which customer you came from.
Add a breadcrumb or back-link. Consider ?from=customer&customer_id=X query params.
30 Cust > KYC Include capability to upload documents like in Retool FIXED UI KYC file upload implemented in CustomerDetail.tsx:576-607. Uses presigned URL, then uploads. Input type="file" is present in the KYC tab.
31 Customers HubSpot opens but doesn't load - infinite loop NOT FIXED Backend HubSpot integration exists. The infinite loop is likely a HubSpot-side issue or wrong URL construction.
Verify the HubSpot URL format. Check if customer's HubSpot ID is correctly stored. May need HubSpot API v3 contact URL format.
37 Cust > KYC KYC file upload not working NOT FIXED Backend Frontend upload logic exists and looks correct. Issue is likely backend.
Test the upload endpoint directly. Check CORS headers, file size limits, and S3/storage bucket permissions.
44 Customers Action dropdown not working in customer list NOT FIXED Manual Could not verify with empty data. The ACTIONS column exists. Needs manual test with populated customer data.
45 Customers Include placeholder text on buttons (Impersonate icon not clear) NOT FIXED UI Icon-only buttons have title= attributes but no visible text labels.
Add visible text labels next to icon buttons. At minimum, use a Tooltip component instead of native title.
51 Customers Include capability to add comments on customers NOT FIXED UI There is an "Internal Notes" field but no threaded comments system or dedicated "Comments" tab.
If requirement is a full comments system, this needs a new backend endpoint. If "Internal Notes" suffices, consider renaming to "Comments".
Quotes List & Detail
#PageBug DescriptionStatusAnalysis / Suggested Fix
32 Quotes Rejecting a quote → reject button still appears, can re-reject FIXED UI QuoteDetail.tsx:806-818 explicitly excludes declined status from the reject button visibility. Button is hidden after rejection.
35 Quotes Fulfilled step — "Licenses table" is weirdly positioned NOT FIXED UI Licenses table renders in the left column under line items. The right column has a mt-6 offset.
Test with a real fulfilled quote to verify positioning. Consider removing mt-6 or using CSS grid alignment.
47 Lists Move customer / end customer selection into the search section FIXED UI Customer and End Customer selectors are in the filter bar of both Quotes.tsx:635-649 and Licenses.tsx:2107-2124.
52 Quotes Can't unselect items in the status dropdown FIXED UI Status filter is a multi-select checkbox dropdown. Each status can be toggled individually via toggleStatus(). "Clear" button resets all.
53 Quotes Rename "More" to "Add filters"/"Hide filters" FIXED UI Button text reads "Add filters" (confirmed via Playwright). Clear button positioned next to filter controls.
Quote Maker
#PageBug DescriptionStatusAnalysis / Suggested Fix
15 All types Wrong roundings / unit amounts NOT FIXED UI convertPercentageToFixed() uses Math.round(... * 100) / 100 which has floating-point precision issues.
Use Number((value).toFixed(2)) or a decimal library for money calculations. Audit backend for server-side rounding consistency.
16 All types Wrong rounding in CSV exports FIXED UI csv.ts:16 uses toFixed(2) for amounts stored in cents, which correctly formats to 2 decimal places.
17 Renewal Renewal quote reproduction steps (unspecified) NOT FIXED Manual QA sheet did not include specific reproduction steps. Needs manual testing of the renewal flow end-to-end.
18 Renewal/Upgrade Display pubhash when selecting licenses to avoid mistakes FIXED UI Pubhash column visible in both license selection tables. Search also filters by pubhash.
19 Renewal/Upgrade Collapse the license table when adding to cart (cart is too low on page) FIXED UI "Load into Cart" sets wizardStep(2) which hides the Step 1 license selector. Table disappears and cart shows at top.
20 Renewal Selecting existing licenses → nothing added in cart NOT FIXED Backend Frontend calls apiClient.getCartFromLicenses(). If backend returns empty cart items, nothing appears.
Check backend POST /cart/licenses/:operation endpoint. Verify it returns populated line_items.
21 New quote Remove TSV NOT FIXED UI TSV Import/Export drawer (TsvImportDrawer.tsx) still exists in the codebase. Not visible on initial page but still importable.
Delete TsvImportDrawer.tsx, remove imports from QuoteWizard.tsx, and delete src/lib/tsv.ts.
22 Quote detail Do we need the debug button? FIXED UI No visible Debug button. DebugDrawer only triggered via Cmd+D (hidden from normal users).
23 Quote maker What is TSV for in the cart? NOT FIXED UI TSV import/export exists for bulk cart data entry. See item #21 about removing it.
24 Quote maker Convert quote modal showing "auto assign server" even without add-ons selected FIXED UI ConvertDialog.tsx is a dead component — never imported. The actual convert dialog uses a simple confirmation with no auto-assign checkbox.
25 Duplicate quote Duplicating a quote → CTA says "Update Quote" instead of "Create Quote" NOT FIXED UI QuoteWizard.tsx:3845: isEditMode ? 'Update Quote' : 'Create Quote'. Duplicated quotes open in edit mode.
Add isDuplicate flag. Navigate to /quotes/new?duplicate_from=:id instead of /quotes/:newId/edit.
36 Migration Kill the migration tab — it's legacy FIXED UI No Migration tab found anywhere in the codebase. Already removed.
38 Renewal Subscription license added to cart but plan dropdown and license type aren't persisted NOT FIXED Backend Frontend relies on backend response for plan/type data.
Verify backend returns plan_id and license_type in the cart response for subscription licenses.
39 Renewal Selecting licenses and adding to cart → internal server error NOT FIXED Backend
500 error from POST /cart/licenses/:operation. Check server logs. Common causes: invalid pubhash, missing product mappings, expired subscriptions.
41 Convert Convert quote triggers a 500 error NOT FIXED Backend
500 from POST /quotes/:id/convert. Check Chargebee integration — subscription creation failure, missing payment method, or invalid item config.
42 New quote Preview license generates a 500 error NOT FIXED Backend
Server error on the preview/estimate endpoint. Check backend logs. Likely Chargebee estimate API failure.
43 Quote maker Customer and end customer search fields are confusing NOT FIXED UI Two separate search fields. End Customer only appears when isReseller is true. No indication that min 2 chars required.
Add placeholder text like "Type at least 2 characters..." and label fields: "Billing Customer (Reseller)" / "End Customer (License Owner)".
54 New quote Can't select products, dropdown is empty NOT FIXED Backend
Product dropdown data comes from API. Check GET /products endpoint. Verify environment has products configured.
55 Quote maker PO number is hidden top-right, should be under plan selections with toggle NOT FIXED UI PO Number is a plain text input in the metadata toolbar, always visible.
Move below plan selections. Add a toggle: "Include a PO Number" that expands to show the input.
56 Quote maker Use toggles for non-mandatory items: "Include notes" NOT FIXED UI
Add toggle switches for optional fields: "Include a PO Number", "Include Notes", "Include Internal Notes". Default to collapsed.
57 Duplicate Duplicate quote triggers a 500 error code NOT FIXED Backend
500 from duplicate API endpoint. Check backend logs. May relate to deep-copying cart items with invalid references.
Licenses
#PageBug DescriptionStatusAnalysis / Suggested Fix
33 License detail Action icons on top-right unclear, add labels next to icons NOT FIXED UI LicenseDetail.tsx:629-638 has two icon-only buttons ("View Customer", "View Quote") with only title=.
Add visible text: <Button><i></i> View Customer</Button>
34 Bulk edit Placeholders/labels make no sense ("Leave empty keep current"). Tag selector height mismatch. NOT FIXED UI Bulk edit form in Licenses.tsx:3529-3605.
1. Change placeholder to: "Leave empty to keep current value"
2. Add consistent h-9 to all form elements
3. Wrap fields in a proper form grid with labels
48 Bulk edit Fix the form — "looks like Claude did it" NOT FIXED UI Same as #34. Needs design polish: consistent spacing, proper labels, aligned heights.
Redesign bulk edit Sheet. Use CustomerForm.tsx form patterns for consistency.
New Issues Found by Automated Testing (March 18, 2026)

Discovered during Playwright section-by-section testing and visual review. Not in the original QA sheet.

#PageBug DescriptionStatusAnalysis / Suggested Fix
N1 Admin All Admin pages return 401 errors — User Profiles, Events show "Error loading..." NOT FIXED Backend X-Test-As header bypass works for /api/retool/* but Admin endpoints (/api/admin/*) require different auth.
Check backend admin routes accept same auth mechanism. Verify /api/admin/profiles, /api/admin/events middleware.
N2 All lists Quotes, Licenses, Invoices require customer selection first — "No Customer Selected" NOT FIXED UI Unlike Retool which shows all records by default, these views force customer pick first. Major UX regression.
Show all records by default (paginated). Customer filter should narrow down results, not be a prerequisite.
N3 Quote Maker "Quote Type *" asterisk is gray, not red — only Email in Customer Form has red asterisk NOT FIXED UI
Apply text-red-500 to all required field asterisks consistently: QuoteWizard.tsx, CustomerForm.tsx (all required fields).
N4 Filter bars Inconsistent input heights across filter bars — 4 different heights (24px, 28px, 32px, 40px) NOT FIXED UI
Standardize all filter bar elements to h-9 / 36px. Apply consistent text-sm sizing.
N5 Quote Maker Customer search dropdown does not appear when typing — no dropdown shown NOT FIXED Backend Customer search input exists but autocomplete doesn't fire. Likely because customer search API returns 401.
Related to general 401 auth issue. Verify /api/retool/customers/paged is accessible.
N6 Invoices Inconsistent empty state messaging — Invoices says "Search or Select Customer" vs others say "No Customer Selected" NOT FIXED UI
Standardize empty state message. Use same component and text pattern across all list views.
N7 Quote Maker Notes and Internal Notes textareas always visible — take up significant space even when empty NOT FIXED UI
Add collapsible toggles: "Include customer notes" / "Include internal notes". Default to collapsed.
N8 Quote Maker "License Manager Email" field always visible — unclear purpose for most users NOT FIXED UI
Add toggle: "Set license manager email" or move it into the convert dialog where it's contextually relevant.
N9 Customer Form Customer creation form has pre-filled placeholder values that look like real data NOT FIXED UI Form shows "John", "Doe", "Acme Inc.", "US", "EU123456789". Looks like real data, confuses users.
Use actual placeholder text instead of pre-populated values: placeholder="Enter first name" instead of value="John".
N10 Dashboard Dashboard "Recent Quotes", "Recent Invoices", "Expiring Soon" are empty with no call-to-action NOT FIXED UI
Add CTA link in empty state: "Create your first quote" → /quotes/new, "View all invoices" → /invoices.
N11 Sidebar Collapsed sidebar icons have no tooltips — icon-only navigation unclear NOT FIXED UI
Add title attributes or Tooltip component on each sidebar nav icon when collapsed.
N12 Customers Customer list shows "No customers found" with "US" pre-filled — different from Retool NOT FIXED UI
Default Country filter to empty/All. Load all customers on page load without requiring filters.
Deep QA Testing — Round 2 (March 18, 2026)

Comprehensive section-by-section Playwright testing with visual screenshot review. Focused on cross-page consistency, workflow issues, and data persistence.

#PageBug DescriptionStatusAnalysis / Suggested Fix
D1 Coupons Coupons page shows "Error loading coupons - Request failed with status code 401" with Retry button NOT FIXED Backend Screenshot
Page displays red "Error loading coupons" text with 401 status. The Coupons API endpoint requires auth that isn't provided.
Ensure the coupons API endpoint accepts the same auth mechanism as other /api/retool/* endpoints. Check if it uses a different route prefix.
D2 Events Events page shows "Error loading events - Request failed with status code 401" with Retry button NOT FIXED Backend Screenshot
Same 401 pattern as Coupons. Admin routes (/api/admin/*) are not accepting auth tokens.
Backend admin middleware needs to accept the same JWT/session auth as retool routes.
D3 User Profiles User Profiles page renders completely blank — no content, no error message, just empty white page NOT FIXED Backend Unlike Events/Coupons which show error messages, User Profiles silently fails with no feedback. Worse UX than showing an error.
Add error handling with a visible error state. If the API fails, show "Error loading user profiles" instead of a blank page.
D4 Sidebar Collapsed sidebar nav icons have NO tooltips — all 6 navigation items show blank text on hover NOT FIXED UI Screenshot
When sidebar is collapsed, tested all nav links — none have title, aria-label, or tooltip. Users cannot tell what each icon means.
Add title attribute or a Radix Tooltip to each nav link when sidebar is collapsed: "Dashboard", "Customers", "Licenses", "Quotes", "Invoices", "Admin".
D5 Customer Form Only "Email" has a red asterisk — no other required fields (Company, Country) are marked as required NOT FIXED UI Screenshot
Tested: only 1 red asterisk found (on Email label, rgb(239,68,68)). Company, Country, Category are all visually optional even though they may be required by the API.
Add <span className="text-red-500">*</span> to all required field labels in CustomerForm.tsx.
D6 Customer Form Placeholder values masquerade as real data: "John", "Doe", "Acme Inc.", "US", "EU123456789", "0" NOT FIXED UI Screenshot
Deep test confirmed: First Name placeholder="John", Last Name placeholder="Doe", Company placeholder="Acme Inc.", Country placeholder="US", VAT placeholder="EU123456789". These are placeholder attributes, not values, but they render as gray text inside the inputs — making it look like the form is pre-filled with "John Doe from Acme Inc."
Change placeholders to instructions: "Enter first name", "Enter last name", "Enter company name", "Select country", "e.g. EU123456789".
D7 All lists Filter bar heights inconsistent across all pages: Customers [32px, 28px], Quotes [32px, 28px, 16px], Licenses [32px, 28px, 16px] NOT FIXED UI Screenshot (Quotes) | Screenshot (Customers)
Measured every filter element on each page. Three distinct height classes used inconsistently. Quotes and Licenses pages have 16px elements (likely hidden selects).
Standardize all filter bar elements to h-9 (36px). Apply to Input, Select, Button, CustomerSelector uniformly across Customers.tsx, Quotes.tsx, Licenses.tsx, Invoices.tsx.
D8 Invoices Invoices empty state says "Search or Select Customer" while Quotes/Licenses say "No Customer Selected" — 3 different patterns NOT FIXED UI Screenshot (Invoices) | Screenshot (Licenses)
Tested all 4 list pages:
• Customers: "No customers found"
• Quotes: "No Customer Selected / Select a customer to view their quotes"
• Licenses: "No Customer Selected / Select a customer to view their licenses"
• Invoices: "Search or Select Customer / Search for an invoice ID or select a customer / Use the customer search above to get started"
Use a single shared EmptyState component for all list pages. If customer selection is required, use: "Select a customer to view [resource]". Better yet: show all records by default (see N2).
D9 Coupons Coupons filter bar has different design pattern: Search input spans full width, "Apply" button instead of auto-filter NOT FIXED UI Screenshot
Coupons page has a wide Search input + Status dropdown + Apply + Clear buttons. Other list pages use auto-filtering without an Apply button and have narrower inputs.
Align Coupons filter bar with other pages: use auto-filtering on change, consistent input widths, remove the "Apply" button, add a filter label above each input.
D10 Quote Maker Clicking quote type (New/Renewal/Upsell) does not navigate to step 2 — page stays on selector NOT FIXED Backend Screenshot
Clicking "New Quote", "Renewal", or "Upsell" does not advance the wizard. The page remains on the type selector. Likely blocked by API auth — the wizard needs to fetch products/plans before showing step 2.
The wizard should show a loading state and graceful error if the products API fails, not silently stay on step 1. Add error toast: "Could not load products. Please check your connection."
D11 Reports Reports page loads with all €0 values and "No data for selected period" — no indication of auth issue NOT FIXED UI Screenshot
All 8 summary cards show €0. The sub-table shows "No data for selected period". Unlike Coupons/Events which show a clear error, Reports silently returns zeros, making it unclear if the data is genuinely empty or if auth failed.
Distinguish between "no data" and "API error". Show a warning banner when API returns 401 or error. "Could not load report data — check your permissions."
D12 Events (blank) Events page (/events) renders completely blank — different from Admin Events which shows error NOT FIXED UI Screenshot
Navigating to /events (vs /admin/events) renders a completely blank white page with no sidebar, no content, no error. This is likely a routing issue — the /events route may not exist or is an unhandled catch-all.
Add a 404/redirect for unknown routes. Or ensure /events redirects to /admin/events.

Summary & Recommendations

  1. Backend auth is the #1 blocker — 8+ API endpoints return 401. Coupons, Events, Notifications all show "Error loading" with 401. User Profiles renders completely blank. Reports silently return €0 instead of showing error. Quote wizard silently fails to advance past type selector.
  2. Backend 500 errors (from QA sheet) — Convert quote (#41), Preview license (#42), Duplicate quote (#57), Add licenses to cart (#39). Need backend log investigation once auth is resolved.
  3. Lists require customer selection (N2, N12, D8) — Major UX regression vs Retool. Quotes, Licenses, Invoices show empty state requiring customer selection. Customer list defaults to "US" country filter. 3 different empty state message patterns across 4 pages.
  4. Silent failures are worse than visible errors (D3, D10, D11, D12) — User Profiles, Reports, Quote Wizard, and /events all fail silently with blank pages or €0 values instead of showing error messages. Users can't tell if data is empty or if something is broken.
  5. UI consistency (D4, D5, D6, D7, D9) — Filter bar heights vary (16-32px), only Email has red asterisk, placeholder values look like real data in Customer Form, collapsed sidebar has no tooltips, Coupons page has different filter pattern from all other pages.
  6. Quote maker UX (N7, N8, #55, #56) — PO Number, Notes, Internal Notes, License Manager Email always visible. Use toggles to reduce clutter.
  7. 16 items confirmed fixed from original QA — sidebar collapse, logo, dashboard cleanup, status filters, pubhash display, column labels, reject button logic, CSV rounding, "Add filters" rename.
Archived (0)
#PageBug DescriptionStatusAnalysis / Suggested Fix

Generated by Claude Code — Playwright + static analysis — March 18, 2026