# ADR-036: custodian.payees Is the Shared Payee Master Across All Payment-Facing PWAs

## Status

Accepted, 2026-06-22.

## Status History

```yaml
status_history:
  - date: 2026-06-22
    status: Proposed
    changed_by: hkl
    reason: Formalising shared payee schema decision across Custodian, Vendors, UPI Pay
    changed_via: adr-kit (360lm)
  - date: 2026-06-22
    status: Accepted
    changed_by: hkl
    reason: custodian.payees + payee_methods live; edits in either PWA visible immediately in other
    changed_via: adr-kit (360lm)
```

## Context

Multiple PWAs deal with payments: Custodian (internal fund management), Vendors (supplier payments), UPI Pay (direct transfers). Each needs a directory of payees with bank details, UPI handles, and aliases. Maintaining per-PWA party tables would create three copies of the same payee — a vendor registered in Vendors would need manual re-entry in Custodian before a transfer could be made. Any update (new bank account, changed UPI handle) would require updating all copies. The `custodian` schema was built first with a complete payee model; the decision was made to extend it to all payment-facing PWAs rather than duplicating.

## Decision

`custodian.payees` and `custodian.payee_methods` are the single shared payee master for all payment-facing PWAs. Any PWA that initiates or records a payment reads from and writes to these tables — not per-PWA party tables.

`search_payees` RPC matches across 9 fields (name, alias, UPI handle, IFSC, account number, etc.) to serve as a universal payee lookup.

**Data truly interlinked:** edits made in the Vendors PWA (e.g. adding a UPI handle to a supplier) are immediately visible in Custodian transfer forms and UPI Pay — no caching, no sync job.

This is the payment-domain analog to ADR-032 (expense.employees as cross-schema FK anchor): `custodian.payees` is the payment identity anchor.

**Decision Maker:** hkl

## Alternatives Considered

- **Per-PWA party tables with sync job.** Rejected: sync jobs introduce lag and failure modes; partial sync creates inconsistent views of the same payee across PWAs; tested and found impractical when a vendor's bank account was updated in Vendors but a Custodian transfer used the stale account number.
- **Per-PWA party tables with no sync (duplicate data).** Rejected: requires re-entry of the same payee in multiple PWAs; users inevitably create slight variations (name spelling, missing IFSC digit) that cannot be detected as duplicates.
- **Shared "finance" schema for parties (not custodian).** Rejected: custodian schema already existed with the correct model; creating a new "finance" parties schema would require migrating existing custodian data and updating all existing PostgREST queries.

## Consequences

**Positive:**
- A payee registered once in any payment-facing PWA is immediately usable in all others.
- `search_payees` RPC provides a single, consistent payee search across all PWAs.
- No sync job, no consistency window — edits are immediately visible everywhere.

**Negative / Trade-offs:**
- All payment-facing PWAs depend on `custodian` schema — it cannot be dropped or isolated.
- `custodian.payees` must evolve to handle all payment-facing use cases (vendor-specific fields, UPI-specific fields, etc.) — field creep risk.
- `web_anon` must have grants on `custodian.payees` and `custodian.payee_methods` for all payment PWAs to access them via PostgREST.

**Risks and mitigations:**
- New payment PWA creates its own payee table: mitigated by this ADR; code review gate.
- custodian.payees grows fields not needed by simpler PWAs (e.g. UPI Pay only needs UPI handle, not IFSC): accepted — unused columns cause no harm; payee record remains the shared identity.

## Related Decisions

- ADR-032 (expense.employees cross-schema FK anchor) — same pattern for employee identity.
- ADR-009 (per-PWA schema isolation) — this is a documented exception for payment identity.
- ADR-037 (soft-polymorphic FK for transaction_lines) — transaction lines reference payees via this shared table.

## References

- `memory/dbt_vendors.md` — "Data truly interlinked: payee + payee_methods + payees-aliases all shared via the single custodian.* schema"
- `memory/dbt_custodian.md` — custodian.payees schema and search_payees RPC
- `finance/custodian/index.html` — transfer form using custodian.payees
