Files
hermes-config/skills/self-hosting/shop-pro-quote/references/v2-pitfalls.md
T
2026-07-12 10:17:17 -04:00

2.7 KiB

SPQ v2 Development Pitfalls

Common recurring issues when working on the React/Vite frontend.

PocketBase Collection Naming

PocketBase collections use camelCase by convention (repairOrders, not repair_orders). Always verify the actual name:

curl -s http://127.0.0.1:8091/api/collections/NAME/records?perPage=1 \
  -H "Authorization: TOKEN"
# 404 = collection doesn't exist with that name
# 400 with "Something went wrong" = collection exists but query is broken (wrong field/sort)
# 200 = correct name, query works

sort: '-created' Returns 400

Most SPQ PocketBase collections were created without system created/updated fields. Queries using sort: '-created' fail with HTTP 400.

Fix: Use sort: '-id' everywhere unless you've confirmed the created field exists on that specific collection. PB IDs are time-sortable (they're ordered by creation time).

Affected collections: quotes, repairOrders, any collection created via API without explicit schema.

React Input Focus Loss with Zustand

When a React component with input fields is defined as a nested function inside its parent component, every zustand store update causes a full parent re-render. This creates a new function identity for the child component, React sees it as a different component type, and destroys/recreates the DOM — killing input focus.

Fix: Extract the component to a file-level function, wrap in memo, and pass all state/actions as explicit props:

// WRONG — loses focus on every keystroke
function Parent() {
  const update = useStore(s => s.update);
  const Child = ({ item }) => (
    <input value={item.name} onChange={e => update({ name: e.target.value })} />
  );
}

// RIGHT — focus stays
interface ChildProps { item: Item; onUpdate: (u: Partial<Item>) => void; }
const Child = memo(function Child({ item, onUpdate }: ChildProps) {
  return <input value={item.name} onChange={e => onUpdate({ name: e.target.value })} />;
});

AI Features Return No Results

The 3 AI functions in src/lib/ai.ts (aiWriteExplanation, getPriorityAnalysis, aiSuggestServices) call /deepseek/v1/chat/completions. This path must be proxied to https://api.deepseek.com/ with the API key.

The proxy script template at references/local-testing.md includes this. Key verification:

curl -s -X POST http://localhost:4173/deepseek/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{"model":"deepseek-v4-flash","messages":[{"role":"user","content":"hi"}],"temperature":0,"thinking":{"type":"disabled"},"max_tokens":50}'
# Should return {"choices":[{"message":{"content":"Hello!"}}]}

API key is extracted from /etc/nginx/sites-enabled/shopproquote and stored in /tmp/deepseek_key.txt.