Credora
Credora decides which corporate customers of Sapphire Bank get a pre-approved loan offer, and it does the work inside Exasol Personal.
It is live and working. Every link below is the real deployment.
| Site | Link |
|---|---|
| Live app | https://credora.loan |
| Docs | https://docs.credora.loan |
| Presentation | https://ppt.credora.loan |
| Demo video | https://video.credora.loan |
| 3rd party data, fetched on demand via API (mock CIBIL, GSTN and Account Aggregator APIs) | https://credora.link |
| Source code | https://github.com/anamika-iit-kgp/credora |
Sign in with one click on the login page, or use a demo login. All data is synthetic, so the passwords are public.
admin/Demo@123is the bank manager, who approves models and policy.datasci/Demo@123is the data scientist, who runs the analysis and publishes it.loanops/Demo@123is loan operations, who assigns companies to relationship managers.rm/Demo@123is Subhashree Mohanty (RM001), a relationship manager who sees only her own companies.

What it does#
Sapphire Bank has 1,000 corporate current-account customers and wants to approach the best of them with a pre-approved offer. Each offer has an amount, a rate and a tenure, plus a negotiation limit the relationship manager can move within. The data for that sits in the bank's Oracle, MySQL and PostgreSQL databases (including each company's credit need on file) and in 3rd party data via API from CIBIL, GSTN and the Account Aggregator. One call, EXECUTE SCRIPT CREDORA.RUN_ANALYSIS('<run>'), reads all six sources in place, scores risk with models trained in Exasol and prices and ranks the companies analysed in about 18 seconds.
The data scientist runs the analysis and publishes it. Loan operations assigns the companies to relationship managers, and each manager negotiates inside the limit and logs the loan status. The admin approves model activations and policy changes. In every role, Ask Credora answers plain-English questions with Claude through the official Exasol MCP server.

Exasol features used#
Credora started on the Exasol Personal Local Starter Kit (exakit 0.2.3, with the Exasol MCP server 2.3.0, exapump 0.13.1 and pyexasol). It was then deployed on AWS with the Exasol Personal launcher 2.3.0, running Exasol 2026.1.0 on an r6i.xlarge.
| Exasol feature | Where Credora uses it |
|---|---|
| Virtual schemas | VS_CBS (Oracle adapter 6.0, Java), VS_CIF and VS_LOS (adbc-vs-rs 0.7, Rust) read the three bank databases live, with pushdown. Nothing is copied. |
EXPLAIN VIRTUAL |
The Sources screen shows the SQL Exasol sends to each database. The aggregation over 850,000 transactions runs inside Oracle. |
| Script language containers | Built-in Python 3 and Java, plus a custom Rust container (0.23.1) uploaded to BucketFS |
| BucketFS | The Rust container, the adapter library, JDBC drivers and every trained model |
| Python UDFs (SET and SCALAR) | Fetch CIBIL, GST and Account Aggregator data in parallel, train and score the risk models, and write credit memos with Claude |
| CONNECTION objects | API endpoints and keys, the BucketFS location and the AI provider, so no secret is in code |
| In-database ML | A gradient-boosting champion, a logistic-regression challenger scored in the shadow and an Isolation Forest anomaly flag |
| Lua scripting | RUN_ANALYSIS runs 13 logged steps as one call. TRAIN_MODEL and PURGE_EXPIRED (with SHA-256 proof) are Lua too. |
| Window functions and analytic SQL | Turn core-banking transactions and GST history into 13 credit features |
PREFERRING (skyline) |
Ranks the Pareto-best companies into the top 50 |
| Semantic views (exasol-semantic-views 0.5.1) | CREDORA_SEM.PORTFOLIO holds 16 certified metrics shared by the app and the AI |
| SQL preprocessor (preprocessor-framework 0.9.1) | Routes semantic SQL per role and skips a failing module |
| Preprocessor library (preprocessor-library 0.3.1) | cast_shorthand and trailing_comma for the roles that send AI-written SQL |
| Users, roles and GRANTs | One Exasol user per app role, so the database decides what each screen and the AI can read |
| Row-level security views | The relationship manager's views filter on CURRENT_USER |
SQL audit (EXA_DBA_AUDIT_SQL, EXA_DBA_AUDIT_SESSIONS) |
Every statement is tagged credora:<app user>:<feature> and shown on the admin's Exasol audit screen |
COMMENT ON |
Every Credora schema, table, column and script carries its meaning, which the MCP server hands to the AI |
Consumer groups and QUERY_TIMEOUT |
CREDORA_BATCH runs the analysis first. Ask Credora sessions get 60 s and 2 GiB in CREDORA_AI, so the AI cannot starve the analysis. |
| Exasol Scheduler (exasol-scheduler 0.4.1) | Runs PURGE_EXPIRED every 15 minutes and refreshes the virtual schemas nightly, logged in SCHED.SCHED_HISTORY |
| System tables | Audit, connections, columns, virtual schemas, scripts, grants and sessions feed the admin screens |
| Exasol MCP server (exasol-mcp-server 2.3.0) | Ask Credora queries Exasol as the signed-in role's own user, with writes switched off |
| Exasol console and control room (Explain mode) | The console lists each statement a screen sent to Exasol, with the user it ran as. The control room maps the database as that role sees it. |
| Exasol Personal launcher | Installs Exasol on EC2 with one command, its ports open to admin IPs only |
Each feature, with its code and the reason for it, is in docs/WHY_EXASOL.md.
Roles, enforced by Exasol#
Every app role reads Exasol as its own database user. The backend runs each screen's queries as that user, and Ask Credora starts the MCP server logged in as the same user. When Exasol refuses a query, the screen shows 403 Exasol denied access for your role. Analysis, training and the purge run as the service user CREDORA_SVC.
| Login | Exasol user and role | What the app shows | What Ask Credora can read |
|---|---|---|---|
admin |
CREDORA_ADMIN / R_ADMIN |
Data generation, sources, approvals, audit and purge, Loan status | Results, the semantic view, the three bank databases and raw 3rd party data |
datasci |
CREDORA_DATASCI / R_DATASCI |
Runs and publishes the analysis, trains models, what-if and policy proposals | Same as admin |
loanops |
CREDORA_LOANOPS / R_LOANOPS |
Published runs, assigning companies to managers, sanctioning escalations | Same as admin, without raw 3rd party data (CREDORA_STAGE) |
rm |
CREDORA_RM / R_RM |
Only her assigned companies, at full detail, with negotiation and loan status | Only the row-filtered V_RM_* and V_LATEST_* views |
The V_RM_* views join CREDORA.RM_ASSIGNMENT on EXA_USER = CURRENT_USER, and R_RM has no grant on the result tables. Signed in to Exasol as CREDORA_RM, V_RM_DECISIONS returns her 25 companies and SELECT * FROM CREDORA.DECISIONS fails with "insufficient privileges". A prompt can't widen that, because the limit lives in the database.

Verify it yourself#
Every claim can be checked on https://credora.loan and in the code.
| Claim | Where to click | Code |
|---|---|---|
| The whole analysis is one Exasol call | datasci, Analysis runs, Run analysis, then any company report (13 steps with their SQL, Lua or Python and their time) |
06_run_analysis.sql |
| Bank data is read in place | admin, Sources |
03_virtual_schemas.sql |
| Oracle does the heavy aggregation | admin, Sources, Pushdown proof (EXPLAIN VIRTUAL) |
exasol_admin.py |
| Exasol UDFs fetch the 3rd party data via API | https://credora.link shows the relays the UDFs call | 04_api_udfs.sql |
| Models are trained and scored in Exasol | datasci, Risk models, Train champion and challenger |
05_ml_udfs.sql |
| Exasol filters the relationship manager's rows | rm, My companies lists 25 companies. Any other company's report returns 403. |
13_rm_row_security.sql |
| Ask Credora has the same grants | Ask the same cross-database question as admin, then as rm |
assistant.py |
| Every hand-off is maker-checker | Send a policy proposal as datasci, approve it as admin under Approvals |
policy.py |
| The database records who ran what | admin, Exasol audit |
exa.py client_tag() |
| 3rd party data is purged on schedule, with proof | admin, Exasol audit (scheduler runs), then Audit and purge |
08_purge.sql, 17_scheduler.sql |
| The AI can't starve the analysis | Ask Credora sessions appear in Exasol audit as credora:<role>:ask-credora |
16_resources.sql |
| Every click shows what Exasol does | Explain mode, Exasol console and Exasol control room in the top bar | console.py, explain/ |
| Everything rebuilds from this repo | One command in any AWS account | credora.py |
Deploy it yourself#
Everything runs from your own machine against your own AWS account. Nothing in the code is tied to an account or a domain.
- Install the
exasollauncher from exasol/exasol-personal and check it withexasol version. - Install the AWS CLI v2, Docker, Python 3.12 with uv, Node.js 20+ and Git.
- Log in to AWS, and have a Route 53 hosted zone in that account. The default sizes need 6 vCPUs of on-demand EC2.
bash aws configure --profile mysite aws sts get-caller-identity --profile mysite - Clone the repo and install the deploy tool.
bash git clone https://github.com/anamika-iit-kgp/credora.git cd credora make setup # or: uv venv deploy/.venv && uv pip install -p deploy/.venv -r deploy/requirements.txt - Copy
.env.exampleto.env.mysiteand fill it in. The name after.env.is the deployment name.
| Variable | Set it to | Required |
|---|---|---|
AWS_PROFILE |
The profile from step 3 | yes |
AWS_REGION |
Your region, for example ap-south-1 |
yes |
DOMAIN |
Your Route 53 hosted zone, for example mybank.example |
yes |
EXTERNAL_DOMAIN |
A second hosted zone for the 3rd party data APIs | no |
ADMIN_CIDR |
Your IP as x.x.x.x/32 (blank detects it) |
no |
APP_*_PASSWORD |
Demo login passwords (blank means Demo@123) |
no |
AI_PROVIDER, ANTHROPIC_API_KEY, AI_MODEL |
anthropic with your key, or bedrock (blank turns the AI off) |
no |
- Deploy, then write every URL, login and password to
deployments/mysite/ACCESS.md.bash python deploy/credora.py deploy --env mysite python deploy/credora.py access --env mysite
deploy is idempotent. It installs Exasol through the launcher, creates the RDS databases, app host and DNS with OpenTofu, starts the containers, generates 1,000 companies and sets up every Exasol object. Database and API passwords are generated into AWS Secrets Manager. Other commands (status, ship, exasol, generate, destroy) and moving a deployment to another machine are in docs/PORTING.md.
Diagrams#
| Diagram | Image | Interactive |
|---|---|---|
| Big picture | PNG | HTML |
| AWS deployment | PNG | HTML |
| Inside Exasol | PNG | HTML |
| Analysis flow | PNG | HTML |
| Roles and AI access | PNG | HTML |
The full design, with failure modes and trade-offs, is in docs/architecture.html.
Repository layout#
exasol/ SQL, Python UDFs, Lua scripts, preprocessor modules and the semantic model
backend/ FastAPI with roles, jobs, Ask Credora and the Exasol audit
frontend/ React and TypeScript, with Explain mode
mocks/ mock CIBIL, GSTN and Account Aggregator APIs and the data generator
deploy/ the one-command deploy tool, with infra/ (OpenTofu) beside it
docs/ architecture, diagrams, glossary, data model, APIs, porting
Documentation#
| Document | Covers |
|---|---|
| docs.credora.loan | The live docs site |
| docs/architecture.html | The full design, roles, decision logic, deployment and failure modes |
| docs/WHY_EXASOL.md | Every Exasol feature used, where and why |
| docs/GLOSSARY.md | Every Exasol, banking, AI and AWS term in plain words |
| docs/DATA_MODEL.md | Bank schemas, mock API data and feature definitions |
| docs/API.md | The mock API contracts and the web app's API |
| docs/PORTING.md | Deploying to another AWS account or domain |
Built with Exasol open source, thank you#
Every project below runs in the live deployment or in CI. Thank you to the Exasol team and to everyone who contributes to them.
| Project | What it does in Credora |
|---|---|
| exasol-labs/exasol-personal-local-starterkit | The starter kit (exakit 0.2.3) Credora began on, with local Exasol, MCP setup, exapump and pyexasol |
| exasol/exasol-personal | Exasol Personal and its launcher, which deploys the database on AWS |
| exasol/oracle-virtual-schema | VS_CBS, core banking in RDS Oracle, read live with pushdown |
| exasol-labs/adbc-vs-rs | VS_CIF and VS_LOS, the MySQL and PostgreSQL databases, read live through ADBC |
| exasol-labs/language-container-rs | The Rust script language container that runs the adbc-vs-rs adapter |
| exasol/script-languages-release | The Python 3 and Java containers behind the API, ML and AI UDFs |
| exasol-labs/exasol-semantic-views | CREDORA_SEM.PORTFOLIO, the certified metrics for the app and the AI |
| exasol-labs/preprocessor-framework | Owns the SQL preprocessor slot and routes semantic SQL per role |
| exasol-labs/preprocessor-library | cast_shorthand and trailing_comma (0.3.1) for AI-written SQL |
| exasol-labs/exasol-scheduler | Release 0.4.1 runs the purge every 15 minutes and the nightly virtual schema refresh |
| exasol/udf-mock-python | Tests the deployed ANOMALY_FLAG and PD_SCORE UDF code in CI |
| exasol/mcp-server | exasol-mcp-server 2.3.0, through which Ask Credora queries Exasol |
| exasol/pyexasol | The Python driver for the backend and the deploy tool |
| exasol-labs/exapump | The starter kit's SQL and bulk-load CLI |
| exasol/virtual-schemas | The virtual schema framework the Oracle adapter builds on |
About, contributing and contact#
Credora is an ExaThon India 2026 project. It is a try-out of the Exasol Personal Local Starter Kit and of Exasol Personal, deployed on AWS. The live deployment runs in my own AWS account, on the domains credora.loan and credora.link, which I registered for this project.
Contributions are welcome. Fork the repo and open a pull request, or open an issue first for a larger change. To build on Credora, adapt it for your bank, or buy or license it, raise an issue and I will get in touch.
Project by Anamika, Product Manager @ Equitas Small Finance Bank. Sapphire Bank is fictional, and all data is synthetic.
License#
MIT. See LICENSE.