Note: The test examples below use the demo SAP O2C dataset that ships with the project. The O2C Insight Engine is dataset-agnostic — these examples validate the query pipeline using realistic enterprise data. When testing with your own uploaded dataset, substitute the entity names, document IDs, and expected results accordingly.
Run the server first: npm start (compiles TypeScript via NestJS and starts main.ts)
Open the UI at: http://localhost:3000
Or test the API directly with any HTTP client (Postman, curl, etc.)
Test files are written in TypeScript (e.g., *.spec.ts).
Each test shows:
- Query — type this into the chat box (uses the demo SAP O2C dataset)
- Expected — what you should see in the response
These should fail immediately before any LLM call.
Query: (submit with nothing typed)
Expected:
Error: Query cannot be empty.
Error type: VALIDATION_ERROR
Query: (paste 501+ characters of any text)
Expected:
Error: Query exceeds max length of 500 characters.
Error type: VALIDATION_ERROR
These are blocked by the domain + intent filter before LLM is called.
Query:
xyzzy frobble wumpus
Expected:
success: false
Error: Could not understand the query. Please rephrase using a clear business action like 'trace', 'show', or 'find'.
Error type: VALIDATION_ERROR
Query:
What is the capital of France?
Expected:
success: true
queryType: RAG
reason: RAG_RESPONSE
nlAnswer: "No specific context found for this topic in the O2C knowledge base."
confidence: 1.00
No graph shown
Note: "What is..." matches the RAG classifier before the domain guardrail fires. This is intentional — RAG queries bypass SQL but still degrade gracefully on KB miss.
These return concept explanations from the auto-generated knowledge base. No SQL runs, no graph shown.
Query:
What is order to cash?
Expected:
queryType: RAG
reason: RAG_RESPONSE
confidence: 1.00
explanation:
Intent: concept explanation
Strategy: knowledge retrieval
nlAnswer: explains the O2C flow (Sales Order → Delivery → Billing → Journal → Payment)
No graph, rowCount: 0
Query:
What is a sales order?
Expected:
queryType: RAG
nlAnswer: definition of a Sales Order in SAP
confidence: 1.00
Query:
Describe the billing process
Expected:
queryType: RAG
nlAnswer: explains Billing Document, cancellations, journal entry link
confidence: 1.00
Query:
Define journal entry
Expected:
queryType: RAG
nlAnswer: explains AR posting, clearing document
confidence: 1.00
Query:
Explain payment clearing
Expected:
queryType: RAG
nlAnswer: explains how payments are matched via clearingAccountingDocument
confidence: 1.00
These run SQL AND inject knowledge base context into the NL answer.
Query:
Why is the billing document not cleared?
Expected:
queryType: HYBRID
success: true
rowCount > 0
explanation.intent: gap-analysis
confidence < 1.00 (SQL + KB, some uncertainty)
nlAnswer: answer enriched with explanation of clearing mechanism
Graph: shows billing + journal nodes
Query:
Why are some sales orders not billed?
Expected:
queryType: HYBRID
SQL executes to find delivered-but-not-billed orders
nlAnswer: factual answer with optional KB context about billing
Graph: shows Sales Order + Delivery nodes with no Billing link
Query:
What is the reason for billing document cancellations?
Expected:
queryType: HYBRID
nlAnswer: explains cancellation with actual data from dataset
confidence < 1.00
Query:
Trace full flow for billing document 90504204
Expected:
success: true
queryType: SQL
rowCount > 0
explanation:
Intent: trace
Strategy: multi-hop join across O2C flow
Graph: shows Sales Order → Delivery → Billing → Journal Entry → Payment
confidence: 1.00
Query:
Trace full flow for billing document 90504248
Expected:
Same structure as above with different document IDs in the graph
Query:
Show full flow for sales order 4
Expected:
SQL traces from sales_order_headers forward through delivery → billing → journal → payment
Graph: full chain if all stages exist
Query:
Top 5 customers by total billing amount
Expected:
reason: AGGREGATION
rowCount: up to 5
confidence: 0.90 (aggregation reduces by -0.1)
Graph: shows Customer nodes with billing count/amount labels
nlAnswer: names the top customers and their amounts
Query:
Count all billing documents
Expected:
reason: AGGREGATION
rowCount: 1
confidence: 0.90
nlAnswer: "There are X billing documents in the dataset."
Query:
Which products have the most billing documents?
Expected:
reason: AGGREGATION
rowCount > 0
Graph: Product nodes with billing count
Query:
How many delivery documents are there?
Expected:
reason: AGGREGATION
rowCount: 1
confidence: 0.90
Query:
Find sales orders delivered but not billed
Expected:
success: true
rowCount > 0
explanation:
Intent: gap-analysis
Strategy: gap detection using LEFT JOIN with NULL check
Graph: Sales Order + Delivery nodes (no Billing edges)
Query:
Show all cancelled billing documents
Expected:
success: true
rowCount > 0
Graph: BillingDocument nodes marked as cancelled
Query:
Show billing documents without a journal entry
Expected:
success: true
rowCount > 0 (if any exist in dataset)
Graph: BillingDocument nodes with no JournalEntry link
Query:
Show all orders for customer 320000083
Expected:
success: true
rowCount > 0
Graph: Customer → multiple Sales Order nodes
Query:
Show all orders for customer 99999999
Expected:
success: true
reason: INVALID_ID
message: "No records found for the given query."
rowCount: 0
No graph
Query:
Trace full flow for billing document 99999999
Expected:
success: true
reason: INVALID_ID
message: "No records found for the given query."
rowCount: 0
suggestions: [ list of 5 valid billing document IDs ]
No graph — UI shows "Document not found in the dataset"
Click one of the suggestion chips — it auto-fills a valid trace query.
Test the "Show SQL (for developers)" checkbox in the chat panel.
10.1 SQL hidden (default)
Steps:
- Leave the checkbox unchecked
- Send:
List all sales orders
Expected:
No "Generated SQL (Debug View)" card appears
Steps:
- Check the "Show SQL (for developers)" checkbox
- Send:
List all sales orders
Expected:
"Generated SQL (Debug View)" card appears below the answer
Shows the raw SELECT statement used
Steps:
- Check the SQL toggle
- Send:
Trace full flow for billing document 90504204
Expected SQL shape:
SELECT DISTINCT
soh.salesOrder, soh.soldToParty, ...
FROM billing_document_headers bdh
JOIN billing_document_items bdi ...
JOIN outbound_delivery_items odi ...
JOIN outbound_delivery_headers odh ...
JOIN sales_order_headers soh ...
LEFT JOIN journal_entry_items_accounts_receivable je ...
LEFT JOIN payments_accounts_receivable pay ...
WHERE bdh.billingDocument = '90504204'
LIMIT 100Every SQL and HYBRID query returns an explanation card "How this was answered".
Query: Trace full flow for billing document 90504204
Expected explanation card:
Intent: trace
Entities: billing, delivery (or similar — based on query keywords)
Strategy: multi-hop join across O2C flow
Query: Top 5 customers by total billing amount
Expected explanation card:
Intent: aggregation
Entities: customer, billing
Strategy: aggregation query with GROUP BY
Query: Find sales orders delivered but not billed
Expected explanation card:
Intent: gap-analysis
Entities: sales order, delivery, billing
Strategy: gap detection using LEFT JOIN with NULL check
Query: List all customers
Expected explanation card:
Intent: list
Entities: customer
Strategy: lookup with filters (or multi-table join query)
Query: Trace full flow for billing document 90504204
Expected:
Confidence: 1.00
(No fallback applied, rows found, not an aggregation)
Query: Count all billing documents
Expected:
Confidence: 0.90
(aggregation deducts -0.10)
Query: What is order to cash?
Expected:
Confidence: 1.00
(KB lookup has no SQL uncertainty)
Query: Trace full flow for billing document 99999999
Expected:
Confidence: 0.60 or lower
(rowCount = 0 deducts -0.40)
When a query produces no results, a human-readable message appears.
Query: Trace full flow for billing document 99999999
Expected:
message: "No records found for the given query."
reason: INVALID_ID
suggestions: [...valid IDs...]
Query: (a valid document ID that exists but has an incomplete chain)
Expected:
reason: NO_FLOW
message: "No records found for the given query."
Graph empty state: "No connected flow found"
Steps:
- Run:
Trace full flow for billing document 90504204 - Click any node in the graph
Expected:
Node tooltip appears showing:
- Entity type (e.g. BillingDocument)
- All properties (billingDocument, totalNetAmount, etc.)
- Connections count
Tooltip is draggable
Steps:
- Run any trace query
- Click "Hide Edge Labels" button (top-left of graph)
Expected:
Edge labels (FULFILLED_BY, BILLED_AS, etc.) disappear
Button changes to "Show Edge Labels"
Click again to restore labels
Steps:
- Run a trace query with a large graph
- Zoom in manually (scroll)
- Click "Fit View"
Expected:
Graph recenters and fits all nodes in the viewport
When a full flow trace returns 0 rows, the system silently retries with LEFT JOINs.
Query:
Show all sales orders with their deliveries
Expected (if fallback triggered):
fallbackApplied: true (visible in API response)
confidence: 0.80 (fallback deducts -0.20)
summary: "Partial flow recovered using relaxed joins"
Graph: shows partial connections (e.g. Order → Delivery without Billing)
| Query Pattern | queryType | SQL runs | KB used | Graph shown |
|---|---|---|---|---|
| "What is..." / "Define..." | RAG | No | Yes | No |
| "Why..." / "Reason..." | HYBRID | Yes | Yes | Yes |
| "Show / Find / List / Trace..." | SQL | Yes | No | Yes |
| Gibberish / no intent | Blocked | No | No | No |
| Condition | Score change |
|---|---|
| Base | 1.00 |
| RAG query | Always 1.00 |
| Aggregation (GROUP BY / COUNT) | -0.10 |
| Fallback JOIN applied | -0.20 |
| Zero rows returned | -0.40 |
| Minimum possible | 0.00 |