Professional
Kaizen AI | Business intelligence
Companies licensing the ERP query their own data by typing the question. An AST rewriter injects three permission filters before the SQL runs.
- AI
- Security
- Organisation
- Kaizen Apps CR
- Role
- Development
- Period
- 2025-09 — 2026-07
Stack
- Next.js
- TypeScript
- Vercel AI SDK
- Upstash Vector
- Cohere rerank
- Drizzle ORM
- MySQL
- Google Cloud Run
Context
A tool Kaizen puts in the hands of the companies that license its ERP. They query their own data by writing the question in plain language.
The version in production is the fourth. Each rebuild moved into code a decision the previous one had left to the model.
Problem
Every client question was handled by someone on the support team. As demand for help grows, that team is overwhelmed and the client waits.
A large share of those questions repeat: how to do something, what a human-resources or occupational-health concept means, what labour law says about it. The tool exists so a client resolves those on their own, and the team handles what genuinely needs a person.
Technical decisions
With several client companies on the same installation, a model querying production data raises a question a prompt cannot answer: who may read what. If access control depended on the model following instructions, rephrasing the question would be enough to get around it.
So the question is translated to SQL, and the server rewrites that query before executing it. A rewriter over the syntax tree injects three filters: client database, session role and action scope.
A query asking for another company’s data does not fail a validation: it runs already scoped and returns only what is permitted.
Architecture
The model does not talk to the database. It proposes SQL, and that text passes through the rewriter before it executes.
Every query is scoped to the database of the client asking. A user at one company cannot reach another company's data, even if the generated SQL asked for it explicitly.
Developer, administrator and user see different sets. The filter is injected from the authenticated role, not from whatever the model proposes.
The specific action narrows the result once more. What the model returns is an intent; the effective scope is set by the server.
The SQL that ran is recorded, together with the role and the user. The audit trail covers the final query, not the one the model proposed.
The rewriter is the only point on the path that sets how much comes back, so permission tests are written against it rather than against the conversation.
Result
The tool is in production for the companies that license the ERP. It answers over each company’s own data, separates what a developer, an administrator and a user can see, sanitises sensitive fields and records every query.
Retrieval carries a relevance floor. A question with no support in the data returns that there is no information, rather than a text assembled from loosely related fragments.
What I learned
Visibility control started out resting on the instruction text and ended up entirely in code. The practical difference is that it can now be executed: a test puts a question through the rewriter and checks that the resulting SQL carries all three filters. There is nothing equivalent to run against a prompt.