ASI Database Node API

Connecting to the database

Production API: https://asi-database-node-api.arybit.co.ke. This HTTPS address serves diagnostics and opt-in application operations; it is not a PostgreSQL or MySQL connection endpoint.

Obtain the actual VM SSH address, approved SSH key, pinned known-hosts file, database name and least-privilege user from the operator. Use existing private credentials; examples deliberately contain no passwords. The backend supports loopback and verified-TLS MySQL transport. Keep PostgreSQL private; public MySQL 3306 requires the explicit reviewed dual-interface policy.

PostgreSQL on the VM

Run a PostgreSQL client on the database VM. Replace the name and user with provisioned values:

psql --host=127.0.0.1 --port=5432 --dbname=YOUR_DB_NAME --username=YOUR_DB_USER --password

Enter the password at the prompt, then verify:

SELECT current_database(), current_user;
SELECT 1;

PostgreSQL through SSH

On your workstation, keep this tunnel running in a separate terminal. Replace VM_ADDRESS with the verified VM SSH host; it may differ from the public API DNS target:

ssh -N -o ExitOnForwardFailure=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile=.private/production-known_hosts -i .private/production-admin.pem -L 127.0.0.1:15432:127.0.0.1:5432 azureuser@VM_ADDRESS

Then connect locally:

psql --host=127.0.0.1 --port=15432 --dbname=YOUR_DB_NAME --username=YOUR_DB_USER --password

For pgAdmin or DBeaver, use host 127.0.0.1, port 15432, the provisioned database/user and a privately entered password while the SSH tunnel is active. Encryption across the remote network is supplied by SSH. Never disable host-key verification to resolve a connection failure.

MySQL

The driver supports an existing local MySQL instance and opt-in authentication operations. This does not qualify the disabled legacy SQL migrations.

mysql --host=127.0.0.1 --port=3306 --user=YOUR_DB_USER --password YOUR_DB_NAME

For workstation access, tunnel a different local port:

ssh -N -o ExitOnForwardFailure=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile=.private/production-known_hosts -i .private/production-admin.pem -L 127.0.0.1:13306:127.0.0.1:3306 azureuser@VM_ADDRESS
mysql --host=127.0.0.1 --port=13306 --user=YOUR_DB_USER --password YOUR_DB_NAME

Use DB_ENGINE=mysql and DB_PORT=3306 in the protected backend runtime settings for an existing MySQL deployment.

Application and migration identities

The API uses DB_ENGINE, DB_HOST, DB_PORT, DB_NAME, DB_USER and DB_PASSWORD. Supply these through the protected runtime file, never through browser configuration. Its diagnostic mode readiness probe runs SELECT 1; application mode also checks contract metadata. Use separate identities for migrations and backups. PostgreSQL tenant policies use CURRENT_USER and asi.tenants.database_role; successful login alone does not grant tenant data access. Provision roles and grants deliberately and validate isolation before enabling products.

For authentication failures, confirm the database/user, password and server authentication policy. For connection refusal, confirm the service, tunnel and selected port. A 503 from /ready can reflect missing credentials or a failed probe. See qualification.

Opt-in MySQL authentication operations

Set APPLICATION_API_ENABLED=1, DB_ENGINE=mysql, DB_PORT=3306 and explicit DB_NAME, DB_USER and DB_PASSWORD only after installing the separate mysql-auth stream. DB_POOL_SIZE defaults to 8 (range 1–64); DB_TIMEOUT defaults to 5 seconds (1–30), bounding pool acquisition, connection and socket reads/writes. Each process has its own pool; size total connections for all workers plus maintenance headroom. MySQL SELECT execution and MariaDB statement limits are five seconds, and InnoDB lock wait is three seconds. Client disconnect does not constitute a committed-write acknowledgement. Writes are never automatically replayed. Connections commit only on success, roll back on rejected operations, discard driver-failed connections, and close on application shutdown. No SQLite fallback or startup schema DDL exists.

Application mode readiness checks all five contract tables as the runtime user; it does not verify every schema constraint or consumer workflow. A missing table or unavailable pool produces 503. Empty tables are valid. The readiness probe reads information_schema column metadata, not audit rows.

Use a separate migration/identity administrator. Grant the runtime only the following on the reviewed schema (replace DB and account using an administrator):

GRANT SELECT ON DB.asi_services TO 'api_runtime'@'localhost';
GRANT SELECT, INSERT, UPDATE ON DB.asi_users TO 'api_runtime'@'localhost';
GRANT SELECT, INSERT, UPDATE ON DB.asi_sessions TO 'api_runtime'@'localhost';
GRANT SELECT, INSERT, UPDATE ON DB.asi_verification TO 'api_runtime'@'localhost';
GRANT INSERT ON DB.asi_audit TO 'api_runtime'@'localhost';

The API never selects audit rows. Metadata visibility follows granted table privileges. Do not grant global privileges, DDL, FILE, PROCESS, GRANT OPTION, service-registry mutation, migration-ledger access or audit UPDATE/DELETE. The integration suite verifies these restrictions for the disposable runtime role. Because the runtime connects to all tenants, compromise of that credential is a cross-tenant incident.

Remote MySQL TCP requires DB_SSL_CA with mandatory certificate/hostname verification. Loopback and reviewed pinned SSH tunnels remain supported. Direct PHP credentials are separate execute-only accounts; never share the HTTPS runtime database identity.

Dual-interface grants and TLS

The same authoritative schema serves direct TLS and HTTPS. In addition to the runtime grants above, grant SELECT/INSERT/UPDATE on asi_service_limits and EXECUTE on the two internal shared user routines to the HTTPS runtime principal. Do not grant it mutation on asi_direct_accounts. Direct consumers receive only EXECUTE on approved asi_direct_* wrappers, with no base-table or private-routine privileges. See complete direct interface contract and .env.example for PHP settings. API_SERVICE_RATE_PER_MINUTE defaults to 120 across workers for one registered tenant/service. DB_SSL_CA is mandatory for non-loopback hosts and DIRECT_DATABASE_ENABLED=1. DB_HOST is always a hostname/IP, never a URL.