Credora

CI License: MIT Exasol Personal 2026.1 ExaThon India 2026

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 (bank manager) admin / Demo@123 Generate a fresh data set, watch the six sources (with Exasol's own pushdown proof), approve or reject policy proposals and model activations under Approvals, follow Loan status, the app's audit and Exasol audit (the database's own log of every statement, and the scheduled jobs)
Data scientist datasci / Demo@123 Run the analysis and publish it to loan operations, train risk models inside Exasol and request activation, run what-if and send a policy proposal
Loan operations loanops / Demo@123 See the newly published results, assign companies to relationship managers from Decisions or the Top 50, verify and sanction escalations, follow Loan status
Relationship manager rm / Demo@123 Signs in as Subhashree Mohanty (RM001) and sees only the companies assigned to her, at full detail: negotiate inside the limit Exasol computed and log the loan status

The hand-off: the data scientist runs the analysis and publishes it, loan operations assigns its companies to relationship managers, each manager works her own companies and logs their loan status, and admin, data scientist and loan operations track every assigned company.

Every role also has Ask Credora: plain-English questions answered by Claude through the official Exasol MCP server, logged in to Exasol as that role's own database user.

Run your own copy: install Exasol Personal, clone this repo, fill in .env.<name> with your AWS profile and Route 53 domain, then run python deploy/credora.py deploy --env <name>. Step by step: Deploy it yourself.

Built on Exasol Personal#

Credora started on the Exasol Personal Local Starter Kit (exakit 0.2.3): its personal launcher 2.3.0, the Exasol MCP server 2.3.0, exapump 0.13.1 and pyexasol. Check yours with exakit version. We then deployed Exasol Personal to AWS with the official launcher (exasol 2.3.0, Exasol 2026.1.0 on an r6i.xlarge), because we wanted a working, always-on demo that exercises as much of Exasol as one real use case allows, end to end:

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 bank's three RDS databases live, with pushdown; nothing is copied
Script language containers Built-in Python 3 and Java, plus a custom Rust SLC (0.23.1) uploaded to BucketFS
BucketFS The Rust SLC, the adapter library, JDBC drivers and every trained model (pickle files)
Python UDFs (SET and SCALAR) Fetch CIBIL, GST and Account Aggregator data over the internet in parallel; train and score the risk models; write credit memos with Claude
CONNECTION objects Hold the API endpoints and keys, the BucketFS location and the AI provider, so no secret is in code
In-database ML Gradient-boosting PD model (champion), logistic-regression scorecard (challenger) and an Isolation Forest anomaly flag, trained and run inside Exasol
Lua scripting RUN_ANALYSIS runs the whole analysis as one call, committing and logging each step; TRAIN_MODEL; PURGE_EXPIRED with SHA-256 proof
PREFERRING (skyline) Ranks the Pareto-best companies into the top 50
Window functions and analytic SQL Turn 850,000 core-banking transactions and GST history into model features
Semantic views (exasol-semantic-views 0.5.1) CREDORA_SEM.PORTFOLIO: 16 certified metrics shared by the app and the AI
SQL preprocessor (preprocessor-framework 0.9.1) Routes semantic SQL per role, fail-open
Preprocessor library (preprocessor-library 0.3.1) cast_shorthand and trailing_comma, installed by the framework itself for the roles that send AI-written SQL: x::DECIMAL(6,4) and a trailing comma just work
Users, roles and GRANTs One Exasol user per app role; the database decides what each screen and the AI can read
Row-level security views A relationship manager's views filter on CURRENT_USER, so Exasol returns only her assigned companies
Auditing (EXA_DBA_AUDIT_SQL, EXA_DBA_AUDIT_SESSIONS) Every session and statement is tagged credora:<app user>:<feature>; the admin's Exasol audit screen shows who ran what, in which consumer group, with CPU, memory and duration
EXPLAIN VIRTUAL The Sources screen shows the SQL Exasol sends to Oracle, MySQL and PostgreSQL: the 850,000-transaction aggregation runs inside Oracle
COMMENT ON Every Credora table, column, schema and script carries its plain-English meaning; the MCP server hands it to the AI
Consumer groups and QUERY_TIMEOUT CREDORA_BATCH (analysis, jobs) high, CREDORA_APP (screens) medium, CREDORA_AI low with 60 s and 2 GiB per session: the AI cannot starve or hang the bank's analysis
Exasol Scheduler (exasol-scheduler 0.4.1) Runs PURGE_EXPIRED every 15 minutes and refreshes the virtual schemas nightly, from SCHED.SCHED_TASKS, with every run in SCHED.SCHED_HISTORY
System tables The app reads EXA_DBA_AUDIT_*, EXA_ALL_CONNECTIONS, EXA_ALL_COLUMNS, EXA_ALL_VIRTUAL_SCHEMAS, EXA_ALL_SCRIPTS, grants and sessions (Exasol audit, the control room, masking, memos)
Exasol MCP server (exasol-mcp-server 2.3.0) Ask Credora: Claude queries Exasol through MCP, logged in as the signed-in role's own user, writes switched off

Details and code for each: 4. Exasol at the centre and docs/WHY_EXASOL.md.

Verify it yourself#

Each claim can be checked on the live site and in one or two files.

Claim Check on https://credora.loan Code that proves it
The whole analysis is one Exasol call Sign in as datasci, open Analysis runs, press Run analysis (the new run is a draft until you press Publish to loan operations), then open any company's report: 13 steps, each with its SQL, Lua or Python and its time (about 17–18 s for 1,000 companies) exasol/lua/06_run_analysis.sql (RUN_ANALYSIS; step 10 is the anomaly flag, step 12 the PREFERRING skyline, step 13 the shadow challenger)
Bank data is read in place, never copied Sign in as admin, open Sources: Oracle, MySQL and PostgreSQL tables are counted through VS_CBS, VS_CIF and VS_LOS exasol/sql/03_virtual_schemas.sql
Exasol fetches outside data over the internet Visit https://credora.link: the CIBIL, GSTN and Account Aggregator relays that Exasol's UDFs call exasol/udf/04_api_udfs.sql, exasol/sql/02_connections.sql
The models are trained and scored inside Exasol Sign in as datasci, open Risk models, press Train champion and challenger: gradient-boosted trees (AUC 0.756) and a logistic regression scorecard (AUC 0.769) on the same hold-out; Champion vs challenger then shows the grades and decisions the challenger would change exasol/udf/05_ml_udfs.sql, exasol/lua/06_run_analysis.sql (TRAIN_MODEL, SCORE_CHALLENGER)
Unusual companies are flagged, never declined on it Open the report of a company referred with "Anomaly: ..." (an Isolation Forest UDF flags about 3% of the companies analysed) exasol/udf/05_ml_udfs.sql (ANOMALY_FLAG)
Each role reads through its own Exasol user Sign in as rm: My companies lists only the 25 companies assigned to RM001, each at full detail (full PAN and GSTIN, features); any other company's report answers 403, because Exasol returns no row for it exasol/sql/07_security.sql, backend/app/exa.py ROLE_USER, backend/app/routes/core.py db()
Exasol itself filters the RM's rows Connect as CREDORA_RM with any SQL client: SELECT COUNT(*) FROM CREDORA.V_RM_DECISIONS returns only her assigned companies (25), CREDORA_SEM.PORTFOLIO counts 25 companies analysed, and SELECT * FROM CREDORA.DECISIONS fails with "insufficient privileges" exasol/sql/13_rm_row_security.sql (V_RM_* join RM_ASSIGNMENT on EXA_USER = CURRENT_USER), exasol/semantic/11_latest_run_views.sql
Every hand-off is maker-checker Propose a policy as datasci (What-if, Send to admin for approval) or request a model activation; approve it as admin under Approvals. Nobody decides their own request; a policy approval writes CREDORA.CONFIG, runs and publishes the official analysis in one job backend/app/policy.py, backend/app/activation.py, backend/app/publish.py
Ask Credora is bound by the same grants Ask the first admin question below as admin, then as rm: the admin's SQL joins VS_CIF, VS_LOS and VS_CBS across three databases; the RM's reads the row-filtered V_RM_* views and only ever sees her assigned companies. Every answer shows each SQL statement it ran, and the API response names the Exasol user backend/app/assistant.py exasol_login(), MCP_SETTINGS, _on_topic()
Metrics are certified in a semantic layer Ask "Which 5 industries have the highest pre-approved amount, with their approval rate?": the SQL reads CREDORA_SEM.PORTFOLIO exasol/semantic/12_credora_model.sql, exasol/extensions/10_semantic_views_module.sql
Credit memos are written inside Exasol Open a company report and press Credit memo: the engine shown is exasol-udf exasol/udf/09_ai_udf.sql, backend/app/memo.py
Outside data is purged on schedule, inside Exasol, with proof Sign in as admin, open Exasol audit: the Exasol Scheduler's task credora_purge_expired (every 15 minutes) with its last runs from SCHED.SCHED_HISTORY, and when the next staged rows are due; Audit and purge then shows the row counts and SHA-256 fingerprints in CREDORA.PURGE_LOG. Or in SQL: SELECT * FROM SCHED.SCHED_HISTORY ORDER BY "STARTED_AT" DESC exasol/lua/08_purge.sql, exasol/sql/17_scheduler.sql, scheduler/Dockerfile
The database proves who ran what Sign in as admin, open Exasol audit: Exasol's own audit log, each statement with its Exasol user, app user and screen (credora:<user>:<feature>), consumer group, CPU, memory, duration and result; and one RUN_ANALYSIS with each step's COMMIT backend/app/exasol_admin.py, backend/app/exa.py client_tag(), tag_sql()
Oracle does the heavy aggregation Sign in as admin or datasci, open Sources, scroll to Pushdown proof: EXPLAIN VIRTUAL: Oracle receives the join, the filter and GROUP BY per account and month over ~850,000 transactions; PostgreSQL and MySQL each receive their own projection. Or run EXPLAIN VIRTUAL yourself on the query in step 7 exasol/lua/06_run_analysis.sql step 7, backend/app/exasol_admin.py PUSHDOWN_QUERIES
The AI cannot starve or hang the analysis Ask Credora anything, then look at Exasol audit: its sessions are credora:<role>:ask-credora; each runs QUERY_TIMEOUT = 60, NICE and a 2 GiB memory limit first, while the analysis runs in consumer group CREDORA_BATCH. In SQL: SELECT CONSUMER_GROUP_NAME, PRECEDENCE, QUERY_TIMEOUT FROM EXA_CONSUMER_GROUPS exasol/sql/16_resources.sql, backend/app/mcp_session.py, backend/app/assistant.py AI_SESSION_SQL
Every object explains itself Connect with any SQL client: SELECT COLUMN_NAME, COLUMN_COMMENT FROM EXA_ALL_COLUMNS WHERE COLUMN_SCHEMA = 'CREDORA' AND COLUMN_TABLE = 'DECISIONS' exasol/sql/15_comments.sql
Every click shows what Exasol does (Explain mode) Sign in as any role; Explain mode in the top bar is on by default. Each screen has a band "What Exasol is doing here", each key number and button an information mark that opens the term with its Exasol objects, code and documentation, and each action (run, publish, train, approve, assign, ask) a note of its steps in Exasol. Switch it off and the app is a plain CRM. All terms: Glossary frontend/src/explain/ (glossary.ts, actions.ts, pages.ts), docs/GLOSSARY.md
Every statement is visible, live Press Exasol console in the top bar, then open any screen or press Run analysis as datasci: each statement the backend sent to Exasol for your tab appears with the Exasol user it ran as (CREDORA_DATASCI, CREDORA_SVC), its time and rows; the analysis adds each RUN_ANALYSIS step as it commits; an Ask Credora question adds each MCP tool call with its SQL. Passwords and secrets are masked; you see only your own statements (the admin may see everyone's) backend/app/console.py, backend/app/exa.py _trace(), backend/app/routes/exasol.py
The control room shows each role a different database Open Exasol control room as admin, then as rm: schemas, virtual schemas with their adapters and last refresh, scripts and their language containers, connections (names only), the model registry with each pickle in BucketFS, roles and grants, the preprocessor and the semantic model's certified metrics, read from Exasol's system tables as the role's own user. The RM sees fewer objects, no virtual schema contents and a refusal from Exasol on MODEL_REGISTRY; the admin also sees every role's grants and the live sessions backend/app/routes/exasol.py build(), frontend/src/pages/exasol/ControlRoom.tsx
Everything rebuilds from this repo One command in any AWS account deploy/credora.py, deploy/exasol_setup.py, infra/main.tf

Contents#

  1. The problem
  2. How Credora solves it
  3. Architecture
  4. Exasol at the centre
  5. Role-based access, enforced by Exasol
  6. Ask Credora: try these
  7. Scale and measured performance
  8. Key decisions and trade-offs
  9. Security and data governance
  10. Failure modes
  11. Deploy it yourself
  12. Repository layout
  13. Documentation
  14. Built with Exasol open source: thank you
  15. About this project, contributing and contact

1. The problem#

Sapphire Bank has 1,000 corporate current-account customers, each run by 2 to 5 partners. Instead of waiting for companies to come to it, 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 18 seconds:

  1. 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.
  2. 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.
  3. 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.
  4. Score risk. A gradient-boosted model (the champion), trained inside Exasol on the bank's past loans, gives each company a probability of default and the effect of each feature on it.
  5. Flag the unusual. An Isolation Forest UDF looks at all companies of the run at once and flags the most unusual 3%: GST turnover far from bank credits or balances, volatile inflows, large partner money at other banks (possible circular trading or inflated turnover).
  6. 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. A flagged company that would be approved is referred with "Anomaly: ..." as the reason, never declined on it.
  7. Rank. Exasol's PREFERRING skyline peels off the companies that are best on return, risk and size at the same time. The top 50 go to the relationship managers.
  8. Shadow-score the challenger. A logistic regression scorecard, trained alongside the champion, scores the same companies and runs the same decision SQL, so the Models screen shows which grades and decisions it would change. It decides nothing until the data scientist requests its activation and the admin approves it.
  9. Hand over. The data scientist reviews the draft run and publishes it to loan operations; the web app exports its offers to the CRM. Loan operations assigns the companies to relationship managers, each manager sees only her assigned companies (Exasol filters the rows), negotiates inside the limit and logs the loan status, and loan operations verifies and sanctions what goes above it. Admin, data scientist and loan operations follow every company on the Loan status tracker.

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 · roles and AI access · 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)
       each role reads Exasol as its own user: CREDORA_ADMIN / _DATASCI / _LOANOPS / _RM
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, or adds more companies to it (append mode keeps every company name, partner name, PAN, GSTIN and account number unique)
Web app React + TypeScript (Vite), FastAPI, Caddy with automatic HTTPS Four role-based workspaces; every number tagged with its source
AI Claude (claude-sonnet-5-5) via the Anthropic API, or Amazon Bedrock with AI_PROVIDER=bedrock; the official Exasol MCP server (exasol-mcp-server 2.3.0, writes off); a CREDIT_MEMO UDF Ask Credora answers plain-English questions as the signed-in role's Exasol user, semantic layer first, showing every SQL it ran; credit memos are 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) the champion, a monotonic gradient-boosted model; train the challenger, a logistic regression scorecard (TRAIN_SCORECARD), on the same hold-out; flag unusual companies with an Isolation Forest (ANOMALY_FLAG); models versioned in BucketFS exasol/udf/05_ml_udfs.sql
Lua scripting RUN_ANALYSIS, TRAIN_MODEL, SCORE_CHALLENGER, DECISION_LOGIC (the decision SQL both share), PURGE_EXPIRED exasol/lua/
Analytic SQL and PREFERRING Feature engineering; multi-criteria skyline ranking exasol/lua/06_run_analysis.sql
Roles, users, grants, masked views Each app role reads through its own Exasol user; jobs run as CREDORA_SVC 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: 16 certified portfolio metrics, including anomaly-flagged companies exasol/semantic/
Exasol MCP server 2.3.0 Ask Credora: Claude queries Exasol as the signed-in role's own Exasol user, so the same grants bound the AI; writes switched off backend/app/assistant.py
Generative AI in a UDF CREDORA.CREDIT_MEMO calls Claude through CONNECTION AI_LLM and returns the memo as SQL output exasol/udf/09_ai_udf.sql
Purge with proof (Lua) PURGE_EXPIRED deletes consent-based outside data on time, keeping row counts and SHA-256 fingerprints exasol/lua/08_purge.sql
exasol-scheduler 0.4.1 Runs the scheduled work inside the Exasol ecosystem: PURGE_EXPIRED every 15 minutes, a nightly refresh of the three virtual schemas, every run in SCHED.SCHED_HISTORY; one container on the app host, logged in as CREDORA_SVC exasol/sql/17_scheduler.sql, scheduler/Dockerfile
Auditing Exasol's audit log, read by the admin's Exasol audit screen as CREDORA_ADMIN; every session and statement is tagged credora:<app user>:<feature> backend/app/exasol_admin.py, backend/app/exa.py
EXPLAIN VIRTUAL Live pushdown proof on the Sources screen for the analysis's reads of Oracle, MySQL and PostgreSQL backend/app/exasol_admin.py
COMMENT ON Plain-English meaning on every Credora schema, table, column and script (196 columns), returned to the AI by the MCP server's describe tools exasol/sql/15_comments.sql
Consumer groups, QUERY_TIMEOUT, NICE, session memory limit, password policy CREDORA_BATCH / CREDORA_APP / CREDORA_AI; Ask Credora's sessions get 60 s, NICE and 2 GiB each exasol/sql/16_resources.sql, backend/app/mcp_session.py
preprocessor-library 0.3.1 cast_shorthand and trailing_comma for the roles that send AI-written SQL, installed by PREPROC.MODULE_INSTALL with a pinned release and SHA-256 deploy/exasol_setup.py install_preprocessor_library()
Exasol Personal launcher One-command installation on AWS, ports limited to admin IPs deploy/credora.py

5. Role-based access, enforced by Exasol#

Access is decided by Exasol, not by the web app. Each of the four roles has its own Exasol user and database role (exasol/sql/07_security.sql). The backend runs every read for a signed-in person as that person's role user (backend/app/exa.py ROLE_USER, backend/app/routes/core.py db()); a query Exasol refuses comes back as 403 Exasol denied access for your role. Ask Credora starts the Exasol MCP server logged in as the same user (backend/app/assistant.py exasol_login()), so the AI can read exactly what the person can read, no more. Analysis, training, the CRM export and the purge run as the service user CREDORA_SVC.

Diagram: roles and AI access shows the four roles as rings of data, one Ask Credora question travelling from the login token through the topic gate and exasol_login() into Exasol as the role's own user, and what each role and its AI can and cannot do.

App role (login) Exasol user / role What the app shows What Ask Credora can read
Admin, the bank manager (admin) CREDORA_ADMIN / R_ADMIN Data generation (replace, append), sources, Approvals (policy proposals and model activations, with a pending-count badge), audit and purge, Loan status, and read-only everything else including drafts; does not run the analysis Results (CREDORA), the semantic view CREDORA_SEM.PORTFOLIO, the bank's databases through VS_CBS (Oracle), VS_CIF (MySQL) and VS_LOS (PostgreSQL), and raw outside data in CREDORA_STAGE
Data scientist (datasci) CREDORA_DATASCI / R_DATASCI Runs the analysis and publishes a reviewed run to loan operations; trains models and requests activation; what-if, saved runs with CSV export, policy proposals; decisions, Top 50 (drafts too), sources; Loan status read-only Same as admin
Loan operations (loanops) CREDORA_LOANOPS / R_LOANOPS Published runs only: decisions and Top 50 with Assign to RM (single, bulk, reassign), who has what, every company report, approval queue (verify, sanction, reject escalations above an RM's limit), Loan status Results, the semantic view and the three bank databases; not raw outside data (CREDORA_STAGE)
Relationship manager (rm) CREDORA_RM / R_RM Only the companies assigned to her (demo: Subhashree Mohanty, RM001), at full detail: unmasked PAN and GSTIN, features, the full report; negotiation inside the limit (above it escalates); loan status Contacted, Negotiating, Loan taken, In progress, Disbursed or Not interested, with a note and full history Only the row-filtered views V_RM_DECISIONS, V_RM_COMPANY, V_RM_FEATURES, V_RM_SCORES, V_RM_ASSIGNMENT, V_RM_LOAN_STATUS, the filtered V_LATEST_* views and semantic view, CONFIG and RUN_LOG; no other company, no bank databases, no outside data
(fallback) CREDORA_MCP / R_MCP Not a login Read-only results; used by Ask Credora only when a role user's password is not configured

How the layers fit:

  • Objects and columns are decided by Exasol grants. The latest-run views behind the semantic layer run with their owner's rights and are granted per role (exasol/semantic/11_latest_run_views.sql).
  • Rows are decided by Exasol too. Loan operations' assignments live in CREDORA.RM_ASSIGNMENT (CIF_ID, RM_ID, EXA_USER, ASSIGNED_BY, ASSIGNED_AT), written by the backend as CREDORA_SVC. The RM's views (exasol/sql/13_rm_row_security.sql) join it on EXA_USER = CURRENT_USER; views run with their owner's rights, so R_RM is granted only these views and has no grant on DECISIONS, SCORES, FEATURES, APPLICATIONS or V_COMPANY_MASKED. The V_LATEST_* views (and so CREDORA_SEM.PORTFOLIO) apply the same filter to any user holding R_RM. The demo maps CREDORA_RM to RM001; in production each relationship manager gets an own Exasol user with R_RM and the same views work unchanged. The backend's own RM checks stay as defence in depth.
  • Only published runs are official. A finished run is a draft until the data scientist publishes it (CREDORA.RUN_PUBLISH, written as CREDORA_SVC). V_LATEST_RUN, the RM views and the backend's current run all use the latest published run, so Exasol decides what loan operations and the RM see; the data scientist and the admin can still open drafts. An approved policy proposal's run is published by the system on the admin's behalf.
  • Semantic SQL is routed per role by the preprocessor framework: one rule per role in exasol/extensions/10_semantic_views_module.sql. CREDORA_SVC has no rule and pays nothing.
  • Demo book: python deploy/credora.py rm-book --env <name> runs exasol/sql/14_seed_rm_book.sql: 25 of the best pre-approved Top 50 companies for RM001, idempotent (nothing happens once RM001 has an assignment). A new deployment runs it after the first published analysis.
  • The AI cannot write. The MCP server runs with enable_write_query, enable_write_bucketfs and the preprocessor tools switched off (MCP_SETTINGS in backend/app/assistant.py).

Verified on the live site: an admin question joined VS_CIF."partner", VS_LOS."application" and VS_CBS.TXN / ACCOUNT across three databases in one statement. Logged in to Exasol as CREDORA_RM: V_RM_DECISIONS returns 25 rows (her assigned companies, one published run), V_RM_COMPANY shows full PAN and GSTIN for them, CREDORA_SEM.PORTFOLIO counts 25 companies analysed where loan operations counts 1,000, and SELECT COUNT(*) FROM CREDORA.DECISIONS fails with insufficient privileges: SELECT on table DECISIONS.

See it in the app: every role has the Exasol control room, a map of the database read from Exasol's system tables with the role's own Exasol user. The admin's map shows every role's grants (EXA_DBA_*, through SELECT ANY DICTIONARY) and the live sessions; the RM's shows only her own grants, the virtual schemas with no objects visible, and Exasol's refusal to read CREDORA.MODEL_REGISTRY. The Exasol console (top bar, Explain mode) lists each statement your screens ran with the Exasol user it ran as.

6. Ask Credora: try these#

Ask Credora answers from the semantic layer CREDORA_SEM.PORTFOLIO first (16 certified metrics, exasol/semantic/12_credora_model.sql), then with plain SQL where the role allows it. Each answer lists every MCP tool call with the exact SQL it ran. A one-word topic check runs before any tool use: unrelated requests (poems, recipes, "ignore your rules") are refused and never reach Exasol.

The page suggests four questions per role, each exercising a different Exasol feature:

Role Question Exercises
Admin For company C000229, join its partners from the customer master, its credit need on file and its current-account credits over the last 12 months from core banking. Cross-database join: MySQL VS_CIF + PostgreSQL VS_LOS + Oracle VS_CBS
Admin Which 5 industries have the highest pre-approved amount, with their approval rate? Semantic view
Admin How long did each step of the latest analysis run take, and how many rows did it process? RUN_LOG
Admin Which partners have a CIBIL score below 650, and which companies are they partners in? Raw CIBIL stage (CREDORA_STAGE) joined with the MySQL customer master
Data scientist Compare the risk model versions: AUC, Gini and the top three features of each. MODEL_REGISTRY
Data scientist What are the average probability of default and the expected loss by GST stage and grade? Semantic view
Data scientist In the latest run, how many grades and decisions would the challenger scorecard change, and in which direction? CHALLENGER_SCORES joined with SCORES and DECISIONS
Data scientist From the past loans in loan origination, what is the default rate by CIBIL commercial rank? PostgreSQL through VS_LOS
Loan operations Which approved companies have their KYC expired or pending in the customer master? MySQL VS_CIF joined with DECISIONS
Loan operations Show the 5 referred companies with the largest indicated need, and why each was referred. DECISIONS (hard fails) and SCORES
Loan operations For the top 10 ranked companies, what were their current-account credits over the last 12 months in core banking? Oracle VS_CBS joined with DECISIONS
Loan operations Which companies did the anomaly model flag in the latest run, with their decision and the reasons? ANOMALY joined with DECISIONS
Relationship manager Which of my assigned companies have the most negotiation headroom? V_RM_DECISIONS (row-filtered by Exasol)
Relationship manager Show my companies by loan status. V_RM_LOAN_STATUS
Relationship manager What is the lowest ROI I can offer my top-ranked company, and what is the RAROC at that rate? V_RM_DECISIONS (floor ROI, RAROC at the floor)
Relationship manager What is the pre-approved amount of my assigned companies by industry? Semantic view, filtered to her companies by V_LATEST_*

Ask a question outside a role's grants (for example the admin's cross-database question as rm) to see Exasol, not the prompt, set the limit.

7. 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 (join, filter and GROUP BY pushed down to Oracle: ~19,000 monthly rows return instead of ~850,000 transactions) 1,000 ~3.2 s (was ~10.5 s while Oracle sent every transaction: TRUNC(date, 'MM') is not pushed, TO_CHAR(date, 'YYYY-MM') is; EXPLAIN VIRTUAL showed it)
Probability of default (ML UDF) 1,000 ~1.9 s
Anomaly flag (Isolation Forest UDF) 1,000 checked, ~30 flagged ~1.3 s
Decide offer and negotiation limit 1,000 <0.1 s
Rank with PREFERRING top 50 <0.1 s
Shadow-score with the challenger (ML UDF + decision SQL) 1,000 ~1.7 s
Total ~17–18 s (run R20261031-2019; ~24–25 s before the Oracle aggregation was fully pushed down)

Two risk models are trained together by TRAIN_MODEL on the same 5,000 past loans and measured on the same 25% hold-out:

Model Role Hold-out AUC Gini Where it runs How it is used
Gradient-boosted trees, monotonic (TRAIN_PD) Champion (active) 0.756 0.512 Python UDF; scored by PD_SCORE in 4 parallel instances Its PD and grade decide every offer
Logistic regression scorecard on standardised features (TRAIN_SCORECARD) Challenger (inactive) 0.769 0.538 Python UDF; scored by the same PD_SCORE in SCORE_CHALLENGER Shadow only: on the last run it would change 713 of 1,000 grades and 62 decisions (42 refer to approve, 20 approve to refer). It decides only after a data scientist activates it
Isolation Forest (ANOMALY_FLAG) Anomaly flag unsupervised Python UDF, one instance that sees the whole run Flags the most unusual 3% (CONFIG ANOMALY_CONTAMINATION_PCT): GST turnover against bank credits and balances, inflow volatility, partners' money at other banks. On the last run 30 were flagged; 4 that would have been approved were referred with the reason, 26 were declined on other grounds, none was declined on the flag

A full data regeneration takes about 75 seconds.

8. 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
Score a challenger in the shadow on every run, through the same decision SQL A model change is judged on today's companies (grades and decisions that would move) before it decides anything About 1.7 s more per run; a second model to keep trained Model changes need formal sign-off: activation goes through an approval step
Anomaly flag refers, never declines Possible circular trading or inflated turnover gets a person's eye without an unexplained rejection A few good companies wait for review The bank labels confirmed cases: train a supervised fraud model on them
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, also for the AI Access is enforced by the database even if the app or the prompt has a bug; Ask Credora cannot read more than the person asking; audit shows the real role More users and grants to manage; one MCP server process per question 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

9. 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: each role reads as its own Exasol user (section 5). Loan operations cannot read raw outside data; relationship managers read only row-filtered views that return the companies assigned to them, so Exasol, not the app, keeps them to their own companies.
  • AI inside the same boundary: Ask Credora's MCP server logs in as the signed-in role's Exasol user with writes switched off; a topic check refuses unrelated questions before any query; every SQL statement it ran is shown with the answer. Credit memos are generated inside Exasol by the CREDIT_MEMO UDF, with the API key held in CONNECTION AI_LLM.
  • Secrets: generated per deployment by OpenTofu into AWS Secrets Manager; Exasol keeps API tokens in CONNECTION objects; nothing secret is in the repo.
  • TLS to Exasol, pinned: the backend and the Exasol MCP server connect with host/<certificate fingerprint>:8563, so pyexasol refuses any certificate but the deployment's own (Exasol's is self-signed). The fingerprint comes from the launcher's connection-instructions.txt at ship time (EXASOL_FINGERPRINT), never from code. The Exasol Scheduler can only validate against CAs, so its connection, inside the VPC, does not check the certificate.
  • Exasol passwords: PASSWORD_SECURITY_POLICY requires at least 12 characters with upper- and lower-case letters for every password set from now on; the generated passwords pass it, and no lock-out rule can take a role user's screens down.
  • Audit by the database: Exasol's audit log records every statement; each session and statement names the app user and screen (credora:<user>:<feature>), and the admin reads it under Exasol audit.
  • View owner: the owner's-rights views (V_COMPANY_MASKED, V_LATEST_*, V_RM_*, V_SESSION_SCOPE) are created by the deploy user SYS, so they read with DBA rights; each is granted only to the roles that may use it, and R_RM holds grants on its views only. A dedicated, minimally granted view owner is the next step, left out for now so the row-level-security views stay exactly as verified.
  • Workload isolation: consumer groups keep the AI (CREDORA_AI, and 60 s, NICE and 2 GiB per Ask Credora session) behind the screens (CREDORA_APP) and the analysis (CREDORA_BATCH).
  • Consent and retention: raw CIBIL, GST and Account Aggregator replies carry a purge time. The Exasol Scheduler runs PURGE_EXPIRED every 15 minutes, inside Exasol; it deletes what is due and keeps the row count and a SHA-256 fingerprint as proof (CREDORA.PURGE_LOG), and each run is a row in SCHED.SCHED_HISTORY. The scheduled task table is writable only by the deploy user.
  • Time zone: the database keeps the launcher's EUROPE/BERLIN. PURGE_AT, RUN_LOG and the other timestamps are plain TIMESTAMP values written in that zone and compared with SYSTIMESTAMP; switching the database to ASIA/KOLKATA would shift every stored value by 4.5 hours (purges early, runs mis-dated) unless all of them were migrated with it. The backend converts every timestamp to UTC with DBTIMEZONE, the UI shows IST, and the scheduler's cron expressions name Asia/Kolkata themselves.
  • Synthetic data only: every company, person and account is generated.

10. 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
Host-name lookup inside the Java script language container The Oracle virtual schema (VS_CBS) adapter cannot resolve the RDS endpoint, so steps that read core banking fail exasol/hotfix/slc_dns_fix.sh links the container's resolv.conf and hosts to the node's; re-run it after an Exasol restart
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; or switch provider with AI_PROVIDER=bedrock
The Exasol MCP server Ask Credora returns 503 ("could not start"); the rest of the app is unaffected Ask again; each question starts a fresh server process
A runaway AI query Exasol cancels it after 60 s ("Query terminated because timeout has been reached"); it ran at low priority (NICE) and could hold at most 2 GiB, so the analysis and the screens were not slowed None: Claude gets the error and answers with what it has
The scheduler container No purge or nightly refresh runs, and no SCHED_HISTORY row is written; missed runs are not replayed docker compose up -d scheduler on the app host (it restarts by itself unless stopped); or set PURGE_INTERVAL_MIN=15 to let the API purge as a fallback
Exasol Personal's 20 parallel connections A new session is refused ("license limit of 20 parallel connections") The backend keeps at most 3 sessions per role user, the scheduler opens one per job, Ask Credora one per question; close other SQL clients
A question outside the AI's grants Exasol refuses the query; Claude says the role cannot see that data None: this is the access control working

11. Deploy it yourself#

Everything below runs from your own machine (Windows, macOS or Linux) against your own AWS account. One command builds the whole system; nothing in the code is tied to a particular account or domain.

Step 1. Install Exasol Personal (the exasol launcher). Follow the install steps in the Exasol Personal repository, then check it works:

bash
exasol version

Step 2. Install the other tools.

Tool Why Check
AWS CLI v2 Credora creates its AWS resources with your credentials aws --version
Docker OpenTofu runs in a container; the app host images are built with it docker --version
Python 3.12 + uv The deploy tool uv --version
Node.js 20+ Builds the web app node --version
Git Clones the repo git --version

Step 3. Prepare the AWS account.

  1. Log the AWS CLI in to the account you want to use, under a profile name of your choice: bash aws configure --profile mysite # or: aws sso login --profile mysite / aws login --profile mysite aws sts get-caller-identity --profile mysite
  2. Have a domain as a Route 53 hosted zone in that account (for example mybank.example). The app is served at its root, with docs., video. and ppt. beside it. A second hosted zone is optional: it becomes the "outside world" with public cibil., gst. and aa. relays.
  3. The default sizes need 6 vCPUs of on-demand EC2 in the region (Exasol r6i.xlarge + app host t3.large). New accounts usually allow 8.

Step 4. Clone the repo and install the deploy tool.

bash
git clone https://github.com/anamika-iit-kgp/credora.git
cd credora
make setup            # without make: uv venv deploy/.venv && uv pip install -p deploy/.venv -r deploy/requirements.txt

Step 5. Fill in the environment file for your deployment. The name after .env. is the deployment name (here mysite):

bash
cp .env.example .env.mysite
Variable Set it to Required
AWS_PROFILE The profile from step 3 (mysite) yes
AWS_REGION Your region, e.g. ap-south-1 yes
DOMAIN Your Route 53 hosted zone, e.g. mybank.example yes
EXTERNAL_DOMAIN A second hosted zone for the outside-world relays no
ADMIN_CIDR Your IP as x.x.x.x/32; blank detects it no
EXASOL_INSTANCE, APP_INSTANCE, ORACLE_INSTANCE Instance sizes (defaults work) no
APP_*_PASSWORD Demo login passwords; blank = Demo@123 no
AI_PROVIDER, ANTHROPIC_API_KEY, AI_MODEL anthropic + your key, or bedrock; blank turns the AI features off no

Database, API and Exasol passwords are generated per deployment and stored in AWS Secrets Manager; you never type them. .env.* files are gitignored.

Step 6. Deploy.

bash
python deploy/credora.py deploy --env mysite      # same as: make deploy ENV=mysite

On Windows use deploy\.venv\Scripts\python (macOS/Linux: deploy/.venv/bin/python) if python is not the deploy tool's virtual environment. The first deploy takes about an hour (the Oracle RDS instance is the slowest part) and prints the site address at the end. Then:

bash
python deploy/credora.py access --env mysite      # writes deployments/mysite/ACCESS.md: every URL, login and password

Open https://<DOMAIN> and sign in with a demo user (admin, datasci, loanops, rm; password Demo@123 unless you set one).

deploy is idempotent (safe to re-run after a failure) and builds everything in order:

  1. Exasol Personal on EC2 through the official launcher, its ports limited to your IP.
  2. RDS for Oracle, MySQL and PostgreSQL, the app host, S3, Secrets Manager and DNS for both domains, with OpenTofu.
  3. The web app, API, mock APIs, generator, docs, video and presentation sites, with Docker Compose.
  4. 1,000 companies of synthetic data.
  5. In Exasol: the Rust container, both virtual schema adapters, the Oracle JDBC driver, connections, UDFs, Lua scripts, virtual schemas, roles, users, consumer groups and the password policy, the scheduler's tables and jobs, the preprocessor framework, the semantic model, the preprocessor-library modules and the comments on every object.
  6. 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 exasol --env <name> Re-applies the Exasol objects only (containers, adapters, UDFs, Lua, roles and users, preprocessor, semantic model)
python deploy/credora.py generate --env <name> Regenerates the synthetic data
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.

12. 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, row security, comments,
│  │              consumer groups, the scheduler's tables and jobs
│  ├─ 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, Exasol audit
├─ scheduler/     the Exasol Scheduler container (pinned release binary)
├─ tests/udf/     UDF unit tests with exasol/udf-mock-python
├─ .github/       CI: backend tests, frontend build, UDF and generator tests, deploy tools
├─ 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

13. 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, roles and AI access
docs/diagrams/05-roles-access.html The four roles as rings of data, one Ask Credora question into Exasol as the role's own user
docs/WHY_EXASOL.md Every Exasol feature and building block used, and why
docs/GLOSSARY.md Every Exasol, banking, AI and AWS term in plain words, with what Exasol does for it and the code
docs/DATA_MODEL.md Bank schemas, mock API data, feature definitions
docs/API.md Mock API contracts and the web app's API, including Ask Credora's response and topic check
docs/PORTING.md Deploying to another AWS account or domain

14. Built with Exasol open source: thank you#

Credora is assembled from Exasol's own products and open-source projects, from both the exasol and the exasol-labs GitHub organisations. Every one below runs in the live deployment or in CI; the versions are pinned in deploy/exasol_setup.py and the requirements files. Thank you to the Exasol team and the contributors of these projects.

Project What it does in Credora
exasol/exasol-personal Exasol Personal and its launcher: the database itself, deployed on AWS with one command
exasol-labs/exasol-personal-local-starterkit The starter kit (exakit 0.2.3) Credora began on: local Exasol, MCP setup, exapump, pyexasol
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 customer master and PostgreSQL loan origination, 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: certified metrics shared by 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 (release 0.3.1) for the roles that send AI-written SQL, installed by the framework's own module installer
exasol-labs/exasol-scheduler Release 0.4.1 runs Credora's scheduled jobs from SCHED.SCHED_TASKS: the consent purge every 15 minutes and the nightly virtual-schema refresh
exasol/udf-mock-python Runs the deployed ANOMALY_FLAG and PD_SCORE UDF code in CI, without a database
exasol/mcp-server exasol-mcp-server 2.3.0: Ask Credora's AI queries Exasol through it, as the signed-in role's user
exasol/pyexasol The Python driver used by the backend and the deploy tool
exasol-labs/exapump SQL and bulk-load CLI from the starter kit, used while building
exasol/virtual-schemas The virtual schema framework the Oracle adapter builds on

15. About this project, contributing and contact#

Credora is an ExaThon India 2026 project: a hands-on try-out of the Exasol Personal Local Starter Kit and the Exasol Personal product, deployed on AWS to show how far one analytics database can carry a real banking workflow: federation, in-database ML, AI, governance and security in one place.

  • Contributions are welcome. Fork the repo and open a pull request; for a larger change, open an issue first to discuss it.
  • Want to build on Credora, adapt it for your bank, or talk about buying or licensing it? Raise an issue in this repository and we will get in touch.
  • Found a bug or have a question about how something works in Exasol? An issue is the right place too.

Project by Anamika, Product Manager @ Equitas Small Finance Bank. The live deployment runs in my own AWS account, on the domains credora.loan and credora.link, which I registered for this project. Sapphire Bank is fictional and all data is synthetic.

License#

MIT. See LICENSE.