Third pass over PR #12189 after review-code on 225eb98de2.
resolve-team-id now has a direct test: all three branches resolve
while rows are live, and file, project and team soft-deletes each
refuse their branch — the two new SQL predicates and the final team-row
check are all pinned by it.
From the same review:
- failing-existence-check-keeps-the-subscription and the sibling
a-failing-check-keeps-the-subscription are deleted: they could not
distinguish a live relay from a dead one. The fail-open policy
remains documented in the docstring and the memory; the memory no
longer claims the pins exist.
- team-readable? projects ::sql/columns like the rest of the backend;
the fully-qualified keyword went away with the new alias.
- The dead when-not guard in get-organization-owner-viewer-team is
removed (resolve-team-id guarantees the row live); the let binding
in resolve-team-id no longer shadows the destructured team-id.
- docs/technical-guide names rpc/notifications.clj as the publisher
and the tree lists the real top-level modules.
Closes#12155
AI-assisted-by: inkling-2-small-free
Second review round on PR #12189 (pabloalba).
The file re-check added in 87ca7aca53 stops at the file row, but the
organization-owner fallback grants read-only access to non-member org
owners via Nitrate over HTTP, which knows nothing about Penpot
soft-deletion. resolve-team-id resolved the team from unfiltered SQL,
so an expelled org owner kept the file subscription open for an
indefinitely soft-deleted file, project or team. Now both SQL lookups
filter deleted_at, and resolve-team-id checks the team row itself
(db/get*, which filters soft-deleted rows) for every caller — teams,
projects and files alike.
Also from the same review:
- file-readable? now uses the same sql:get-minimal-file as the
subscribe gate (non-throwing via throw-if-not-exists false), and
team-readable? projects id and deleted-at, so db/get* can filter.
- The test suite extracts the thrice-duplicated raw delete into
delete-team-membership!; a sibling of the fail-open pin now redefs
the existence probe to throw; memory and docstring aligned with the
code.
- docs/technical-guide/developer/architecture/backend.md attributed
the websocket to notifications.clj; it now names app.http.websocket
as the owner and notifications.clj as the revocation publisher.
- mem:backend/auth-permissions-product-domains documents the fallback
mechanism and the resolve-team-id contract.
Closes#12155
AI-assisted-by: inkling-2-small-free