A floating chat widget that can query your database in real time is one of those features that looks deceptively simple until you actually build it. This post walks through the full implementation in CitizenApp — what works, what blew up, and the patterns I'd use again.
What It Does
The widget lives in the bottom-right corner of the app. Clicking it opens a 420×560px panel. The user types a natural language question. A single API call goes to the backend, which:
Asks Claude Haiku to either answer using aggregate statistics, or generate a safe SELECT query
If Claude generated SQL, the backend validates it (SELECT only, single table, no PII columns), injects tenant_id, enforces LIMIT 100, and executes it











