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, defaultgen_random_uuid()). name(text, NOT NULL).platform(enumcompany_billing_platform:liqpay,mono).companyId(uuid, NOT NULL) — no DB-level FK declared (application-side only).active(boolean, NOT NULL, defaulttrue).
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,activeNOT NULL (enforced in tktspace-backend/libs/shared/data-access-db/src/lib/schema/payments.schema.ts).companyIdhas no DB-level FK (cross-schema reference:payments.payment_settings→companies.companies). Application-level integrity only. See ADR cross-schema-references-without-fk.
Business invariants:
platformdecides which sibling table is read for credentials —liqpay(table LiqPay payment) ormono(Mono settings). Sibling tables are UNIQUE onpayment_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 noliqpayrow) is possible; it only fails at firstcreatePaymentuse. active=falseexcludes the settings from gateway-selection increatePayment(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 (
UPDATEon sibling row),activetoggle (UPDATE settings.active), orname. - Soft-disable:
active=false— gateway selection increatePaymentskips this row. - Delete: hard delete cascades on sibling rows (
liqpay,mono_settings) via theirpayment_idFKs.
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_idUNIQUE. - Monobank payment settings (ENT-034) — 1:0..1 via
payments.mono_settings.payment_idUNIQUE. - Payment (ENT-035) — 1:N via
payments.payments.payment_settings_id.
API surfaces
| Surface | Exposed | Notes |
|---|---|---|
| client | yes — /companies/{companyId}/payment-settings (PaymentSettingsResponseDto) — non-secret summary | Swagger UI |
| business | yes — managed via libs/features/payments/src/lib/payments-admin.module.ts | Swagger UI |
| super-admin | no | — |
Known gotchas / open questions
platformdecides 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, multipleactive=truerows for the same gateway create ambiguity over which credentials are used. OPEN: addUNIQUE (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 theliqpaysibling row is silently accepted — the failure happens only at the firstcreatePaymentcall.
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=truewhile the matching sibling row is missing. Today this inconsistency only surfaces at first use. - Encrypt credentials at rest —
privateKey,tokenare 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.