Skip to main content
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:
ServicePurpose
FirestorePrimary document store for events, tickets, orders, and users
AuthenticationUser identity and token verification
Cloud FunctionsHosts all backend logic (Node.js 22 runtime)
Cloud StorageFile uploads and generated documents
Firebase Cloud MessagingPush 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.
config/config.js
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');
ExportTypeDescription
adminfirebase-admin namespaceFull Admin SDK, used for custom token minting and admin-level operations
dbFirestoreFirestore database instance
authAuthFirebase Authentication instance
storageStorageCloud Storage instance
messagingMessagingFirebase 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.
VariableTypeService
merchantIdnumberBanco Mercantil payment gateway — primary merchant account
merchantId_tednumberBanco Mercantil — TED merchant account
cifrstringBanco Mercantil cipher/API signing key
cifr_tedstringBanco Mercantil TED cipher key
clientidibmstringIBM client identifier for Mercantil integration
clientidibmpmstringIBM client identifier (PM variant)
numtelnumberSMS notification phone number
cuentabdvstringBanco de Venezuela account number
apibdvstringBanco de Venezuela API key
seatsio_devstringSeats.io development workspace secret key
seatsio_prodstringSeats.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:
config/dbpostgres.js
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,
});
FieldDescription
instanceConnectionNameThe Cloud SQL connection string — found in the Cloud Console under Connections > Connection name
ipType'PUBLIC' for public IP or 'PRIVATE' for VPC private IP
userPostgreSQL database user
passwordDatabase user password
databaseTarget database name
maxMaximum 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)
ParameterRequiredDescription
tiposqlYesOperation type: 'select', 'insert', 'update', or 'delete'
tablaYesTable name
camposFor most operationsColumn list (SELECT/INSERT) or SET clause (UPDATE)
whereNoWHERE clause string (without the WHERE keyword)
valoresFor INSERTVALUES string, e.g. "('a', 'b')"
groupbyNoGROUP 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.
config/encryption.js
const { decrypt, encrypt, decryptAES256, encryptAES256 } = require('./config/encryption');

Functions

FunctionAlgorithmUse case
encrypt(data, secretKeyHex)AES-256-CBCEncrypts a UTF-8 string using a 32-byte hex key. Returns encryptedBase64:ivBase64
decrypt(encryptedString, secretKeyHex)AES-256-CBCDecrypts a string produced by encrypt()
encryptAES256(message, key)AES-128-ECBEncrypts using a SHA-256-derived key, for compatibility with external systems
decryptAES256(message, key)AES-128-ECBDecrypts 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.

Build docs developers (and LLMs) love