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