Skip to main content
The TMT Platform manages ticketed events through a layered system of zones, seats, and individually addressable tickets. Each event stores its configuration and generated tickets in Firestore under the events collection, with a mirrored copy maintained in PostgreSQL for high-throughput querying during sales and access control.

Ticket Anatomy

Every ticket in the system is scoped to an event, a zone within that event, and a specific seat within that zone. The ticket is the atomic unit of admission — it carries its own identity, state, and a full audit trail via the ledger.
FieldDescription
ticket_idComposite ID: {event_id}-{firestore_doc_id}
seat_idComposite seat reference: {zone_id}-{seat_number}
zoneDisplay name of the seating zone
colorHex color assigned to the zone
statustrue = available, false = sold
status_offlinetrue when the ticket is assigned to an offline office
access_statustrue once the ticket has been scanned for entry
access_entrytrue while the holder is inside the venue
ledgerArray of time-stamped action entries (see below)
date_startEvent start timestamp (copied from the event document)
date_endEvent end timestamp (copied from the event document)
event_nameDisplay name of the parent event
event_idFirestore document ID of the parent event
seat_rowRow label, set to "por asignar" at generation

Ledger Entries

The ledger array records every significant action against a ticket. Each entry has the same shape:
{
  "date": "2024-11-15T20:00:00-05:00",
  "action": "generated",
  "metadata": "{}"
}
Possible action values:
ActionWhen it is written
generatedTicket is first created by tickets_generate
accessedTicket is scanned for entry (access_control_in)
came-outTicket holder exits the venue (access_control_out)
updatedTicket fields are manually updated
offlineTicket is assigned to an offline office
unassignTicket is returned from an offline office

Firestore Data Model

Tickets live as sub-documents under their parent event:
events/
  {event_id}/
    setup/
      zones          ← zone & seat configuration
    tickets/
      {ticket_doc_id}   ← one document per seat
    credentials/
      {credential_id}   ← staff / VIP credentials
    security/
      qr-pin         ← QR validation pin
The events/{id}/setup/zones document must have status: true before tickets_generate will proceed. This acts as an activation gate to prevent accidental generation.

Subsystems

Ticket Generation

Generate one ticket per seat from zone configuration. Writes to both Firestore and PostgreSQL in a single atomic batch.

Ticket Management

List all tickets for an event, fetch an individual ticket, or update ticket status and ledger entries.

Access Control

Checkpoint-based entry and exit scanning for both ticket QR codes and staff credentials. Supports cold (offline) sync.

Virtual Office

Online sales point: list available seats, lock tickets during checkout, view live sales status, and release held tickets.

Offline Office

Physical box offices that operate without a live connection. Tickets are assigned, sold locally, and synchronised back to the central platform.

Dual-Write Architecture

All ticket mutations are written to both Firestore and PostgreSQL. Firestore is the source of truth for real-time UI and access control apps. PostgreSQL backs all reporting, sales, and bulk queries via the dbpostgres.sqltmt helper.
The tickets_blocked table in PostgreSQL acts as a short-lived reservation lock. Records are inserted with a locked_up expiry timestamp and deleted either explicitly or by the tickets_unlock sweep.

Build docs developers (and LLMs) love