Skip to content

Payment settings

Purpose

Per-company configuration row for a payment gateway. Picks the platform (liqpay or mono) and links to the sibling table where the credentials live (LiqPay payment or Mono settings). Every Payment created for the company is bound to one of these rows.

Identity & key fields

  • Primary key: id (uuid, default gen_random_uuid()).
  • name (text, NOT NULL).
  • platform (enum company_billing_platform: liqpay, mono).
  • companyId (uuid, NOT NULL) — no DB-level FK declared (application-side only).
  • active (boolean, NOT NULL, default true).

platform is the discriminator: it tells the system which sibling table to read credentials from. The sibling row is not enforced to exist at the DB level — the check happens at first createPayment call (payments.service.ts:47: throws errors.payment.liqpay_incomplete if the keys are missing).

Invariants

  • name, platform, companyId, active NOT NULL (enforced in tktspace-backend/libs/shared/data-access-db/src/lib/schema/payments.schema.ts).
  • companyId has no DB-level FK (cross-schema reference: payments.payment_settingscompanies.companies). Application-level integrity only. See ADR cross-schema-references-without-fk.

Business invariants:

  • platform decides which sibling table is read for credentials — liqpay (table LiqPay payment) or mono (Mono settings). Sibling tables are UNIQUE on payment_id (1:1) with ON DELETE CASCADE — deleting the settings row deletes the credentials.
  • The DB does not enforce that the sibling row exists for the chosen platform. Inconsistency (platform='liqpay' settings with no liqpay row) is possible; it only fails at first createPayment use.
  • active=false excludes the settings from gateway-selection in createPayment (if (!settings.active) throw NotFoundException).
  • (company_id, platform) is not UNIQUE on the DB level — a company can theoretically have multiple LiqPay or Mono settings rows.

business invariants: TBD by human

Lifecycle

No status enum — active boolean is the soft-disable flag.

  • Create: admin creates the settings row plus the sibling credentials row (LiqPay keys / Mono token) — typically as two separate operations from the admin UI.
  • Update: admin updates credentials (UPDATE on sibling row), active toggle (UPDATE settings.active), or name.
  • Soft-disable: active=false — gateway selection in createPayment skips this row.
  • Delete: hard delete cascades on sibling rows (liqpay, mono_settings) via their payment_id FKs.

No cron jobs, no system-mutators — settings are admin-CRUD only.

Relationships

  • Company (ENT-016) — companyId (no DB FK). N:1, application-side.
  • LiqPay payment settings (ENT-033) — 1:0..1 via payments.liqpay_payment.payment_id UNIQUE.
  • Monobank payment settings (ENT-034) — 1:0..1 via payments.mono_settings.payment_id UNIQUE.
  • Payment (ENT-035) — 1:N via payments.payments.payment_settings_id.

API surfaces

SurfaceExposedNotes
clientyes — /companies/{companyId}/payment-settings (PaymentSettingsResponseDto) — non-secret summarySwagger UI
businessyes — managed via libs/features/payments/src/lib/payments-admin.module.tsSwagger UI
super-adminno

Known gotchas / open questions

  • platform decides which sibling table (LiqPay / Mono) is expected — no DB CHECK that exactly one sibling row exists per settings row of the corresponding platform.
  • No DB-level FK on companyId — intentional cross-schema design, see ADR.
  • Application-level invariant: one settings row per (companyId, platform) — a company has at most one LiqPay config and one Mono config. No DB constraint enforces this today. Without it, multiple active=true rows for the same gateway create ambiguity over which credentials are used. OPEN: add UNIQUE (company_id, platform) in a future migration.
  • Credentials are stored in plain text in the sibling tables (liqpay.privateKey, mono.token). A DB dump or backup contains live payment credentials.
  • Setting platform='liqpay' without populating the liqpay sibling row is silently accepted — the failure happens only at the first createPayment call.

Recommendations

Forward-looking improvements suggested while filling this doc — not currently in place.

  • UNIQUE (company_id, platform) — already OPEN above. Promote the “one settings row per gateway” rule to the DB.
  • Sibling-row presence guard — either a DB trigger or a transactional service method that prevents active=true while the matching sibling row is missing. Today this inconsistency only surfaces at first use.
  • Encrypt credentials at restprivateKey, token are sensitive financial credentials. Move into a secrets manager (Vault / AWS Secrets / GCP Secret Manager) or at minimum encrypt with pgcrypto + a KMS-managed key.
  • Audit log for credential changes — financial-impact field; changes must be attributable for incident response.
  • Test-payment / verify-credentials endpoint — let an admin click “test” to confirm credentials work, without running a real transaction. Today the only way to discover misconfiguration is a failed customer payment.