# RLS Open Decisions

> Audience: operator (decision-owner) and vendor (downstream implementer).
> Purpose: explicit log of product decisions required to close remaining lax RLS surfaces.
> Out of scope: any commercial / effort / cost language.

This file tracks RLS-policy decisions that the codebase cannot make on its own. Each item lists what is open, why it is open, the default applied if no decision is made, and the consequences of each path.

---

## D-1 — `project_type_assignments` write scope (DECIDED)

- **Question.** Who is authorised to add / change / remove project↔project-type assignments?
- **Decision.** Owner of the parent project (`projects.user_id = auth.uid()`) plus admin / masteradmin override via the existing `current_user_role()` SECURITY DEFINER helper.
- **Closure SQL (review-only).** `supabase/rls/supabase-rls-closure-pta-ownership.sql`.
- **Status.** Decided 2026-04-29 against the default in `working_notes/40_must_do_before_handover.md` §1.
- **Reviewer notes.** Smoke-test plan inside the SQL header. Do not apply without staging review.

## D-2 — `project_suppliers` write scope (DECIDED)

- **Question.** Same as D-1 for project↔supplier assignments.
- **Decision.** Same shape as D-1.
- **Closure SQL (review-only).** `supabase/rls/supabase-rls-closure-ps-ownership.sql`.
- **Status.** Decided 2026-04-29.
- **Reviewer notes.** As D-1.

---

## D-3 — `appointment_types` write scope (OPEN)

- **Current.** RLS enabled. Two SELECT policies both `USING (true)`. Write policies allow any authenticated user to insert / update / delete catalogue rows.
- **Question.** Should the appointment-type catalogue be admin-only writable, or should consultants be able to add ad-hoc types?
- **Inputs.** Catalogue is referenced by planning + audit flows; uncontrolled writes cause downstream taxonomy drift.
- **Default if unanswered.** Admin / masteradmin only via `current_user_role()`. SELECT remains open to authenticated users (catalogue is non-sensitive).
- **Action required.** Operator confirms / overrides. After confirmation, write a closure SQL (`supabase-rls-closure-appointment-types.sql`) following the pattern of D-1.

## D-4 — `document_metadata` write scope (OPEN)

- **Current.** RLS enabled. Lax write policies. Reads gated by parent-document join.
- **Question.** Are metadata writes scoped to the document uploader, the originating project owner, or admins only?
- **Inputs.** `documents` table has both `uploaded_by` (FK auth.users, SET NULL) and `project_id` (FK projects, SET NULL) plus `access_scope` ∈ {global, project}. Existing `docs_select` policy: global OR project-owner OR admin. Cross-tenant write today reachable.
- **Default applied in closure SQL.** **Uploader OR parent-project-owner**, with admin override. Predicate: `documents.uploaded_by = auth.uid() OR projects.user_id = auth.uid()` via LEFT JOIN so orphan / global-scope docs are still writable by uploader.
- **Action required.** Operator confirms uploader-OR-project-owner shape OR overrides to one of: project-owner-only / uploader-only / admin-only.

## D-5 — `document_departments` write scope (OPEN)

- **Current.** RLS enabled. Two duplicate SELECT policies both `USING (true)`. Lax writes.
- **Question.** Department mapping for documents: who can author?
- **Inputs.** Department master data is already gated for writes (admin only). Mapping table currently lax.
- **Default applied in closure SQL.** Same shape as D-4 (uploader OR project-owner) plus admin override.
- **Action required.** Operator confirms or overrides.

## D-6 — `document_suppliers` write scope (OPEN)

- **Current.** RLS enabled. Lax writes.
- **Question.** Supplier mapping for documents: who can author?
- **Inputs.** Supplier master data is read-only for non-admins; mapping should mirror that.
- **Default applied in closure SQL.** Same shape as D-4 (uploader OR project-owner) plus admin override.
- **Action required.** Operator confirms or overrides.

---

## D-7 — `role_permissions` write policy (OPEN — Architectural)

- **Current.** RLS enabled. Three SELECT-only policies. **No write policy.**
- **Question.** Who modifies the role↔permissions matrix? Via what UI? With what audit?
- **Default if unanswered.** Carry forward today's behaviour (no in-app writes — schema-driven only). Document the constraint and defer to vendor.
- **Action required.** ADR (placeholder ADR 021) — sketched in `working_notes/41_strongly_recommended.md` §7. Cross-link this entry to that ADR when written.

---

## How to convert an OPEN entry to DECIDED

1. Operator confirms the answer in this file.
2. Author closure SQL using the pattern of `supabase/rls/supabase-rls-closure-pta-ownership.sql`:
   - `BEGIN; … ROLLBACK;` envelope while review pending.
   - `DROP POLICY IF EXISTS` for every prior name.
   - One `_own` policy + one `_admin` policy per CRUD shape.
   - Both `USING` and `WITH CHECK` set on `FOR ALL`.
3. Mention the SQL filename in the entry's "Closure SQL" line.
4. Move the entry above the horizontal rule (DECIDED block).
5. Update `docs/foundation/follow-ups.md` if a tracked risk closes.

## Azure-translation note

These decisions all live in the Supabase form (`auth.uid()`, `current_user_role()`). The Azure-translated equivalents are produced by `scripts/rls-azure-translate.mjs` from `docs/foundation/rls-azure-translation.md` at vendor migration time. **Do not pre-port these files manually.**
