TDB Enterprise — IT Administrator Deployment Guide¶
TDB Enterprise
This guide is written for the IT or platform team that will deploy and operate the commercial enterprise edition on your own infrastructure. For a faster first run, start with Installation and the Quickstart. For the free, open-source CSV edition, see the Community Edition quickstart.
0. What you are deploying¶
TDB Enterprise is a single, self-contained Docker image. It runs one FastAPI/uvicorn process that exposes:
- a REST query API and source registry (
/v1/...), - an MCP server for AI tools (
/v1/mcp), - OpenAPI/Swagger docs (
/docs), - operational endpoints:
/health,/metrics(Prometheus),/(version banner).
It is read-only middleware in front of your data sources (CSV files and, in
enterprise, PostgreSQL / MySQL / SQL Server / Snowflake). It does not copy or
warehouse your data — it proxies governed SELECT-only queries and writes an
audit record for each one. Access is gated by a signed license (see the
build/licensing playbook).
There is one container; there is no separate database server to run. State lives in two files on a mounted volume (registry DB + audit log).
1. Pre-installation checklist¶
1.1 Operating system & runtime¶
| Requirement | Supported / recommended |
|---|---|
| Host OS | Any 64-bit Linux that runs a current container engine (Ubuntu 22.04/24.04 LTS, RHEL/Rocky 8–9, Debian 12 verified in test). macOS/Windows via Docker Desktop work for evaluation. |
| CPU arch | Production / commercial image: linux/amd64 (x86-64). Trial and evaluation images are multi-arch (linux/amd64 + linux/arm64), so they run natively on Apple Silicon Macs — docker pull selects your architecture automatically. If you need arm64 for a production deployment (e.g. AWS Graviton), tell us: it is a build-pipeline change, not a code change. |
| Container engine | Docker Engine ≥ 20.10 (BuildKit era) or any OCI-compliant runtime (Podman ≥ 4 works). |
| Compose (optional) | Docker Compose v2 if you deploy via compose file. |
| Kubernetes (optional) | Any conformant cluster ≥ 1.25. We ship no Helm chart or manifests today — a reference Deployment is in §4.3. |
The image is based on python:3.12-slim. The only system library baked in is
unixodbc (so the SQL Server connector can load). To actually connect to SQL
Server you additionally need the Microsoft ODBC Driver 18, which is not
in the image — see §5.4.
1.2 Hardware sizing (starting point — not an SLA)¶
Starting points, not an SLA. These are conservative recommendations derived from the deployment footprint — they are not benchmarked figures, and we do not publish throughput numbers we have not measured. Size against your own workload: §8 gives a repeatable method.
| Profile | vCPU | RAM | Disk |
|---|---|---|---|
| Evaluation / single user | 1 | 1 GB | 5 GB |
| Small team (default) | 2 | 2–4 GB | 20 GB |
| Heavier CSV / concurrent | 4 | 8 GB | 50 GB+ |
Notes that drive sizing: - The image is ~520 MB on disk / ~130 MB compressed. - CSV queries run in-process via DuckDB, which is memory- and CPU-hungry on large files (it reads the file per query — see §6). RAM should comfortably exceed your largest CSV working set. Database connectors stream from the remote engine and are far lighter on the TDB host. - Disk grows mainly with the audit log (one NDJSON line per successful query, append-only). Plan rotation/retention — see §5.3.
1.3 Network & ports¶
- The container listens on TCP 8000 (HTTP) inside the container. Publish/remap it
with
-p(e.g.-p 8000:8000). The server speaks plain HTTP — terminate TLS in front of it (see §7). - Egress the host must allow: to each registered data source (e.g. Postgres 5432, MySQL 3306, SQL Server 1433, Snowflake 443); to your private registry if pulling the image; and to your SIEM endpoint if you enable the Splunk exporter (HEC over 443/8088).
- No inbound connections are required other than to port 8000 from your API/MCP clients (and the reverse proxy).
1.4 Getting the image¶
Two channels — see Installation for the step-by-step version:
A. Customer-scoped private registry (default). You receive a pull token scoped to your own repo path:
docker login registry.tdb.jiracorp.co.in # use the token we provide
docker pull registry.tdb.jiracorp.co.in/tdb-customers/<your-slug>/tdb-enterprise:<edition>-<expiry>
B. Air-gapped tarball. For locked-down environments we deliver a .tar.gz:
docker load < tdb-enterprise-<edition>-<expiry>.tar.gz
docker images tdb-enterprise # confirm the tag is now present
License: trial images have a signed, expiring license baked in — nothing to configure. Commercial deployments may instead receive a token-less image and supply the license at runtime via
-e TDB_LICENSE=.... See §5.5.
2. Quick deploy (single container)¶
The minimum viable run. Generate real secrets — do not copy the placeholders.
docker run -d --name tdb -p 8000:8000 \
-e TDB_API_KEYS="$(python3 -c 'import secrets;print(secrets.token_urlsafe(32))')" \
-e TDB_JWT_SECRET="$(python3 -c 'import secrets;print(secrets.token_hex(32))')" \
-e TDB_ADMIN_USER=admin \
-e TDB_ADMIN_PASSWORD='<choose-a-strong-password>' \
-e TDB_LOG_FILE=/app/logs/tdb_audit.jsonl \
-v "$(pwd)/tdb-data:/app/data" \
-v "$(pwd)/tdb-logs:/app/logs" \
-v "$(pwd)/csv:/data:ro" \
<image>
What each mount is for:
- /app/data — persistent state (SQLite registry DB + API-key store). Must be
writable. Do not mount it read-only: the registry DB is created here at
startup, and a read-only mount makes the container exit at migration
(unable to open database file).
- /app/logs — the audit log (if you point TDB_LOG_FILE here). Persist it.
- /data (read-only) — where you place CSV inputs. The image confines registered CSV
paths to this directory by default (TDB_ALLOWED_DATA_DIR=/data). Mounting it :ro
is correct and recommended — it's a separate path from /app/data.
Confirm it came up:
docker logs tdb | grep license_ok # INFO: license_ok customer=... edition=... days_left=...
curl -fsS http://localhost:8000/health # {"status":"ok",...}
The container runs as a non-root user (tdb). Keep it that way; do not add
--user root.
3. Configuration reference (environment variables)¶
All configuration is via environment variables — there is no config file to edit inside the image. Defaults in parentheses.
3.1 Core / required¶
| Variable | Default | Purpose |
|---|---|---|
TDB_API_KEYS |
dev-insecure-key-change-me |
Comma-separated static API keys (Authorization: Bearer <key>). Always override. |
TDB_JWT_SECRET |
(empty) | HMAC secret for JWT auth. Required for JWT/OAuth login flows. |
TDB_ADMIN_USER / TDB_ADMIN_PASSWORD |
(empty) | Admin credentials for the login/OAuth consent flow. |
TDB_LICENSE |
(empty) | Runtime license token. Takes precedence over the baked file (commercial/renewals). |
TDB_LICENSE_FILE |
/app/license.jwt |
Path to the baked license token. |
3.2 Data, storage & logging¶
| Variable | Default | Purpose |
|---|---|---|
TDB_REGISTRY_DB |
data/tdb_registry.db |
SQLite path for the source registry + API keys. |
TDB_ALLOWED_DATA_DIR |
/data (set in image) |
Confines registered CSV file paths to this dir (symlinks/.. resolved). Empty = no restriction. DB connectors unaffected. |
TDB_LOG_FILE |
tdb_audit.jsonl |
Audit log path (NDJSON). Point at a persisted volume, e.g. /app/logs/.... |
TDB_LOG_LEVEL |
INFO |
DEBUG/INFO/WARNING/ERROR. |
TDB_VIEWS_DIR |
(unset) | Directory of YAML named-view definitions. Unset = views disabled. |
TDB_SCHEMA_CACHE_TTL |
300 |
Schema cache TTL (seconds). 0 disables caching. |
TDB_MAX_ROWS |
1000 |
Ceiling on rows in a single query response. A request asking for more is rejected with 400; a result larger than the request's limit is cut and flagged truncated. Raising it trades host RAM for bigger responses — size with §1.2. A bad value falls back to 1000 rather than uncapping. |
3.3 Access, auth & API behaviour¶
| Variable | Default | Purpose |
|---|---|---|
TDB_JWT_EXPIRE_MINUTES |
60 |
JWT lifetime. |
TDB_DEFAULT_RATE_LIMIT |
60 |
Default requests/min per API key (overridable per key). |
TDB_CORS_ORIGINS |
(empty = off) | Comma-separated allowed origins. * = all (dev only). |
TDB_CORS_ALLOW_CREDENTIALS |
false |
Access-Control-Allow-Credentials. Don't combine with *. |
TDB_SERVER_URL |
(derived) | Public base URL TDB advertises as the OAuth issuer. Set to your external HTTPS URL behind a proxy. |
3.4 SIEM export (optional — Splunk)¶
| Variable | Default | Purpose |
|---|---|---|
TDB_SPLUNK_HEC_URL |
(unset = exporter off) | Splunk HEC endpoint, e.g. https://splunk.corp/services/collector/event. |
TDB_SPLUNK_HEC_TOKEN |
(empty) | HEC token (a secret — see §6.3). |
TDB_SPLUNK_INDEX |
(unset) | Target index. |
TDB_SPLUNK_SOURCETYPE |
tdb:audit |
Event sourcetype. |
TDB_SPLUNK_VERIFY_TLS |
true |
Set false only for self-signed lab Splunk. |
3.5 Advanced¶
| Variable | Default | Purpose |
|---|---|---|
TDB_LICENSE_PUBKEY_FILE |
(baked key) | Override the license verification public key path. Normally leave unset. |
4. Deployment topologies¶
4.1 Docker Compose (recommended for a single host)¶
# docker-compose.yml
services:
tdb:
image: registry.tdb.jiracorp.co.in/tdb-customers/<slug>/tdb-enterprise:<edition>-<expiry>
restart: unless-stopped
ports:
- "8000:8000"
environment:
TDB_API_KEYS: ${TDB_API_KEYS}
TDB_JWT_SECRET: ${TDB_JWT_SECRET}
TDB_ADMIN_USER: ${TDB_ADMIN_USER}
TDB_ADMIN_PASSWORD: ${TDB_ADMIN_PASSWORD}
TDB_LOG_FILE: /app/logs/tdb_audit.jsonl
TDB_SERVER_URL: https://tdb.yourcompany.com
volumes:
- tdb-data:/app/data
- tdb-logs:/app/logs
- ./csv:/data:ro
volumes:
tdb-data:
tdb-logs:
Keep secrets in a .env file (referenced as ${...}) with chmod 600, or use your
platform's secret store — see §6.3.
4.2 Single docker run¶
See §2. Add --restart unless-stopped for
production. The image already declares a HEALTHCHECK against /health, so
docker ps / orchestrators see container health automatically.
4.3 Kubernetes (reference only)¶
Reference only — not a supported artifact. No official Helm chart or manifests ship today. The manifest below is a minimal starting point to adapt to your cluster conventions; we do not support it as a deployment artifact. The supported single-host path is Docker Compose (§4.1).
apiVersion: apps/v1
kind: Deployment
metadata: { name: tdb-enterprise }
spec:
replicas: 1 # see scaling caveat below
selector: { matchLabels: { app: tdb } }
template:
metadata: { labels: { app: tdb } }
spec:
securityContext: { runAsNonRoot: true }
containers:
- name: tdb
image: <image>
ports: [ { containerPort: 8000 } ]
envFrom: [ { secretRef: { name: tdb-secrets } } ]
volumeMounts:
- { name: data, mountPath: /app/data }
- { name: logs, mountPath: /app/logs }
readinessProbe: { httpGet: { path: /health, port: 8000 } }
livenessProbe: { httpGet: { path: /health, port: 8000 } }
volumes:
- { name: data, persistentVolumeClaim: { claimName: tdb-data } }
- { name: logs, persistentVolumeClaim: { claimName: tdb-logs } }
Scaling caveat: state (registry DB + audit log) is local SQLite + a local file. Do not run multiple replicas against the same volume — SQLite and the append-only hash-chained log assume a single writer. Run one replica with a
Recreatestrategy and an RWO volume. Horizontal scale-out is not supported today — this is a property of the state layer, not of the packaging, so no chart or manifest change would lift it.
5. Custom configuration tasks¶
5.1 Registering a data source¶
Sources are registered at runtime over the REST API (admin key), not in a config file. Example (PostgreSQL):
curl -fsS -X POST http://localhost:8000/v1/sources \
-H "Authorization: Bearer $ADMIN_KEY" -H 'Content-Type: application/json' \
-d '{
"name": "orders_pg",
"source_type": "postgres",
"connection": {
"host": "db.internal", "port": 5432, "dbname": "sales",
"user": "tdb_readonly", "password": "***",
"schema": "public", "table": "orders"
}
}'
- One registered source maps to one table (matches the CSV model). Need several tables? Register several sources, or use named views.
- Read-only is enforced at the engine level, not just by SQL parsing: Postgres sets
connection.read_only = True; MySQL uses a read-only transaction; SQL Server always rolls back (autocommit off) and is fronted by the SELECT-only validator. - Best practice: give TDB a least-privilege, read-only DB login (e.g. Postgres role
with
SELECTonly; SQL Serverdb_datareader). This is your real guarantee — TDB's enforcement is defence-in-depth on top of it.
Security: the
connectionblock (including the password) is persisted, encrypted at rest — read §6.2 for the key model before registering anything against production.
5.2 Named views (optional)¶
Set TDB_VIEWS_DIR=/app/views and mount a directory of YAML view definitions to expose
curated, reusable queries. Leave unset to disable the feature.
5.3 Logging & audit¶
- The audit log is append-only NDJSON at
TDB_LOG_FILE, hash-chained (each entry carriesseq+prev_hash+ SHA-256hash) so tampering is detectable. - Both outcomes are recorded. A successful query writes
event: "query"; a refusal writesevent: "denied"with the attemptedactionand a machine-readablereason(e.g.invalid_api_key,sql_validation_failed). Rejected access attempts are therefore first-class audit evidence, not just application-log noise — and because denials are signed into the same chain, deleting an inconvenient one breaks/v1/audit/verify. - Verify integrity any time (admin role):
- Rotation/retention is your responsibility. Rotating the file starts a fresh chain;
archive rotated segments if you need continuous verifiability. Optionally stream to a
SIEM via the Splunk exporter (§3.4).
Denial auditing applies to both editions. Entry shapes and the verification endpoint are documented in full at Audit Log.
5.4 SQL Server driver¶
The image ships unixodbc but not the Microsoft ODBC Driver 18. If you register a
SQL Server source you must provide the driver. The cleanest path is to install it in a
thin layer on top of our image:
FROM <tdb-enterprise-image>
USER root
RUN curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /usr/share/keyrings/microsoft.gpg \
&& curl -fsSL https://packages.microsoft.com/config/debian/12/prod.list > /etc/apt/sources.list.d/mssql.list \
&& apt-get update && ACCEPT_EULA=Y apt-get install -y --no-install-recommends msodbcsql18 \
&& rm -rf /var/lib/apt/lists/*
USER tdb
The connector defaults to Encrypt=yes. For self-signed SQL Server certs set
"trust_server_certificate": true in the source's connection block (lab only).
5.5 License¶
- Trial: baked in and expiring. On expiry the container keeps
/health,/, and/metricsgreen but returns HTTP 403 on every data route. Renew by re-pulling a new image. - Commercial: supply/rotate the token at runtime with
-e TDB_LICENSE=<token>and restart — no rebuild. See Installation → License and theTDB_LICENSE/TDB_LICENSE_FILEentries in the environment variable reference. - To extend a trial or renew a commercial license, contact hello@tdb.jiracorp.co.in.
6. Security model — what an admin must know¶
6.1 What TDB stores, and where¶
| Data | Location | At rest |
|---|---|---|
| Source registry (incl. DB connection + password) | SQLite TDB_REGISTRY_DB (/app/data/tdb_registry.db) |
Encrypted (Fernet, enc:v1: prefix) — whole connection blob, no plaintext mode. Key from TDB_ENCRYPTION_KEY or an auto-generated 0600 file beside the DB — see §6.2 |
| API keys | same SQLite DB (api_keys table) |
SHA-256 hashed (only hash + 6-char prefix); raw key shown once at creation |
| OAuth clients / authorization codes | same SQLite DB | codes are short-lived |
| Audit log (query text, source id, row count, key hint, timestamp) | TDB_LOG_FILE NDJSON |
plaintext, hash-chained |
| License token | /app/license.jwt (or TDB_LICENSE env) |
signed JWT; baked tokens are recoverable via docker history |
6.2 Where source credentials live¶
When you register a database source, the entire connection block — including the
password — is encrypted before it is written to the sources.connection column of
the SQLite registry DB (Fernet: AES-128-CBC + HMAC-SHA256, values prefixed enc:v1:).
The whole blob is encrypted, not just password-like fields, so host and username are
covered too. There is no plaintext mode — you cannot turn this off, and a database
from an older version is re-encrypted in place at first startup.
The encryption key comes from one of two places:
| Key source | How | What it protects against |
|---|---|---|
TDB_ENCRYPTION_KEY (recommended) |
You supply it from your secrets manager | Theft of the database file and theft of the whole data volume — the key never lands on disk beside the data |
| Auto-generated (default) | Created as .tdb_secret_key (mode 0600) beside the registry DB on first start |
Theft of the database file alone — e.g. a stray backup or a copied .db. Not theft of the whole data directory, since the key travels with it |
Be precise about that distinction in any security questionnaire: with the default
key, "credentials are encrypted at rest" is true and the key sits next to the data.
Setting TDB_ENCRYPTION_KEY is what makes the claim unconditional.
Still applies regardless:
- Protect the
/app/datavolume: restrictive filesystem permissions, and put it on an encrypted volume / encrypted-at-rest storage class. - Use a dedicated least-privilege, read-only DB account per source so the blast radius of a leaked credential is "read this one table," not "own the database."
- Restrict who holds an admin API key — registering/reading sources is an admin operation.
- Back the key up separately from the database. Losing it means re-registering every source; there is no offline recovery and no online re-key command today.
Registration responses and GET /v1/sources mask secret fields (password,
token, …) as ***, so credentials are not echoed back over the API either.
Full detail: Credentials at Rest and the
TDB_ENCRYPTION_KEYentry in the environment variable reference.
6.3 Where runtime secrets live¶
TDB_JWT_SECRET, TDB_ADMIN_PASSWORD, TDB_SPLUNK_HEC_TOKEN, and a runtime
TDB_LICENSE are read from environment variables. They are not written to the
registry DB, but standard env-secret caveats apply: they are visible via
docker inspect, the container's /proc/1/environ, and orchestrator manifests. Inject
them from your secret manager (Docker/K8s secrets, Vault) rather than committing them.
A baked license token is additionally recoverable from image metadata
(docker history) — acceptable because it only verifies against our public key and
grants nothing beyond what was issued.
6.4 DuckDB / query engine access¶
- CSV sources are queried in-process by DuckDB; there is no DuckDB server and no persisted DuckDB database file. DuckDB reads the CSV file directly per query.
- CSV file access is confined to
TDB_ALLOWED_DATA_DIR(default/data); symlinks and..are resolved and paths outside are rejected. Keep that mount read-only. - Queries are
SELECT-only, enforced by the SQL validator before execution; the CSV path is passed through DuckDB'sread_csvPython API (never string-interpolated), which prevents path/SQL injection.
6.5 Authentication & directory integration¶
TDB authenticates callers via static API keys, JWT (HMAC, TDB_JWT_SECRET), and
OAuth 2.1 + PKCE (for Claude/ChatGPT/Cursor MCP), plus a single
TDB_ADMIN_USER/TDB_ADMIN_PASSWORD for the consent/login flow. Authorization is
RBAC (read / readwrite / admin) per API key, with optional MCP tool-level
scoping.
Directory / AD integration is not supported today: - No SSO / SAML / OIDC-IdP / LDAP / Active Directory login to TDB itself (this is on the post-launch roadmap, not in the current edition). - No Kerberos / keytab / Windows-integrated auth to data sources. All DB connectors use SQL username/password auth only (SQL Server uses
UID/PWD, notTrusted_Connection). If your security policy mandates AD/Kerberos service accounts for database access, that requirement is not met today — the supported pattern is a dedicated, least-privilege SQL login per source. If AD-backed database auth is a hard requirement in your environment, raise it with us before you evaluate.
7. TLS / SSL¶
TDB serves plain HTTP on port 8000 and does not terminate TLS itself. For any non-localhost deployment, put it behind a TLS-terminating reverse proxy (nginx, Caddy, Traefik) or an ingress controller / cloud load balancer.
Minimal nginx example:
server {
listen 443 ssl;
server_name tdb.yourcompany.com;
ssl_certificate /etc/ssl/certs/tdb.crt;
ssl_certificate_key /etc/ssl/private/tdb.key;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Then set TDB_SERVER_URL=https://tdb.yourcompany.com so TDB advertises the correct
external HTTPS URL as its OAuth issuer. Note the OAuth flow requires https://
redirect URIs (only http://localhost is exempted) — OAuth will not work over plain
HTTP to a non-local host, which is by design. Restrict the container's port 8000 to the
proxy (bind to 127.0.0.1 or a private network), not the public interface.
8. Performance & capacity¶
No published benchmark figures. We deliberately do not quote throughput or latency numbers, because we have not run a benchmark we would be willing to hold ourselves to. What follows is a repeatable method for measuring TDB on your own hardware and data, plus the qualitative behaviour that drives the result.
How to benchmark in your environment:
1. Register a representative source (your real CSV size / DB table).
2. Drive load with a tool like k6/hey/wrk against POST /v1/query with a
representative SELECT, ramping concurrency.
3. Watch container CPU/RAM (docker stats) and the /metrics endpoint
(request_count, request_latency, schema_cache_hits).
What to expect qualitatively:
- CSV/DuckDB is CPU/RAM-bound and re-reads the file per query — large CSVs benefit
most from more RAM and from the schema cache (TDB_SCHEMA_CACHE_TTL).
- DB connectors push work to the remote engine; TDB mostly marshals rows, so the TDB
host stays light and the source DB is the bottleneck.
- Every response is capped, and the cap is enforced after fetching — a LIMIT in
your own SQL cannot raise it. The ceiling is TDB_MAX_ROWS (default 1,000; community
is fixed at 1,000). When rows are dropped the response carries truncated: true;
treat that flag as "this is not the whole answer." There is no pagination or cursor
today, so a larger result set must be narrowed in SQL — filter, aggregate, or page
with LIMIT/OFFSET yourself against a database source. This bounds per-request
memory and is the main thing to check before planning a bulk-extract workload.
- Single process/single writer — see the scaling caveat in §4.3.
9. Post-setup verification¶
Run these after deploying.
- Liveness:
curl -fsS http://localhost:8000/health→{"status":"ok"}. The version banner isGET /. - License accepted:
docker logs tdb | grep license_okshowscustomer=... edition=... days_left=N. (If you see 403s on data routes withreason: missing|expired, the license isn't being picked up.) - Auth enforced: a query without a bearer key →
401; with a valid key →200. - Register + query a source (§5.1) → rows returned.
- Read-only enforced: send a non-SELECT (e.g.
UPDATE ...) → rejected (400), and nothing is written to the source. - Audit working: confirm a new line appended to
TDB_LOG_FILEafter a successful query, thenGET /v1/audit/verify→{"valid": true, ...}. - Metrics:
curl -fsS http://localhost:8000/metricsreturns Prometheus text; wire it into your scraper. - MCP (if used): point your AI client at
https://<host>/v1/mcpand confirm theinitializehandshake + aquery_sourcecall succeed.
10. Day-2 operations¶
- Backups: snapshot the
/app/datavolume (registry DB + API keys) and archive the audit log. These two volumes are the entire stateful surface. - Upgrades: pull the new image tag, stop the old container, start the new one against
the same
/app/datavolume. Migrations are idempotent and run on startup. - Key rotation: add/rotate API keys via the
/v1/apikeysadmin API (raw key shown once); rotateTDB_JWT_SECRET(invalidates outstanding JWTs) on a schedule. - License renewal: see §5.5.
- Monitoring: scrape
/metrics; alert on/healthand onaudit/verifyreturningvalid:false.
11. Related documentation¶
- Installation — image channels, license, first run
- Quickstart — register a source and run a query
- Connect an IDE / AI Tool (MCP)
- Environment variables — every setting in §3
- RBAC · Audit Log · Credentials at Rest · Security & Updates
- Prometheus metrics · Splunk HEC
- Editions — what the community and paid editions each include
Questions about a deployment we have not covered here? hello@tdb.jiracorp.co.in