A lightweight React frontend for an HCI-powered, interactive ambiguity-aware NL2SQL workflow.
This project focuses only on the frontend GUI. The final NL2SQL backend method is still undecided, so the current implementation uses deterministic mock data and a stable frontend service contract. The UI is designed so a future backend can replace the mock service without rewriting the main interaction flow.
The first version supports the core user flow:
- Select a database and SQL dialect.
- Enter a natural-language query.
- Answer one clarification question at a time.
- Continue until the query is ready.
- Show the final read-only SQL.
- Display the mock query result table.
The interface uses a focused workspace layout: the main task area shows the active query step, while the right context panel keeps schema, clarification history, and rewritten-query details available but secondary.
- React
- Vite
- TypeScript
- Local shadcn-style UI components under
src/components/ui - Lucide React icons
- Vitest and React Testing Library
- Oxlint
Note: the shadcn CLI could not fully initialize in this environment because registry access was blocked. The project still keeps a components.json file and local components/ui source files so the code follows the intended component boundary.
src/
├── App.tsx
├── app/
│ └── query-reducer.ts
├── components/
│ └── ui/
├── lib/
│ └── utils.ts
├── mocks/
│ └── catalog.ts
├── services/
│ └── nl2sql/
│ ├── ambisql-adapter.ts
│ ├── mock-service.ts
│ └── types.ts
└── test/
└── setup.ts
Key boundaries:
query-reducer.tsowns the workflow state transitions.services/nl2sql/types.tsdefines the frontend domain contract.mock-service.tsimplements the current deterministic demo flow.ambisql-adapter.tsmaps AmbiSQL-style fields into frontend domain types.- UI components do not directly depend on AmbiSQL response fields.
The frontend depends on this stable service interface:
interface Nl2SqlService {
listDatabases(): Promise<DatabaseOption[]>
analyze(input: AnalyzeInput): Promise<TurnResponse>
resolve(input: ResolveInput): Promise<TurnResponse>
executeReadonly(input: ExecuteInput): Promise<QueryExecution>
}The current mock implementation includes:
- A multi-turn clarification path.
- A direct ready path for simple unambiguous queries.
- A read-only violation path for unsafe SQL execution.
Install dependencies:
npm installStart the local development server:
npm run devBuild for production:
npm run buildRun tests:
npm testRun lint:
npm run lintThe current test suite covers:
- reducer workflow transitions;
- clarification answer serialization;
- AmbiSQL flag and field mapping;
- structured service error mapping;
- deterministic mock multi-turn flow;
- read-only execution blocking;
- the main UI path from query submission to final result.
The backend is not fixed yet. When a real backend is ready, add an HTTP service implementation behind the existing Nl2SqlService interface instead of changing UI components directly.
For AmbiSQL-style integration, keep all field-name conversion inside ambisql-adapter.ts. The UI should continue consuming only frontend domain types such as TurnResponse, ClarificationQuestion, and QueryExecution.
Known backend assumptions for future integration:
- Analyze starts the session.
- Resolve submits one answer at a time.
- The frontend expects one active clarification question per turn.
- SQL execution must be enforced as read-only by the backend.
- The frontend only displays read-only execution results; it does not override backend safety decisions.
The first version intentionally does not include:
- user accounts or permissions;
- saved query history;
- custom database connections;
- SQL editing;
- multi-question batch clarification UI;
- charts or dashboards;
- HCI experiment instrumentation;
- a finalized HTTP backend service.
