Credora
Pre-approved corporate loan offers for Sapphire Bank, decided inside Exasol.
Built for ExaThon India 2026 · Powered by Exasol Personal.
| Site | Address |
|---|---|
| Live app | https://credora.loan |
| Docs | https://docs.credora.loan |
| Demo video | https://video.credora.loan |
| Presentation | https://ppt.credora.loan |
| Outside world (mock CIBIL, GSTN, Account Aggregator) | https://credora.link |
Sign in with one click on the login page, or use these demo logins. All data is synthetic, so the passwords are public on purpose.
| Role | Login | What to try |
|---|---|---|
| Admin | admin / Demo@123 |
Generate a fresh data set, watch the seven sources, run the analysis |
| Data scientist | datasci / Demo@123 |
Train a risk model inside Exasol, compare versions, run what-if on policy |
| Loan operations | loanops / Demo@123 |
Open any company's Exasol report: the decision, why, and every step Exasol ran |
| Relationship manager | rm / Demo@123 |
Negotiate a pre-approved offer inside the limit Exasol computed |
Contents#
- The problem
- How Credora solves it
- Architecture
- Exasol at the centre
- Scale and measured performance
- Key decisions and trade-offs
- Security and data governance
- Failure modes
- Deploy it yourself
- Repository layout
- Documentation
1. The problem#
Sapphire Bank has 1,000 corporate current-account customers, each run by 2 to 5 partners. Instead of waiting for loan applications, the bank wants to approach its best customers with a pre-approved loan offer: an amount, a rate (ROI) and a tenure, plus a negotiation limit the relationship manager can move within without going back to credit.
To decide that, a credit officer needs data that lives in six places, half inside the bank and half outside it:
| Data | Where it lives | Owner |
|---|---|---|
| Accounts and about 8.5 lakh current-account transactions | Oracle core banking | Sapphire Bank |
| Companies, partners, KYC | MySQL customer master | Sapphire Bank |
| Each company's credit need on file, 5,000 past loans with outcomes | PostgreSQL loan origination and CRM | Sapphire Bank |
| Credit reports for every partner and company | CIBIL | Outside party |
| 2 to 10 years of monthly GST returns | GSTN | Outside party |
| Partners' accounts at other banks, with consent | Account Aggregator | Outside party |
Requirements
- Functional: combine all six sources per company; score credit risk with a model trained on the bank's own loan history; price an offer and a negotiation limit that still meet the bank's return hurdle; rank the portfolio; show every number with its source; let four roles work the result, from data generation to sanction.
- Non-functional: no copy of core banking leaves the bank's databases; consent-based outside data is deleted on time, with proof; each role sees only what it may see, enforced by the database; the full analysis of 1,000 companies runs in under a minute; the whole system rebuilds in any AWS account from this repo with one command.
- Out of scope: real CIBIL, GSTN or Account Aggregator connections (Credora ships faithful mocks); loan disbursement and servicing; real customer data of any kind.
2. How Credora solves it#
One call, EXECUTE SCRIPT CREDORA.RUN_ANALYSIS('<run>'), does the whole job inside Exasol in about 20 seconds:
- Read the bank's data in place. Virtual schemas expose Oracle, MySQL and PostgreSQL as Exasol schemas. Queries are pushed down to the source; nothing is copied first.
- Fetch the outside world. Python UDFs call the CIBIL, GSTN and Account Aggregator relays over the public internet, 16 in parallel, and stage the replies with a purge time.
- Build features. Thirteen credit features per company: GST turnover and filing discipline, the gap between GST turnover and bank credits, balances, inflow volatility, bounces, CIBIL ranks and partner scores, other-bank balances, debt service cover.
- Score risk. A gradient-boosted model, trained inside Exasol on the bank's past loans, gives each company a probability of default and the effect of each feature on it.
- Price and decide. Amount, ROI and tenure as the offer; floor ROI, maximum amount and maximum tenure as the negotiation limit, where the bank's risk-adjusted return (RAROC) still meets its hurdle; Approve, Refer or Decline with reasons.
- Rank. Exasol's
PREFERRINGskyline peels off the companies that are best on return, risk and size at the same time. The top 50 go to the relationship managers. - Hand over. The web app exports the offers to the CRM, and relationship managers negotiate inside the limit while loan operations verifies and sanctions.
Every step is logged with its row count and duration, and the web app shows each one with the SQL, Lua or Python that ran.
3. Architecture#
Diagrams: all diagrams · big picture · AWS deployment · inside Exasol · analysis flow · full design document
Sapphire Bank (private RDS) Outside world (https://credora.link)
Oracle CBS MySQL CIF PostgreSQL LOS cibil. gst. aa. (HTTPS relays)
| | | | | |
Oracle VS adbc-vs-rs adbc-vs-rs Python SET UDFs, 16 in parallel
\_____________|_____________/__________________|_______|______|
|
Exasol Personal on EC2 (r6i.xlarge, via the official launcher)
virtual schemas · API UDFs · ML training and scoring · Lua orchestration · PREFERRING
per-role users · masking · purge with proof · preprocessor framework · semantic layer
|
Web app at https://credora.loan (React + FastAPI behind Caddy, HTTPS)
Admin · Data scientist · Loan operations · Relationship manager · Ask Credora (MCP)
| Component | Technology | Why it is there |
|---|---|---|
| Analytics platform | Exasol Personal 2026.1 on EC2, installed by the official launcher | The single place where bank and outside data meet and become a decision |
| Bank databases | RDS for Oracle SE2, MySQL 8.4, PostgreSQL 16 in private subnets | Stand in for a bank's real core banking, customer master and loan origination systems |
| Outside parties | Mock CIBIL, GSTN and Account Aggregator APIs (FastAPI, own database each), published as cibil., gst., aa.credora.link |
Faithful stand-ins for external services that Exasol reaches over the internet |
| Data generator | Python service behind the admin's "Generate mock data" button | Rebuilds a consistent synthetic world (1,000 companies, ~3,500 partners) on demand |
| Web app | React + TypeScript (Vite), FastAPI, Caddy with automatic HTTPS | Four role-based workspaces; every number tagged with its source |
| AI | Claude via the Anthropic API or Amazon Bedrock, the Exasol MCP server, a CREDIT_MEMO UDF |
Plain-English questions over certified metrics; credit memos written inside Exasol |
| Infrastructure | OpenTofu (in Docker), Route 53 for both domains, Secrets Manager, S3, IAM | Reproducible from the repo in any AWS account |
4. Exasol at the centre#
Credora is assembled from Exasol's open-source building blocks, from the exasol and exasol-labs GitHub organisations, plus the bank-specific logic in this repo. docs/WHY_EXASOL.md covers each feature in depth.
| Exasol feature | Used for | Code |
|---|---|---|
| Virtual schemas: Oracle VS 6.0 (Java) and adbc-vs-rs 0.7 (Rust, ADBC, Arrow) | Read Oracle, MySQL and PostgreSQL in place | exasol/sql/03_virtual_schemas.sql |
| Custom script language container (Rust 0.23.1) and BucketFS | Run the Rust adapter; hold drivers and model files | deploy/exasol_setup.py |
| Python UDFs (SET scripts) and CONNECTION objects | Call the outside APIs in parallel, credentials kept out of SQL | exasol/udf/04_api_udfs.sql |
| ML in UDFs | Train (TRAIN_PD) and score (PD_SCORE) a monotonic gradient-boosted model, versioned in BucketFS |
exasol/udf/05_ml_udfs.sql |
| Lua scripting | RUN_ANALYSIS, TRAIN_MODEL, PURGE_EXPIRED |
exasol/lua/ |
Analytic SQL and PREFERRING |
Feature engineering; multi-criteria skyline ranking | exasol/lua/06_run_analysis.sql |
| Roles, users, masked views | Each app role reads through its own Exasol user | exasol/sql/07_security.sql |
| preprocessor-framework 0.9.1 | Owns Exasol's single preprocessor slot and dispatches per role, fail-open | exasol/extensions/ |
| exasol-semantic-views 0.5.1 | CREDORA_SEM.PORTFOLIO: 15 certified portfolio metrics |
exasol/semantic/ |
| Exasol MCP server | Ask Credora queries Exasol as a read-only user | backend/app/assistant.py |
| Exasol Personal launcher | One-command installation on AWS, ports limited to admin IPs | deploy/credora.py |
5. Scale and measured performance#
The demo data set is generated, but its volumes are realistic for a mid-size corporate book.
| Data | Volume |
|---|---|
| Companies / partners | 1,000 / ~3,500 |
| Current-account transactions (Oracle) | ~850,000 |
| GST returns (via the GSTN relay) | ~71,000 |
| Credit reports (via the CIBIL relay) | ~3,500 consumer + 1,000 commercial |
| Other-bank accounts (via the AA relay) | ~6,000 accounts, ~400,000 transactions |
| Past loans for training | 5,000, ~8% defaulted |
RUN_ANALYSIS on the live deployment (one r6i.xlarge node):
| Step | Rows | Time |
|---|---|---|
| Refresh three virtual schemas | 3 | ~1.7 s |
| Read credit needs and customer master (PostgreSQL + MySQL) | 1,000 | ~0.3 s |
| CIBIL consumer and commercial reports (public relay) | 4,490 | ~1.2 s |
| GST returns (public relay) | ~71,000 | ~1.5 s |
| Account Aggregator (public relay) | ~5,800 | ~3.4 s |
| Features over Oracle transactions (pushdown aggregation) | 1,000 | ~10.5 s |
| Probability of default (ML UDF) | 1,000 | ~1.9 s |
| Decide offer and negotiation limit | 1,000 | <0.1 s |
Rank with PREFERRING |
top 50 | <0.1 s |
| Total | ~20 s |
The risk model reaches an AUC of about 0.75 on a hold-out set of past loans. A full data regeneration takes about 75 seconds.
6. Key decisions and trade-offs#
| Decision | Solves | Worsens | Would change when |
|---|---|---|---|
| Read the bank's databases through virtual schemas instead of loading them | No copy of core banking; always current; one SQL surface over three engines | Each run pays network and source-database cost; features depend on the sources being up | Runs need to be much faster or more frequent: materialise the monthly aggregates in Exasol on a schedule |
| Call outside parties from UDFs over public HTTPS relays | External data lands next to bank data in one SQL step; mirrors how real bureaus are reached | Internet latency and a public endpoint to protect (API key, rate limits) | A real bureau requires private connectivity: point the CONNECTION objects at a private endpoint, no code change |
| Train and score the model inside Exasol | No data export to an ML platform; versioned models in BucketFS; scoring is a SQL step | Limited to libraries in the Python container; no GPU | Models need deep learning or heavy feature stores: score externally and keep only results in Exasol |
Rank with PREFERRING instead of a weighted score |
No hand-tuned weights; shows the genuinely non-dominated companies | Skyline layers are harder to explain than one number | The bank wants one policy-driven score: keep the skyline for exploration, add a weighted rank |
| One Exasol user per app role | Access is enforced by the database even if the app has a bug; audit shows the real role | More users and grants to manage | Hundreds of roles: move to impersonation or an identity provider |
| Preprocessor framework + semantic views | Many SQL extensions share Exasol's single preprocessor slot safely; certified metrics for humans and AI | Adds a step on every statement for the routed roles (~4 ms) | Statement latency matters more than governed metrics for a role: remove its routing rule |
| Single Exasol node and one app host | Cheap, simple, fits the hackathon | No high availability; a host failure is an outage | Production: multi-node Exasol, two app hosts behind a load balancer, Multi-AZ RDS |
| Mock outside parties with their own databases | Realistic, repeatable demos with consistent hidden risk | Not real-world data quality | Real integrations: replace the relays' targets, keep the UDFs and contracts |
7. Security and data governance#
- Network: only Caddy (80, 443) is public. Exasol's ports (8563, 8443, 2581, 22) open only to admin IPs; the RDS databases sit in private subnets reachable from the VPC only.
- Least privilege in the database: loan operations cannot read raw outside data; relationship managers see only their own companies through a masked view; the AI assistant uses a read-only user.
- Secrets: generated per deployment by OpenTofu into AWS Secrets Manager; Exasol keeps API tokens in CONNECTION objects; nothing secret is in the repo.
- Consent and retention: raw CIBIL, GST and Account Aggregator replies carry a purge time.
PURGE_EXPIREDdeletes them on schedule and keeps the row count and a SHA-256 fingerprint as proof. - Synthetic data only: every company, person and account is generated.
8. Failure modes#
| If this fails | What happens | Recovery |
|---|---|---|
| A bank database (RDS) | The analysis step that reads it fails and is logged; the previous run's results stay visible in the app | Re-run the analysis when the source is back |
| An outside relay | The fetch step fails with the API's error; no partial run is published | Re-run; the relays are stateless |
| A broken preprocessor module | The framework skips it (fail-open), so ordinary SQL keeps working | Fix or remove the module's rule |
| The Exasol node | The app shows the last results it can reach; analysis and AI are unavailable | Restart through the launcher; all objects are recreated idempotently by deploy |
| The app host | The site is down; Exasol and the databases are unaffected | python deploy/credora.py ship --env <name> rebuilds it |
| The AI provider | Ask Credora and memos show "not configured" or an error; everything else works | None needed |
9. Deploy it yourself#
You need an AWS account with one Route 53 hosted zone (two for the outside-world domain), the AWS CLI logged in, Docker, Node.js, Python 3.12 and the Exasol Personal launcher.
cp .env.example .env.mysite # AWS_PROFILE, DOMAIN, optionally EXTERNAL_DOMAIN
make setup # Python dependencies for the deploy tool
make deploy ENV=mysite # or: python deploy/credora.py deploy --env mysite
deploy is idempotent and builds everything in order:
- Exasol Personal on EC2 through the official launcher, its ports limited to your IP.
- RDS for Oracle, MySQL and PostgreSQL, the app host, S3, Secrets Manager and DNS for both domains, with OpenTofu.
- The web app, API, mock APIs, generator, docs, video and presentation sites, with Docker Compose.
- 1,000 companies of synthetic data.
- In Exasol: the Rust container, both virtual schema adapters, the Oracle JDBC driver, connections, UDFs, Lua scripts, virtual schemas, roles, users, the preprocessor framework and the semantic model.
- The first model training and analysis.
| Command | Does |
|---|---|
python deploy/credora.py status --env <name> |
Site address, logins, container health |
python deploy/credora.py access --env <name> |
Writes deployments/<name>/ACCESS.md: every URL, login, password and connection command |
python deploy/credora.py allow-ip --env <name> |
Opens Exasol and SSH to another machine's IP |
python deploy/credora.py ship --env <name> |
Rebuilds and restarts the app host only |
python deploy/credora.py destroy --env <name> |
Removes everything the deployment created |
Everything local about a deployment (launcher directory, OpenTofu state, SSH keys, logs, ACCESS.md) lives in deployments/<name>/, which is gitignored. Copy it with .env.<name> to operate the same deployment from another machine. See docs/PORTING.md.
10. Repository layout#
credora/
├─ deploy/ one-command deploy tool, remote start script
├─ infra/ OpenTofu: RDS x3, app host, S3, secrets, Route 53 for both domains
├─ exasol/
│ ├─ sql/ schemas, connections, virtual schemas, security
│ ├─ udf/ Python UDFs: outside APIs, ML training and scoring, AI memo
│ ├─ lua/ RUN_ANALYSIS, TRAIN_MODEL, PURGE_EXPIRED
│ ├─ extensions/ the semantic layer as a preprocessor-framework module
│ └─ semantic/ latest-run views and the Credora semantic model
├─ db/ Sapphire Bank schemas (Oracle, MySQL, PostgreSQL) and the mock API schemas
├─ mocks/ mock CIBIL, GSTN and Account Aggregator APIs; synthetic data generator
├─ backend/ FastAPI: roles, jobs, reports, CRM export, Ask Credora
├─ frontend/ React + TypeScript
├─ sites/ docs, video, presentation and outside-world sites
├─ media/ demo video and presentation files
└─ docs/ architecture, diagrams, data model, APIs, why Exasol, porting
11. Documentation#
| Document | Covers |
|---|---|
| docs/architecture.html | The full design: components, roles, data, decision logic, deployment |
| docs/diagrams/ | Big picture, AWS deployment, inside Exasol, analysis flow |
| docs/WHY_EXASOL.md | Every Exasol feature and building block used, and why |
| docs/DATA_MODEL.md | Bank schemas, mock API data, feature definitions |
| docs/API.md | Mock API contracts and the web app's API |
| docs/PORTING.md | Deploying to another AWS account or domain |
License#
MIT. See LICENSE.