Skip to main content
A card represents a physical or virtual payment card (credit, debit, prepaid, corporate, or virtual) associated with a workspace. Each card record identifies its cardholder — either a Company or a People (mutually exclusive) — and carries card-identification attributes such as the last four digits, anonymized PAN, brand, type, and lifecycle dates. The entity is used to enrich payment-means data and surfaces in the financial graph as a composite via composite_cards_list on related roots (companies, people) and as a first-class cards records root.

API operations

Data model

Attributes

Relationships

System-computed

  • card_id is generated by PostgreSQL gen_random_uuid() on INSERT; the value is immutable after creation.
  • created_at is set once by the MikroORM @Property({ onCreate }) lifecycle hook at record creation and is never modified thereafter.
  • updated_at is set by the MikroORM @Property({ onCreate, onUpdate }) lifecycle hooks — populated on both create and every subsequent update.
  • deleted_at is null for all active records. Setting it to a timestamp soft-deletes the card; the row is retained in the database. Every active-record query must filter deleted_at IS NULL.
  • Cardholder is polymorphic: exactly one of company or people should be non-null for a meaningful card record. Neither FK carries a database-level mutual-exclusion constraint — the invariant is enforced at the service layer.
  • Three composite indexes are maintained for hot-path Hasura traversals: idx_cards_company_deleted (company_pk, deleted_at), idx_cards_people (people_pk), and idx_cards_workspace_deleted (workspace_pk, deleted_at). These were added in Migration20260416200000 after Query Insights revealed sequential scans on the companies.cards, peoples.cards, and workspace-scoped traversal paths.
  • The cards root is surfaced as a composite_cards_list array composite on the companies and people records roots (source_fields: card_id, brand, last_four_digits, type). The composite is defined in composites.yml under companies and people with display_type: relation_list and a sort_proxy of cards_aggregate.min.brand.
  • Cards are also linked from payment_means via the payment_means.card relationship (FK: payment_means.card_pk → cards.pk, ON DELETE SET NULL), added in Migration20260102111942. This underpins the composite_payment_means_summary composite renderer which reads payment_means.card.brand, payment_means.card.last_four_digits, and payment_means.card.type.

Example

Source: apps/api/src/database/entities/Card.ts · domain: financial-graph · tier: Supporting