The TMT Platform backend runs on Firebase Cloud Functions and depends on three Firebase services — Firestore, Authentication, and Cloud Storage — plus a PostgreSQL database on Cloud SQL. This page covers how each is initialized and what credentials you need before deploying.
Firebase project requirements
Your Firebase project must have the following services enabled:
| Service | Purpose |
|---|
| Firestore | Primary document store for events, tickets, orders, and users |
| Authentication | User identity and token verification |
| Cloud Functions | Hosts all backend logic (Node.js 22 runtime) |
| Cloud Storage | File uploads and generated documents |
| Firebase Cloud Messaging | Push notifications |
Cloud Functions requires a Firebase project on the Blaze (pay-as-you-go) plan. The free Spark plan does not support outbound network calls or Cloud SQL connections.
Firebase Admin SDK initialization
All Firebase service access flows through config/config.js. The file initializes the Admin SDK once and exports the service instances used throughout the platform.
const admin = require("firebase-admin");
admin.initializeApp();
const auth = admin.auth();
const db = admin.firestore();
const storage = admin.storage();
const messaging = admin.messaging();
admin.initializeApp() with no arguments reads credentials automatically from the GOOGLE_APPLICATION_CREDENTIALS environment variable when running locally, or from the attached service account when running inside Cloud Functions.
Exported values
Every function that needs Firebase access imports from config/config.js:
const { admin, db, auth, storage, messaging } = require('./config/config');
| Export | Type | Description |
|---|
admin | firebase-admin namespace | Full Admin SDK, used for custom token minting and admin-level operations |
db | Firestore | Firestore database instance |
auth | Auth | Firebase Authentication instance |
storage | Storage | Cloud Storage instance |
messaging | Messaging | Firebase Cloud Messaging instance |
Third-party credentials
config/config.js also holds references to third-party service credentials. These are initialized as placeholder values ('-' or 0) and must be injected at runtime via Firebase Secrets.
| Variable | Type | Service |
|---|
merchantId | number | Banco Mercantil payment gateway — primary merchant account |
merchantId_ted | number | Banco Mercantil — TED merchant account |
cifr | string | Banco Mercantil cipher/API signing key |
cifr_ted | string | Banco Mercantil TED cipher key |
clientidibm | string | IBM client identifier for Mercantil integration |
clientidibmpm | string | IBM client identifier (PM variant) |
numtel | number | SMS notification phone number |
cuentabdv | string | Banco de Venezuela account number |
apibdv | string | Banco de Venezuela API key |
seatsio_dev | string | Seats.io development workspace secret key |
seatsio_prod | string | Seats.io production workspace secret key |
Never hardcode production credentials in config.js. The - placeholder values are intentional — set real values through Firebase Secrets so they are injected at deploy time and never committed to source control.
Cloud SQL connection
PostgreSQL queries run through the sqltmt() helper in config/dbpostgres.js. It uses the @google-cloud/cloud-sql-connector package to establish an authenticated connection to Cloud SQL without requiring a VPC or static IP allowlist.
Connection configuration
Update the following values inside dbpostgres.js to match your Cloud SQL instance:
const connector = new Connector();
const clientOpts = await connector.getOptions({
instanceConnectionName: 'your-project:region:instance-name',
ipType: 'PUBLIC',
});
const pool = new Pool({
...clientOpts,
user: 'your-db-user',
password: 'your-db-password',
database: 'your-db-name',
max: 5,
});
| Field | Description |
|---|
instanceConnectionName | The Cloud SQL connection string — found in the Cloud Console under Connections > Connection name |
ipType | 'PUBLIC' for public IP or 'PRIVATE' for VPC private IP |
user | PostgreSQL database user |
password | Database user password |
database | Target database name |
max | Maximum number of pooled connections |
The sqltmt() helper
sqltmt() is an async function that builds and executes a SQL query, then closes the pool before returning results. It abstracts the four core DML operations:
async function sqltmt(tiposql, tabla, campos, where, valores, groupby)
| Parameter | Required | Description |
|---|
tiposql | Yes | Operation type: 'select', 'insert', 'update', or 'delete' |
tabla | Yes | Table name |
campos | For most operations | Column list (SELECT/INSERT) or SET clause (UPDATE) |
where | No | WHERE clause string (without the WHERE keyword) |
valores | For INSERT | VALUES string, e.g. "('a', 'b')" |
groupby | No | GROUP BY clause string (without the GROUP BY keyword) |
Example usage from within a Cloud Function:
const { sqltmt } = require('./config/dbpostgres');
// SELECT
const rows = await sqltmt('select', 'orders', '*', `status = 'pending'`);
// INSERT
await sqltmt('insert', 'orders', 'id, amount, status', null, "('ord_001', 500, 'pending')");
// UPDATE
await sqltmt('update', 'orders', `status = 'complete'`, `id = 'ord_001'`);
// DELETE
await sqltmt('delete', 'orders', null, `id = 'ord_001'`);
sqltmt() opens a new connection pool on every call and closes it after the query completes. This is appropriate for the stateless Cloud Functions execution model where persistent connection pools are not viable.
Encryption
The config/encryption.js module provides symmetric encryption for sensitive data stored in Firestore or transmitted between services. It exports four functions using Node.js’s built-in crypto module.
const { decrypt, encrypt, decryptAES256, encryptAES256 } = require('./config/encryption');
Functions
| Function | Algorithm | Use case |
|---|
encrypt(data, secretKeyHex) | AES-256-CBC | Encrypts a UTF-8 string using a 32-byte hex key. Returns encryptedBase64:ivBase64 |
decrypt(encryptedString, secretKeyHex) | AES-256-CBC | Decrypts a string produced by encrypt() |
encryptAES256(message, key) | AES-128-ECB | Encrypts using a SHA-256-derived key, for compatibility with external systems |
decryptAES256(message, key) | AES-128-ECB | Decrypts a message produced by encryptAES256() |
AES-256-CBC usage
encrypt() generates a random 16-byte IV on each call and appends it to the ciphertext, separated by ::
const { encrypt, decrypt } = require('./config/encryption');
const secretKeyHex = 'your-64-char-hex-string'; // 32 bytes = 64 hex chars
const ciphertext = encrypt('sensitive-data', secretKeyHex);
// Returns: 'base64EncodedCiphertext:base64EncodedIV'
const plaintext = decrypt(ciphertext, secretKeyHex);
AES-128-ECB usage
encryptAES256() / decryptAES256() derive the key by SHA-256 hashing the input key string and using the first 16 bytes. This variant is used for compatibility with payment gateway integrations that expect this key derivation scheme.
const { encryptAES256, decryptAES256 } = require('./config/encryption');
const ciphertext = encryptAES256('payment-token', 'shared-secret-key');
const plaintext = decryptAES256(ciphertext, 'shared-secret-key');
Store encryption keys as Firebase Secrets — never in source code. Rotate keys if they are ever exposed.
Firebase Functions v2 configuration
The TMT Platform targets Firebase Functions v2 (firebase-functions v7+). Functions are defined using the onRequest callable from firebase-functions/v2/https:
const { onRequest } = require('firebase-functions/v2/https');
exports.my_function = onRequest(async (req, res) => {
// handler
});
Runtime options (memory, timeout, region) are passed as the first argument to onRequest():
exports.my_function = onRequest(
{ timeoutSeconds: 300, memory: '512MiB', region: 'us-central1' },
async (req, res) => {
// handler
}
);
Functions that call sqltmt() or external payment APIs should set timeoutSeconds to at least 60 to accommodate cold starts and network latency.