Skip to content

0008. Derive support-user eligibility from the adapter driver, not the direction matrix

Date: 2026-07-21 Status: Accepted

Context

ADR-0007 ties system_user membership eligibility to whether a System's direction_matrix includes PullOut. The direction matrix is a per-instance sync configuration (ADR-0004) describing what data currently flows and in which direction — an operational setting, not an organisational one. Whether a consuming platform's staff can ever act as platform support for a given adapter type is fixed by what kind of adapter it is (a shop a tenant plugs in vs. a platform that itself consumes Conflux), not by which sync directions happen to be configured on one instance of it at a given moment. Gating membership on direction_matrix also couples an authorization decision to a field that ADR-0004 already expects to become a domain-keyed map rather than a flat list — a "does the flat list contain PullOut" check would not survive that change.

Decision

Support-user eligibility is a static property of the adapter type, not of any one System row's sync configuration: SystemDriver::canHaveSupportUsers() is the single source of truth (shop adapters — WooCommerce, PrestaShop, Shopify, Shopware — return false; the internal consuming platforms — RapidMail, UserPlatform — return true). System::scopeCanHaveSupportUsers() reads this per-driver classification, and every place that previously inspected direction_matrix for this purpose reads it instead: the system_user pivot's assignment guard, Tenant::scopeAccessibleBy(), and SystemConnection::scopeFullyAccessibleBy().

This corrects only the eligibility criterion in ADR-0007; its other two decisions — the accessible-tenants union and the own-connections-full / sibling-connections-status-only split — are unaffected and remain in effect.

Consequences

A System's direction_matrix no longer has any bearing on whether it may have support members; reclassifying an adapter's eligibility now means changing SystemDriver::canHaveSupportUsers() (a code change, reviewed like any other), not editing per-row configuration data. The system_user pivot's creating guard (App\Models\SystemUser) throws SystemCannotHaveSupportUsersException at assignment time based on this same classification; if a driver is later reclassified from eligible to ineligible, existing pivot rows are not retroactively removed — Tenant::scopeAccessibleBy() and SystemConnection::scopeFullyAccessibleBy() re-check canHaveSupportUsers() on every query, so access is still cut off for stale assignments even though the pivot row itself lingers.