Files
paliad/internal/db/migrations/006_visibility.up.sql
m 3da11bd798 chore(t-paliad-081): doc + dead-code batch (F-5/F-10/F-11/F-15/F-16/F-17/F-18)
Bundle of small audit findings, all doc-only or dead-code:

- F-5: refresh stale escalation-contact comment in models.User —
  Settings UI dropdown shipped 2026-04-29 (t-paliad-066).
- F-10: add "OBSOLETED by migration 018" note to migrations 004/005/006
  so readers stop hunting for the live shape in obsolete files.
- F-11: document the data-loss semantics of dropping
  paliad.partner_unit_events on the 027 down — audit rows are
  append-only telemetry, accepted loss on rollback.
- F-15: drop the patholo_session / patholo_refresh cookie fallback
  added during the 2026-04-16 rebrand. Active users have long since
  been re-authed through the upgrade path; inactive users hit the
  normal /login flow.
- F-16: refresh stale /api/departments comment in team_pages.go to
  /api/partner-units (renamed in t-paliad-070).
- F-17: move internal/db/migrations/_dev/mock_supabase_auth.sql to
  internal/db/devtools/ so a future loosening of the //go:embed
  pattern can't accidentally ship the dev-only fixture.
- F-18: update docs/project-status.md "Audit polish-2" entry — the
  batch shipped via t-paliad-067 / 068 / 073, follow-ups are now
  tracked under the 2026-04-30 re-audit + t-paliad-074.

go build / vet / test clean.
2026-04-30 03:42:25 +02:00

45 lines
1.6 KiB
PL/PgSQL

-- Phase A: paliad.can_see_akte(akte_id) — single source of truth for
-- office-scoped Akten visibility (design §2).
--
-- OBSOLETED by migration 018 (data model v2): can_see_akte() is dropped and
-- replaced by paliad.can_see_project(project_id) with team-based visibility
-- (direct + inherited up the project tree). The effective shape lives in 018;
-- this file is kept only so a fresh database can replay the migration history.
--
-- A user can see an Akte iff ANY of:
-- - the Akte is flagged firm_wide_visible
-- - the Akte's owning_office matches the user's office
-- - the user's uuid appears in the Akte's collaborators array
-- - the user has role = 'admin'
--
-- Used by every RLS policy (migration 007) and mirrored at the application
-- layer (Phase B AkteService.ListVisibleForUser) for defense in depth.
--
-- SECURITY DEFINER so the function can read paliad.users regardless of the
-- caller's own RLS grants. The function itself enforces the identity check
-- by keying off auth.uid().
CREATE OR REPLACE FUNCTION paliad.can_see_akte(_akte_id uuid)
RETURNS boolean
LANGUAGE sql
STABLE
SECURITY DEFINER
SET search_path = paliad, public
AS $$
SELECT EXISTS (
SELECT 1
FROM paliad.akten a
LEFT JOIN paliad.users u ON u.id = auth.uid()
WHERE a.id = _akte_id
AND (
a.firm_wide_visible
OR (u.office IS NOT NULL AND a.owning_office = u.office)
OR auth.uid() = ANY (a.collaborators)
OR (u.role = 'admin')
)
);
$$;
COMMENT ON FUNCTION paliad.can_see_akte(uuid) IS
'Office-scoped visibility predicate for paliad.akten. Called from RLS policies.';